Merge from Chromium at DEPS revision r167172

This commit was generated by merge_to_master.py.

Change-Id: Ib8d56fd5ae39a2d7e8c91dcd76cc6d13f25f2aab
diff --git a/base/DEPS b/base/DEPS
new file mode 100644
index 0000000..e1545ae
--- /dev/null
+++ b/base/DEPS
@@ -0,0 +1,15 @@
+include_rules = [
+  "+jni",
+  "+native_client/src/untrusted/irt/irt.h",
+  "+third_party/ashmem",
+  "+third_party/apple_apsl",
+  "+third_party/libevent",
+  "+third_party/dmg_fp",
+  "+third_party/GTM",
+  "+third_party/mach_override",
+  "+third_party/modp_b64",
+  "+third_party/tcmalloc",
+
+  # ICU dependendencies must be separate from the rest of base.
+  "-i18n",
+]
diff --git a/base/OWNERS b/base/OWNERS
new file mode 100644
index 0000000..60c01ff
--- /dev/null
+++ b/base/OWNERS
@@ -0,0 +1,5 @@
+mark@chromium.org
+darin@chromium.org
+brettw@chromium.org
+willchan@chromium.org
+jar@chromium.org
diff --git a/base/PRESUBMIT.py b/base/PRESUBMIT.py
new file mode 100644
index 0000000..c84a992
--- /dev/null
+++ b/base/PRESUBMIT.py
@@ -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.
+
+"""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 gcl.
+"""
+
+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 "/test/" in f.LocalPath() and
+        not f.LocalPath().endswith('_unittest.mm')):
+      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
+
+
+def GetPreferredTrySlaves():
+  return [
+    'linux_rel:sync_integration_tests',
+    'mac_rel:sync_integration_tests',
+    'win_rel:sync_integration_tests',
+  ]
diff --git a/base/allocator/README b/base/allocator/README
new file mode 100644
index 0000000..ec8a707
--- /dev/null
+++ b/base/allocator/README
@@ -0,0 +1,59 @@
+Notes about the Chrome memory allocator.
+
+Background
+----------
+We use this library as a generic way to fork into any of several allocators.
+Currently we can, at runtime, switch between:
+   the default windows allocator
+   the windows low-fragmentation-heap
+   tcmalloc
+   jemalloc (the heap used most notably within Mozilla Firefox)
+
+The mechanism for hooking LIBCMT in windows is rather tricky.  The core
+problem is that by default, the windows library does not declare malloc and
+free as weak symbols.  Because of this, they cannot be overriden.  To work
+around this, we start with the LIBCMT.LIB, and manually remove all allocator
+related functions from it using the visual studio library tool.  Once removed,
+we can now link against the library and provide custom versions of the 
+allocator related functionality.
+
+
+Source code
+-----------
+This directory contains just the allocator (i.e. shim) layer that switches
+between the different underlying memory allocation implementations.
+
+The tcmalloc and jemalloc libraries originate outside of Chromium
+and exist in ../../third_party/tcmalloc and ../../third_party/jemalloc
+(currently, the actual locations are defined in the allocator.gyp file).
+The third party sources use a vendor-branch SCM pattern to track
+Chromium-specific changes independently from upstream changes.
+
+The general intent is to push local changes upstream so that over
+time we no longer need any forked files.
+
+
+Adding a new allocator
+----------------------
+Adding a new allocator requires definition of the following five functions:
+
+  extern "C" {
+    bool init();
+    void* malloc(size_t s);
+    void* realloc(void* p, size_t s);
+    void free(void* s);
+    size_t msize(void* p);
+  }
+
+All other allocation related functions (new/delete/calloc/etc) have been
+implemented generically to work across all allocators.
+
+
+Usage
+-----
+You can use the different allocators by setting the environment variable
+CHROME_ALLOCATOR to:
+   "tcmalloc"  - TC Malloc (default)
+   "jemalloc"  - JE Malloc
+   "winheap"   - Windows default heap
+   "winlfh"    - Windows Low-Fragmentation heap
diff --git a/base/allocator/allocator.gyp b/base/allocator/allocator.gyp
new file mode 100644
index 0000000..f669298
--- /dev/null
+++ b/base/allocator/allocator.gyp
@@ -0,0 +1,665 @@
+# Copyright (c) 2012 The Chromium 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': {
+    'jemalloc_dir': '../../third_party/jemalloc/chromium',
+    'tcmalloc_dir': '../../third_party/tcmalloc/chromium',
+    'use_vtable_verify%': 0,
+  },
+  'targets': [
+    {
+      'target_name': 'allocator',
+      'type': 'static_library',
+      # Make sure the allocation library is optimized to
+      # the hilt in official builds.
+      'variables': {
+        'optimize': 'max',
+      },
+      'include_dirs': [
+        '.',
+        '<(tcmalloc_dir)/src/base',
+        '<(tcmalloc_dir)/src',
+        '../..',
+      ],
+      'direct_dependent_settings': {
+        'configurations': {
+          'Common_Base': {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'],
+                'AdditionalDependencies': [
+                  '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib'
+                ],
+              },
+            },
+          },
+        },
+        'conditions': [
+          ['OS=="win"', {
+            'defines': [
+              'PERFTOOLS_DLL_DECL=',
+            ],
+          }],
+        ],
+      },
+      'sources': [
+        # Generated for our configuration from tcmalloc's build
+        # and checked in.
+        '<(tcmalloc_dir)/src/config.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-linuxppc.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-macosx.h',
+        '<(tcmalloc_dir)/src/base/atomicops-internals-windows.h',
+        '<(tcmalloc_dir)/src/base/atomicops-internals-x86.cc',
+        '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
+        '<(tcmalloc_dir)/src/base/atomicops.h',
+        '<(tcmalloc_dir)/src/base/basictypes.h',
+        '<(tcmalloc_dir)/src/base/commandlineflags.h',
+        '<(tcmalloc_dir)/src/base/cycleclock.h',
+        # We don't list dynamic_annotations.c since its copy is already
+        # present in the dynamic_annotations target.
+        '<(tcmalloc_dir)/src/base/dynamic_annotations.h',
+        '<(tcmalloc_dir)/src/base/elf_mem_image.cc',
+        '<(tcmalloc_dir)/src/base/elf_mem_image.h',
+        '<(tcmalloc_dir)/src/base/elfcore.h',
+        '<(tcmalloc_dir)/src/base/googleinit.h',
+        '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
+        '<(tcmalloc_dir)/src/base/linuxthreads.cc',
+        '<(tcmalloc_dir)/src/base/linuxthreads.h',
+        '<(tcmalloc_dir)/src/base/logging.cc',
+        '<(tcmalloc_dir)/src/base/logging.h',
+        '<(tcmalloc_dir)/src/base/low_level_alloc.cc',
+        '<(tcmalloc_dir)/src/base/low_level_alloc.h',
+        '<(tcmalloc_dir)/src/base/simple_mutex.h',
+        '<(tcmalloc_dir)/src/base/spinlock.cc',
+        '<(tcmalloc_dir)/src/base/spinlock.h',
+        '<(tcmalloc_dir)/src/base/spinlock_internal.cc',
+        '<(tcmalloc_dir)/src/base/spinlock_internal.h',
+        '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
+        '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
+        '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
+        '<(tcmalloc_dir)/src/base/stl_allocator.h',
+        '<(tcmalloc_dir)/src/base/synchronization_profiling.h',
+        '<(tcmalloc_dir)/src/base/sysinfo.cc',
+        '<(tcmalloc_dir)/src/base/sysinfo.h',
+        '<(tcmalloc_dir)/src/base/thread_annotations.h',
+        '<(tcmalloc_dir)/src/base/thread_lister.c',
+        '<(tcmalloc_dir)/src/base/thread_lister.h',
+        '<(tcmalloc_dir)/src/base/vdso_support.cc',
+        '<(tcmalloc_dir)/src/base/vdso_support.h',
+        '<(tcmalloc_dir)/src/central_freelist.cc',
+        '<(tcmalloc_dir)/src/central_freelist.h',
+        '<(tcmalloc_dir)/src/common.cc',
+        '<(tcmalloc_dir)/src/common.h',
+        '<(tcmalloc_dir)/src/debugallocation.cc',
+        '<(tcmalloc_dir)/src/deep-heap-profile.cc',
+        '<(tcmalloc_dir)/src/deep-heap-profile.h',
+        '<(tcmalloc_dir)/src/free_list.cc',
+        '<(tcmalloc_dir)/src/free_list.h',
+        '<(tcmalloc_dir)/src/getpc.h',
+        '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
+        '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
+        '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
+        '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
+        '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
+        '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
+        '<(tcmalloc_dir)/src/gperftools/profiler.h',
+        '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
+        '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
+        '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+        '<(tcmalloc_dir)/src/heap-checker.cc',
+        '<(tcmalloc_dir)/src/heap-profile-table.cc',
+        '<(tcmalloc_dir)/src/heap-profile-table.h',
+        '<(tcmalloc_dir)/src/heap-profiler.cc',
+        '<(tcmalloc_dir)/src/internal_logging.cc',
+        '<(tcmalloc_dir)/src/internal_logging.h',
+        '<(tcmalloc_dir)/src/libc_override.h',
+        '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
+        '<(tcmalloc_dir)/src/libc_override_glibc.h',
+        '<(tcmalloc_dir)/src/libc_override_osx.h',
+        '<(tcmalloc_dir)/src/libc_override_redefine.h',
+        '<(tcmalloc_dir)/src/linked_list.h',
+        '<(tcmalloc_dir)/src/malloc_extension.cc',
+        '<(tcmalloc_dir)/src/malloc_hook-inl.h',
+        '<(tcmalloc_dir)/src/malloc_hook.cc',
+        '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
+        '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
+        '<(tcmalloc_dir)/src/maybe_threads.cc',
+        '<(tcmalloc_dir)/src/maybe_threads.h',
+        '<(tcmalloc_dir)/src/memfs_malloc.cc',
+        '<(tcmalloc_dir)/src/memory_region_map.cc',
+        '<(tcmalloc_dir)/src/memory_region_map.h',
+        '<(tcmalloc_dir)/src/packed-cache-inl.h',
+        '<(tcmalloc_dir)/src/page_heap.cc',
+        '<(tcmalloc_dir)/src/page_heap.h',
+        '<(tcmalloc_dir)/src/page_heap_allocator.h',
+        '<(tcmalloc_dir)/src/pagemap.h',
+        '<(tcmalloc_dir)/src/profile-handler.cc',
+        '<(tcmalloc_dir)/src/profile-handler.h',
+        '<(tcmalloc_dir)/src/profiledata.cc',
+        '<(tcmalloc_dir)/src/profiledata.h',
+        '<(tcmalloc_dir)/src/profiler.cc',
+        '<(tcmalloc_dir)/src/raw_printer.cc',
+        '<(tcmalloc_dir)/src/raw_printer.h',
+        '<(tcmalloc_dir)/src/sampler.cc',
+        '<(tcmalloc_dir)/src/sampler.h',
+        '<(tcmalloc_dir)/src/span.cc',
+        '<(tcmalloc_dir)/src/span.h',
+        '<(tcmalloc_dir)/src/stack_trace_table.cc',
+        '<(tcmalloc_dir)/src/stack_trace_table.h',
+        '<(tcmalloc_dir)/src/stacktrace.cc',
+        '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
+        '<(tcmalloc_dir)/src/stacktrace_config.h',
+        '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
+        '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
+        '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
+        '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
+        '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
+        '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
+        '<(tcmalloc_dir)/src/static_vars.cc',
+        '<(tcmalloc_dir)/src/static_vars.h',
+        '<(tcmalloc_dir)/src/symbolize.cc',
+        '<(tcmalloc_dir)/src/symbolize.h',
+        '<(tcmalloc_dir)/src/system-alloc.cc',
+        '<(tcmalloc_dir)/src/system-alloc.h',
+        '<(tcmalloc_dir)/src/tcmalloc.cc',
+        '<(tcmalloc_dir)/src/tcmalloc_guard.h',
+        '<(tcmalloc_dir)/src/thread_cache.cc',
+        '<(tcmalloc_dir)/src/thread_cache.h',
+        '<(tcmalloc_dir)/src/windows/config.h',
+        '<(tcmalloc_dir)/src/windows/get_mangled_names.cc',
+        '<(tcmalloc_dir)/src/windows/gperftools/tcmalloc.h',
+        '<(tcmalloc_dir)/src/windows/ia32_modrm_map.cc',
+        '<(tcmalloc_dir)/src/windows/ia32_opcode_map.cc',
+        '<(tcmalloc_dir)/src/windows/mingw.h',
+        '<(tcmalloc_dir)/src/windows/mini_disassembler.cc',
+        '<(tcmalloc_dir)/src/windows/mini_disassembler.h',
+        '<(tcmalloc_dir)/src/windows/mini_disassembler_types.h',
+        '<(tcmalloc_dir)/src/windows/override_functions.cc',
+        '<(tcmalloc_dir)/src/windows/patch_functions.cc',
+        '<(tcmalloc_dir)/src/windows/port.cc',
+        '<(tcmalloc_dir)/src/windows/port.h',
+        '<(tcmalloc_dir)/src/windows/preamble_patcher.cc',
+        '<(tcmalloc_dir)/src/windows/preamble_patcher.h',
+        '<(tcmalloc_dir)/src/windows/preamble_patcher_with_stub.cc',
+
+        # jemalloc files
+        '<(jemalloc_dir)/jemalloc.c',
+        '<(jemalloc_dir)/jemalloc.h',
+        '<(jemalloc_dir)/ql.h',
+        '<(jemalloc_dir)/qr.h',
+        '<(jemalloc_dir)/rb.h',
+
+        'allocator_shim.cc',
+        'allocator_shim.h',
+        'generic_allocators.cc',
+        'win_allocator.cc',
+      ],
+      # sources! means that these are not compiled directly.
+      'sources!': [
+        # Included by allocator_shim.cc for maximal inlining.
+        'generic_allocators.cc',
+        'win_allocator.cc',
+
+        # 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.cc',
+        '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
+        '<(tcmalloc_dir)/src/base/atomicops.h',
+        '<(tcmalloc_dir)/src/base/basictypes.h',
+        '<(tcmalloc_dir)/src/base/commandlineflags.h',
+        '<(tcmalloc_dir)/src/base/cycleclock.h',
+        '<(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/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',
+        '<(tcmalloc_dir)/src/windows/config.h',
+        '<(tcmalloc_dir)/src/windows/gperftools/tcmalloc.h',
+        '<(tcmalloc_dir)/src/windows/get_mangled_names.cc',
+        '<(tcmalloc_dir)/src/windows/ia32_modrm_map.cc',
+        '<(tcmalloc_dir)/src/windows/ia32_opcode_map.cc',
+        '<(tcmalloc_dir)/src/windows/mingw.h',
+        '<(tcmalloc_dir)/src/windows/mini_disassembler.cc',
+        '<(tcmalloc_dir)/src/windows/mini_disassembler.h',
+        '<(tcmalloc_dir)/src/windows/mini_disassembler_types.h',
+        '<(tcmalloc_dir)/src/windows/override_functions.cc',
+        '<(tcmalloc_dir)/src/windows/patch_functions.cc',
+        '<(tcmalloc_dir)/src/windows/preamble_patcher.cc',
+        '<(tcmalloc_dir)/src/windows/preamble_patcher.h',
+        '<(tcmalloc_dir)/src/windows/preamble_patcher_with_stub.cc',
+      ],
+      'dependencies': [
+        '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+      ],
+      'msvs_settings': {
+        # TODO(sgk):  merge this with build/common.gypi settings
+        'VCLibrarianTool': {
+          'AdditionalOptions': ['/ignore:4006,4221'],
+          'AdditionalLibraryDirectories':
+            ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'],
+        },
+        'VCLinkerTool': {
+          'AdditionalOptions': ['/ignore:4006'],
+        },
+      },
+      'configurations': {
+        'Debug_Base': {
+          'msvs_settings': {
+            'VCCLCompilerTool': {
+              'RuntimeLibrary': '0',
+            },
+          },
+        },
+      },
+      'conditions': [
+        ['OS=="linux" and clang_type_profiler==1', {
+          'dependencies': [
+            'type_profiler_tcmalloc',
+          ],
+          # It is undoing dependencies and cflags_cc for type_profiler which
+          # build/common.gypi injects into all targets.
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+        }],
+        ['OS=="win"', {
+          'defines': [
+            'PERFTOOLS_DLL_DECL=',
+          ],
+          'defines!': [
+            # tcmalloc source files unconditionally define this, remove it from
+            # the list of defines that common.gypi defines globally.
+            'NOMINMAX',
+          ],
+          'dependencies': [
+            'libcmt',
+          ],
+          'include_dirs': [
+            '<(jemalloc_dir)',
+            '<(tcmalloc_dir)/src/windows',
+          ],
+          'sources!': [
+            '<(tcmalloc_dir)/src/base/elf_mem_image.cc',
+            '<(tcmalloc_dir)/src/base/elf_mem_image.h',
+            '<(tcmalloc_dir)/src/base/linuxthreads.cc',
+            '<(tcmalloc_dir)/src/base/linuxthreads.h',
+            '<(tcmalloc_dir)/src/base/vdso_support.cc',
+            '<(tcmalloc_dir)/src/base/vdso_support.h',
+            '<(tcmalloc_dir)/src/maybe_threads.cc',
+            '<(tcmalloc_dir)/src/maybe_threads.h',
+            '<(tcmalloc_dir)/src/symbolize.h',
+            '<(tcmalloc_dir)/src/system-alloc.cc',
+            '<(tcmalloc_dir)/src/system-alloc.h',
+
+            # included by allocator_shim.cc
+            '<(tcmalloc_dir)/src/tcmalloc.cc',
+
+            # heap-profiler/checker/cpuprofiler
+            '<(tcmalloc_dir)/src/base/thread_lister.c',
+            '<(tcmalloc_dir)/src/base/thread_lister.h',
+            '<(tcmalloc_dir)/src/deep-heap-profile.cc',
+            '<(tcmalloc_dir)/src/deep-heap-profile.h',
+            '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+            '<(tcmalloc_dir)/src/heap-checker.cc',
+            '<(tcmalloc_dir)/src/heap-profiler.cc',
+            '<(tcmalloc_dir)/src/heap-profile-table.cc',
+            '<(tcmalloc_dir)/src/heap-profile-table.h',
+            '<(tcmalloc_dir)/src/memory_region_map.cc',
+            '<(tcmalloc_dir)/src/memory_region_map.h',
+            '<(tcmalloc_dir)/src/profiledata.cc',
+            '<(tcmalloc_dir)/src/profiledata.h',
+            '<(tcmalloc_dir)/src/profile-handler.cc',
+            '<(tcmalloc_dir)/src/profile-handler.h',
+            '<(tcmalloc_dir)/src/profiler.cc',
+
+            # debugallocation
+            '<(tcmalloc_dir)/src/debugallocation.cc',
+          ],
+        }],
+        ['OS=="linux" or OS=="freebsd" or OS=="solaris"', {
+          'sources!': [
+            '<(tcmalloc_dir)/src/system-alloc.h',
+            '<(tcmalloc_dir)/src/windows/port.cc',
+            '<(tcmalloc_dir)/src/windows/port.h',
+
+            # TODO(willchan): Support allocator shim later on.
+            'allocator_shim.cc',
+
+            # TODO(willchan): support jemalloc on other platforms
+            # jemalloc files
+            '<(jemalloc_dir)/jemalloc.c',
+            '<(jemalloc_dir)/jemalloc.h',
+            '<(jemalloc_dir)/ql.h',
+            '<(jemalloc_dir)/qr.h',
+            '<(jemalloc_dir)/rb.h',
+
+          ],
+          # We enable all warnings by default, but upstream disables a few.
+          # Keep "-Wno-*" flags in sync with upstream by comparing against:
+          # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am
+          'cflags': [
+            '-Wno-sign-compare',
+            '-Wno-unused-result',
+          ],
+          'cflags!': [
+            '-fvisibility=hidden',
+          ],
+          'link_settings': {
+            'ldflags': [
+              # Don't let linker rip this symbol out, otherwise the heap&cpu
+              # profilers will not initialize properly on startup.
+              '-Wl,-uIsHeapProfilerRunning,-uProfilerStart',
+              # Do the same for heap leak checker.
+              '-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi',
+              '-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl',
+              '-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv',
+          ]},
+        }],
+        [ 'use_vtable_verify==1', {
+          'cflags': [
+            '-fvtable-verify=preinit',
+          ],
+        }],
+        [ 'linux_use_debugallocation==1', {
+          'sources!': [
+            # debugallocation.cc #includes tcmalloc.cc,
+            # so only one of them should be used.
+            '<(tcmalloc_dir)/src/tcmalloc.cc',
+          ],
+          'defines': [
+            'TCMALLOC_FOR_DEBUGALLOCATION',
+          ],
+        }, { # linux_use_debugallocation != 1
+          'sources!': [
+            '<(tcmalloc_dir)/src/debugallocation.cc',
+          ],
+        }],
+        [ 'linux_keep_shadow_stacks==1', {
+          'sources': [
+            '<(tcmalloc_dir)/src/linux_shadow_stacks.cc',
+            '<(tcmalloc_dir)/src/linux_shadow_stacks.h',
+            '<(tcmalloc_dir)/src/stacktrace_shadow-inl.h',
+          ],
+          'cflags': [
+            '-finstrument-functions',
+          ],
+          'defines': [
+            'KEEP_SHADOW_STACKS',
+          ],
+        }],
+        [ 'linux_use_heapchecker==0', {
+          # Do not compile and link the heapchecker source.
+          'sources!': [
+            '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+            '<(tcmalloc_dir)/src/heap-checker.cc',
+          ],
+          # Disable the heap checker in tcmalloc.
+          'defines': [
+            'NO_HEAP_CHECK',
+           ],
+        }],
+        [ 'clang==1', {
+          'cflags': [
+            '-Wno-non-literal-null-conversion',
+          ],
+        }],
+        ['order_profiling != 0', {
+          'target_conditions' : [
+            ['_toolset=="target"', {
+              'cflags!': [ '-finstrument-functions' ],
+            }],
+          ],
+        }],
+      ],
+    },
+    {
+      # This library is linked in to src/base.gypi:base and allocator_unittests
+      # It can't depend on either and nothing else should depend on it - all
+      # other code should use the interfaced provided by base.
+      'target_name': 'allocator_extension_thunks',
+      'type': 'static_library',
+      'sources': [
+        'allocator_extension_thunks.cc',
+        'allocator_extension_thunks.h',
+      ],
+      'toolsets': ['host', 'target'],
+      'include_dirs': [
+        '../../'
+      ],
+      'conditions': [
+        ['OS=="linux" and clang_type_profiler==1', {
+          # It is undoing dependencies and cflags_cc for type_profiler which
+          # build/common.gypi injects into all targets.
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+        }],
+      ],
+    },
+   ],
+  'conditions': [
+    ['OS=="win"', {
+      'targets': [
+        {
+          'target_name': 'libcmt',
+          'type': 'none',
+          'actions': [
+            {
+              'action_name': 'libcmt',
+              'inputs': [
+                'prep_libc.py',
+              ],
+              'outputs': [
+                '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib',
+              ],
+              'action': [
+                'python',
+                'prep_libc.py',
+                '$(VCInstallDir)lib',
+                '<(SHARED_INTERMEDIATE_DIR)/allocator',
+              ],
+            },
+          ],
+        },
+        {
+          'target_name': 'allocator_unittests',
+          'type': 'executable',
+          'dependencies': [
+            'allocator',
+            'allocator_extension_thunks',
+            '../../testing/gtest.gyp:gtest',
+          ],
+          'include_dirs': [
+            '.',
+            '<(tcmalloc_dir)/src/base',
+            '<(tcmalloc_dir)/src',
+            '../..',
+          ],
+          'sources': [
+            'allocator_unittests.cc',
+            '../profiler/alternate_timer.cc',
+            '../profiler/alternate_timer.h',
+          ],
+        },
+        {
+          'target_name': 'allocator_extension_thunks_win64',
+          'type': 'static_library',
+          'sources': [
+            'allocator_extension_thunks.cc',
+            'allocator_extension_thunks.h',
+          ],
+          'toolsets': ['host', 'target'],
+          'include_dirs': [
+            '../../'
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+        },
+      {
+        'target_name': 'tcmalloc_unittest',
+        'type': 'executable',
+        'sources': [
+          'tcmalloc_unittest.cc',
+        ],
+        'include_dirs': [
+          '../..',
+          # For constants of TCMalloc.
+          '<(tcmalloc_dir)/src',
+        ],
+        'dependencies': [
+          '../../testing/gtest.gyp:gtest',
+          '../base.gyp:base',
+          'allocator',
+        ],
+      },
+      ],
+    }],
+    ['OS=="linux" and clang_type_profiler==1', {
+      # Some targets in this section undo dependencies and cflags_cc for
+      # type_profiler which build/common.gypi injects into all targets.
+      'targets': [
+        {
+          'target_name': 'type_profiler',
+          'type': 'static_library',
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+          'include_dirs': [
+            '../..',
+          ],
+          'sources': [
+            'type_profiler.cc',
+            'type_profiler.h',
+            'type_profiler_control.h',
+          ],
+          'toolsets': ['host', 'target'],
+        },
+        {
+          'target_name': 'type_profiler_tcmalloc',
+          'type': 'static_library',
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+          'include_dirs': [
+            '<(tcmalloc_dir)/src',
+            '../..',
+          ],
+          'sources': [
+            'type_profiler_tcmalloc.cc',
+            'type_profiler_tcmalloc.h',
+            '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
+            '<(tcmalloc_dir)/src/type_profiler_map.cc',
+          ],
+        },
+        {
+          'target_name': 'type_profiler_unittests',
+          'type': 'executable',
+          'dependencies': [
+            '../../testing/gtest.gyp:gtest',
+            '../base.gyp:base',
+            'allocator',
+            'type_profiler_tcmalloc',
+          ],
+          'include_dirs': [
+            '../..',
+          ],
+          'sources': [
+            'type_profiler_control.cc',
+            'type_profiler_control.h',
+            'type_profiler_unittests.cc',
+          ],
+        },
+        {
+          'target_name': 'type_profiler_map_unittests',
+          'type': 'executable',
+          'dependencies': [
+            '../../testing/gtest.gyp:gtest',
+            '../base.gyp:base',
+            'allocator',
+          ],
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+          'include_dirs': [
+            '<(tcmalloc_dir)/src',
+            '../..',
+          ],
+          'sources': [
+            'type_profiler_map_unittests.cc',
+            '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
+            '<(tcmalloc_dir)/src/type_profiler_map.cc',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/allocator/allocator_extension.cc b/base/allocator/allocator_extension.cc
new file mode 100644
index 0000000..d4ed6d7
--- /dev/null
+++ b/base/allocator/allocator_extension.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/allocator_extension.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace allocator {
+
+bool GetProperty(const char* name, size_t* value) {
+  thunks::GetPropertyFunction get_property_function =
+      base::allocator::thunks::GetGetPropertyFunction();
+  return get_property_function != NULL && get_property_function(name, value);
+}
+
+void GetStats(char* buffer, int buffer_length) {
+  DCHECK_GT(buffer_length, 0);
+  thunks::GetStatsFunction get_stats_function =
+      base::allocator::thunks::GetGetStatsFunction();
+  if (get_stats_function)
+    get_stats_function(buffer, buffer_length);
+  else
+    buffer[0] = '\0';
+}
+
+void ReleaseFreeMemory() {
+  thunks::ReleaseFreeMemoryFunction release_free_memory_function =
+      base::allocator::thunks::GetReleaseFreeMemoryFunction();
+  if (release_free_memory_function)
+    release_free_memory_function();
+}
+
+void SetGetPropertyFunction(
+    thunks::GetPropertyFunction get_property_function) {
+  DCHECK_EQ(base::allocator::thunks::GetGetPropertyFunction(),
+            reinterpret_cast<thunks::GetPropertyFunction>(NULL));
+  base::allocator::thunks::SetGetPropertyFunction(get_property_function);
+}
+
+void SetGetStatsFunction(thunks::GetStatsFunction get_stats_function) {
+  DCHECK_EQ(base::allocator::thunks::GetGetStatsFunction(),
+            reinterpret_cast<thunks::GetStatsFunction>(NULL));
+  base::allocator::thunks::SetGetStatsFunction(get_stats_function);
+}
+
+void SetReleaseFreeMemoryFunction(
+    thunks::ReleaseFreeMemoryFunction release_free_memory_function) {
+  DCHECK_EQ(base::allocator::thunks::GetReleaseFreeMemoryFunction(),
+            reinterpret_cast<thunks::ReleaseFreeMemoryFunction>(NULL));
+  base::allocator::thunks::SetReleaseFreeMemoryFunction(
+      release_free_memory_function);
+}
+
+}  // namespace allocator
+}  // namespace base
diff --git a/base/allocator/allocator_extension.h b/base/allocator/allocator_extension.h
new file mode 100644
index 0000000..dda0fd9
--- /dev/null
+++ b/base/allocator/allocator_extension.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H
+#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H
+
+#include <stddef.h> // for size_t
+
+#include "base/allocator/allocator_extension_thunks.h"
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace allocator {
+
+// Request the allocator to report value of its internal state variable.
+//
+// |name| name of the variable
+// |value| pointer to the returned value, must be not NULL.
+// Returns true if the value has been returned, false if a variable with such
+// name does not exist.
+BASE_EXPORT bool GetProperty(const char* name, size_t* value);
+
+// Request that the allocator print a human-readable description of the current
+// state of the allocator into a null-terminated string in the memory segment
+// buffer[0,buffer_length-1].
+//
+// |buffer| must point to a valid piece of memory
+// |buffer_length| must be > 0.
+BASE_EXPORT void GetStats(char* buffer, int buffer_length);
+
+// Request that the allocator release any free memory it knows about to the
+// system.
+BASE_EXPORT void ReleaseFreeMemory();
+
+
+// These settings allow specifying a callback used to implement the allocator
+// extension functions.  These are optional, but if set they must only be set
+// once.  These will typically called in an allocator-specific initialization
+// routine.
+//
+// No threading promises are made.  The caller is responsible for making sure
+// these pointers are set before any other threads attempt to call the above
+// functions.
+BASE_EXPORT void SetGetPropertyFunction(
+    thunks::GetPropertyFunction get_property_function);
+
+BASE_EXPORT void SetGetStatsFunction(
+    thunks::GetStatsFunction get_stats_function);
+
+BASE_EXPORT void SetReleaseFreeMemoryFunction(
+    thunks::ReleaseFreeMemoryFunction release_free_memory_function);
+
+}  // namespace allocator
+}  // namespace base
+
+#endif
diff --git a/base/allocator/allocator_extension_thunks.cc b/base/allocator/allocator_extension_thunks.cc
new file mode 100644
index 0000000..e5ee8ce
--- /dev/null
+++ b/base/allocator/allocator_extension_thunks.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/allocator/allocator_extension_thunks.h"
+
+#include <cstddef> // for NULL
+
+namespace base {
+namespace allocator {
+namespace thunks {
+
+// This slightly odd translation unit exists because of the peculularity of how
+// allocator_unittests work on windows.  That target has to perform
+// tcmalloc-specific initialization on windows, but it cannot depend on base
+// otherwise. This target sits in the middle - base and allocator_unittests
+// can depend on it. This file can't depend on anything else in base, including
+// logging.
+
+static GetPropertyFunction g_get_property_function = NULL;
+static GetStatsFunction g_get_stats_function = NULL;
+static ReleaseFreeMemoryFunction g_release_free_memory_function = NULL;
+
+void SetGetPropertyFunction(GetPropertyFunction get_property_function) {
+  g_get_property_function = get_property_function;
+}
+
+GetPropertyFunction GetGetPropertyFunction() {
+  return g_get_property_function;
+}
+
+void SetGetStatsFunction(GetStatsFunction get_stats_function) {
+  g_get_stats_function = get_stats_function;
+}
+
+GetStatsFunction GetGetStatsFunction() {
+  return g_get_stats_function;
+}
+
+void SetReleaseFreeMemoryFunction(
+    ReleaseFreeMemoryFunction release_free_memory_function) {
+  g_release_free_memory_function = release_free_memory_function;
+}
+
+ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction() {
+  return g_release_free_memory_function;
+}
+
+}  // namespace thunks
+}  // namespace allocator
+}  // namespace base
diff --git a/base/allocator/allocator_extension_thunks.h b/base/allocator/allocator_extension_thunks.h
new file mode 100644
index 0000000..3b0e4ed
--- /dev/null
+++ b/base/allocator/allocator_extension_thunks.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_ALLOCATOR_ALLOCATOR_THUNKS_EXTENSION_H
+#define BASE_ALLOCATOR_ALLOCATOR_THUNKS_EXTENSION_H
+
+#include <stddef.h> // for size_t
+
+namespace base {
+namespace allocator {
+namespace thunks {
+
+// WARNING: You probably don't want to use this file unless you are routing a
+// new allocator extension from a specific allocator implementation to base.
+// See allocator_extension.h to see the interface that base exports.
+
+typedef bool (*GetPropertyFunction)(const char* name, size_t* value);
+void SetGetPropertyFunction(GetPropertyFunction get_property_function);
+GetPropertyFunction GetGetPropertyFunction();
+
+typedef void (*GetStatsFunction)(char* buffer, int buffer_length);
+void SetGetStatsFunction(GetStatsFunction get_stats_function);
+GetStatsFunction GetGetStatsFunction();
+
+typedef void (*ReleaseFreeMemoryFunction)();
+void SetReleaseFreeMemoryFunction(
+    ReleaseFreeMemoryFunction release_free_memory_function);
+ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction();
+
+}  // namespace thunks
+}  // namespace allocator
+}  // namespace base
+
+#endif
diff --git a/base/allocator/allocator_extension_thunks.target.mk b/base/allocator/allocator_extension_thunks.target.mk
new file mode 100644
index 0000000..4e45330
--- /dev/null
+++ b/base/allocator/allocator_extension_thunks.target.mk
@@ -0,0 +1,149 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := base_allocator_allocator_extension_thunks_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	base/allocator/allocator_extension_thunks.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS := \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-mthumb \
+	-march=armv7-a \
+	-mtune=cortex-a8 \
+	-mfloat-abi=softfp \
+	-mfpu=vfpv3-d16 \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-mthumb-interwork \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-Wno-error=extra \
+	-Wno-error=ignored-qualifiers \
+	-Wno-error=type-limits \
+	-Wno-error=non-virtual-dtor \
+	-Wno-error=sign-promo \
+	-Wno-error=address \
+	-Wno-error=format-security \
+	-Wno-error=non-virtual-dtor \
+	-Wno-error=return-type \
+	-Wno-error=sequence-point \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_CFLAGS_C :=
+
+MY_DEFS := \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_PEPPER_THREADING' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DUSE_SKIA=1' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_SYMBOLS_ID=""' \
+	'-DANDROID_UPSTREAM_BRINGUP=1' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH) \
+	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
+	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wno-deprecated \
+	-Wno-abi \
+	-Wno-error=c++0x-compat
+
+### Rules for final target.
+
+LOCAL_LDFLAGS := \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections
+
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: base_allocator_allocator_extension_thunks_gyp
+
+# Alias gyp target name.
+.PHONY: allocator_extension_thunks
+allocator_extension_thunks: base_allocator_allocator_extension_thunks_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/base/allocator/allocator_shim.cc b/base/allocator/allocator_shim.cc
new file mode 100644
index 0000000..bcc84aa
--- /dev/null
+++ b/base/allocator/allocator_shim.cc
@@ -0,0 +1,445 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <config.h>
+#include "base/allocator/allocator_extension_thunks.h"
+#include "base/profiler/alternate_timer.h"
+#include "base/sysinfo.h"
+#include "jemalloc.h"
+
+// When defined, different heap allocators can be used via an environment
+// variable set before running the program.  This may reduce the amount
+// of inlining that we get with malloc/free/etc.  Disabling makes it
+// so that only tcmalloc can be used.
+#define ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+
+// TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth
+// from the "user code" so that debugging tools (HeapChecker) can work.
+
+// __THROW is defined in glibc systems.  It means, counter-intuitively,
+// "This function will never throw an exception."  It's an optional
+// optimization tool, but we may need to use it to match glibc prototypes.
+#ifndef __THROW    // I guess we're not on a glibc system
+# define __THROW   // __THROW is just an optimization, so ok to make it ""
+#endif
+
+// new_mode behaves similarly to MSVC's _set_new_mode.
+// If flag is 0 (default), calls to malloc will behave normally.
+// If flag is 1, calls to malloc will behave like calls to new,
+// and the std_new_handler will be invoked on failure.
+// Can be set by calling _set_new_mode().
+static int new_mode = 0;
+
+typedef enum {
+  TCMALLOC,    // TCMalloc is the default allocator.
+  JEMALLOC,    // JEMalloc.
+  WINHEAP,  // Windows Heap (standard Windows allocator).
+  WINLFH,      // Windows LFH Heap.
+} Allocator;
+
+// This is the default allocator. This value can be changed at startup by
+// specifying environment variables shown below it.
+// See SetupSubprocessAllocator() to specify a default secondary (subprocess)
+// allocator.
+// TODO(jar): Switch to using TCMALLOC for the renderer as well.
+static Allocator allocator = TCMALLOC;
+
+// The names of the environment variables that can optionally control the
+// selection of the allocator.  The primary may be used to control overall
+// allocator selection, and the secondary can be used to specify an allocator
+// to use in sub-processes.
+static const char primary_name[] = "CHROME_ALLOCATOR";
+static const char secondary_name[] = "CHROME_ALLOCATOR_2";
+
+// We include tcmalloc and the win_allocator to get as much inlining as
+// possible.
+#include "tcmalloc.cc"
+#include "win_allocator.cc"
+
+// Forward declarations from jemalloc.
+extern "C" {
+void* je_malloc(size_t s);
+void* je_realloc(void* p, size_t s);
+void je_free(void* s);
+size_t je_msize(void* p);
+bool je_malloc_init_hard();
+void* je_memalign(size_t a, size_t s);
+}
+
+extern "C" {
+
+// Call the new handler, if one has been set.
+// Returns true on successfully calling the handler, false otherwise.
+inline bool call_new_handler(bool nothrow) {
+  // Get the current new handler.  NB: this function is not
+  // thread-safe.  We make a feeble stab at making it so here, but
+  // this lock only protects against tcmalloc interfering with
+  // itself, not with other libraries calling set_new_handler.
+  std::new_handler nh;
+  {
+    SpinLockHolder h(&set_new_handler_lock);
+    nh = std::set_new_handler(0);
+    (void) std::set_new_handler(nh);
+  }
+#if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)
+  if (!nh)
+    return false;
+  // Since exceptions are disabled, we don't really know if new_handler
+  // failed.  Assume it will abort if it fails.
+  (*nh)();
+  return false;  // break out of the retry loop.
+#else
+  // If no new_handler is established, the allocation failed.
+  if (!nh) {
+    if (nothrow)
+      return 0;
+    throw std::bad_alloc();
+  }
+  // Otherwise, try the new_handler.  If it returns, retry the
+  // allocation.  If it throws std::bad_alloc, fail the allocation.
+  // if it throws something else, don't interfere.
+  try {
+    (*nh)();
+  } catch (const std::bad_alloc&) {
+    if (!nothrow)
+      throw;
+    return true;
+  }
+#endif  // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)
+}
+
+void* malloc(size_t size) __THROW {
+  void* ptr;
+  for (;;) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+    switch (allocator) {
+      case JEMALLOC:
+        ptr = je_malloc(size);
+        break;
+      case WINHEAP:
+      case WINLFH:
+        ptr = win_heap_malloc(size);
+        break;
+      case TCMALLOC:
+      default:
+        ptr = do_malloc(size);
+        break;
+    }
+#else
+    // TCMalloc case.
+    ptr = do_malloc(size);
+#endif
+    if (ptr)
+      return ptr;
+
+    if (!new_mode || !call_new_handler(true))
+      break;
+  }
+  return ptr;
+}
+
+void free(void* p) __THROW {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+  switch (allocator) {
+    case JEMALLOC:
+      je_free(p);
+      return;
+    case WINHEAP:
+    case WINLFH:
+      win_heap_free(p);
+      return;
+  }
+#endif
+  // TCMalloc case.
+  do_free(p);
+}
+
+void* realloc(void* ptr, size_t size) __THROW {
+  // Webkit is brittle for allocators that return NULL for malloc(0).  The
+  // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure
+  // to call malloc for this case.
+  if (!ptr)
+    return malloc(size);
+
+  void* new_ptr;
+  for (;;) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+    switch (allocator) {
+      case JEMALLOC:
+        new_ptr = je_realloc(ptr, size);
+        break;
+      case WINHEAP:
+      case WINLFH:
+        new_ptr = win_heap_realloc(ptr, size);
+        break;
+      case TCMALLOC:
+      default:
+        new_ptr = do_realloc(ptr, size);
+        break;
+    }
+#else
+    // TCMalloc case.
+    new_ptr = do_realloc(ptr, size);
+#endif
+
+    // Subtle warning:  NULL return does not alwas indicate out-of-memory.  If
+    // the requested new size is zero, realloc should free the ptr and return
+    // NULL.
+    if (new_ptr || !size)
+      return new_ptr;
+    if (!new_mode || !call_new_handler(true))
+      break;
+  }
+  return new_ptr;
+}
+
+// TODO(mbelshe): Implement this for other allocators.
+void malloc_stats(void) __THROW {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+  switch (allocator) {
+    case JEMALLOC:
+      // No stats.
+      return;
+    case WINHEAP:
+    case WINLFH:
+      // No stats.
+      return;
+  }
+#endif
+  tc_malloc_stats();
+}
+
+#ifdef WIN32
+
+extern "C" size_t _msize(void* p) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+  switch (allocator) {
+    case JEMALLOC:
+      return je_msize(p);
+    case WINHEAP:
+    case WINLFH:
+      return win_heap_msize(p);
+  }
+#endif
+  return MallocExtension::instance()->GetAllocatedSize(p);
+}
+
+// This is included to resolve references from libcmt.
+extern "C" intptr_t _get_heap_handle() {
+  return 0;
+}
+
+static bool get_jemalloc_property_thunk(const char* name, size_t* value) {
+  jemalloc_stats_t stats;
+  jemalloc_stats(&stats);
+#define EXTRACT_JEMALLOC_PROPERTY(property) \
+  if (strcmp(name, "jemalloc." #property) == 0) \
+    return *value = stats.property, true;
+  EXTRACT_JEMALLOC_PROPERTY(narenas);
+  EXTRACT_JEMALLOC_PROPERTY(balance_threshold);
+  EXTRACT_JEMALLOC_PROPERTY(quantum);
+  EXTRACT_JEMALLOC_PROPERTY(small_max);
+  EXTRACT_JEMALLOC_PROPERTY(large_max);
+  EXTRACT_JEMALLOC_PROPERTY(chunksize);
+  EXTRACT_JEMALLOC_PROPERTY(dirty_max);
+  EXTRACT_JEMALLOC_PROPERTY(reserve_min);
+  EXTRACT_JEMALLOC_PROPERTY(reserve_max);
+  EXTRACT_JEMALLOC_PROPERTY(mapped);
+  EXTRACT_JEMALLOC_PROPERTY(committed);
+  EXTRACT_JEMALLOC_PROPERTY(allocated);
+  EXTRACT_JEMALLOC_PROPERTY(dirty);
+  EXTRACT_JEMALLOC_PROPERTY(reserve_cur);
+#undef EXTRACT_JEMALLOC_PROPERTY
+  return false;
+}
+
+static bool get_property_thunk(const char* name, size_t* value) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+  switch (allocator) {
+    case JEMALLOC:
+      return get_jemalloc_property_thunk(name, value);
+    case WINHEAP:
+    case WINLFH:
+      // TODO(alexeif): Implement for other allocators.
+      return false;
+  }
+#endif
+  return MallocExtension::instance()->GetNumericProperty(name, value);
+}
+
+static void get_stats_thunk(char* buffer, int buffer_length) {
+  MallocExtension::instance()->GetStats(buffer, buffer_length);
+}
+
+static void release_free_memory_thunk() {
+  MallocExtension::instance()->ReleaseFreeMemory();
+}
+
+// The CRT heap initialization stub.
+extern "C" int _heap_init() {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+  const char* environment_value = GetenvBeforeMain(primary_name);
+  if (environment_value) {
+    if (!stricmp(environment_value, "jemalloc"))
+      allocator = JEMALLOC;
+    else if (!stricmp(environment_value, "winheap"))
+      allocator = WINHEAP;
+    else if (!stricmp(environment_value, "winlfh"))
+      allocator = WINLFH;
+    else if (!stricmp(environment_value, "tcmalloc"))
+      allocator = TCMALLOC;
+  }
+
+  switch (allocator) {
+    case JEMALLOC:
+      return je_malloc_init_hard() ? 0 : 1;
+    case WINHEAP:
+      return win_heap_init(false) ? 1 : 0;
+    case WINLFH:
+      return win_heap_init(true) ? 1 : 0;
+    case TCMALLOC:
+    default:
+      // fall through
+      break;
+  }
+#endif
+  // Initializing tcmalloc.
+  // We intentionally leak this object.  It lasts for the process
+  // lifetime.  Trying to teardown at _heap_term() is so late that
+  // you can't do anything useful anyway.
+  new TCMallocGuard();
+
+  // Provide optional hook for monitoring allocation quantities on a per-thread
+  // basis.  Only set the hook if the environment indicates this needs to be
+  // enabled.
+  const char* profiling =
+      GetenvBeforeMain(tracked_objects::kAlternateProfilerTime);
+  if (profiling && *profiling == '1') {
+    tracked_objects::SetAlternateTimeSource(
+        tcmalloc::ThreadCache::GetBytesAllocatedOnCurrentThread,
+        tracked_objects::TIME_SOURCE_TYPE_TCMALLOC);
+  }
+
+  base::allocator::thunks::SetGetPropertyFunction(get_property_thunk);
+  base::allocator::thunks::SetGetStatsFunction(get_stats_thunk);
+  base::allocator::thunks::SetReleaseFreeMemoryFunction(
+      release_free_memory_thunk);
+
+  return 1;
+}
+
+// The CRT heap cleanup stub.
+extern "C" void _heap_term() {}
+
+// We set this to 1 because part of the CRT uses a check of _crtheap != 0
+// to test whether the CRT has been initialized.  Once we've ripped out
+// the allocators from libcmt, we need to provide this definition so that
+// the rest of the CRT is still usable.
+extern "C" void* _crtheap = reinterpret_cast<void*>(1);
+
+// Provide support for aligned memory through Windows only _aligned_malloc().
+void* _aligned_malloc(size_t size, size_t alignment) {
+  // _aligned_malloc guarantees parameter validation, so do so here.  These
+  // checks are somewhat stricter than _aligned_malloc() since we're effectively
+  // using memalign() under the hood.
+  DCHECK_GT(size, 0U);
+  DCHECK_EQ(alignment & (alignment - 1), 0U);
+  DCHECK_EQ(alignment % sizeof(void*), 0U);
+
+  void* ptr;
+  for (;;) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+    switch (allocator) {
+      case JEMALLOC:
+        ptr = je_memalign(alignment, size);
+        break;
+      case WINHEAP:
+      case WINLFH:
+        ptr = win_heap_memalign(alignment, size);
+        break;
+      case TCMALLOC:
+      default:
+        ptr = tc_memalign(alignment, size);
+        break;
+    }
+#else
+    // TCMalloc case.
+    ptr = tc_memalign(alignment, size);
+#endif
+    if (ptr) {
+      // Sanity check alignment.
+      DCHECK_EQ(reinterpret_cast<uintptr_t>(ptr) & (alignment - 1), 0U);
+      return ptr;
+    }
+
+    if (!new_mode || !call_new_handler(true))
+      break;
+  }
+  return ptr;
+}
+
+void _aligned_free(void* p) {
+  // Both JEMalloc and TCMalloc return pointers from memalign() that are safe to
+  // use with free().  Pointers allocated with win_heap_memalign() MUST be freed
+  // via win_heap_memalign_free() since the aligned pointer is not the real one.
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+  switch (allocator) {
+    case JEMALLOC:
+      je_free(p);
+      return;
+    case WINHEAP:
+    case WINLFH:
+      win_heap_memalign_free(p);
+      return;
+  }
+#endif
+  // TCMalloc case.
+  do_free(p);
+}
+
+#endif  // WIN32
+
+#include "generic_allocators.cc"
+
+}  // extern C
+
+namespace base {
+namespace allocator {
+
+void SetupSubprocessAllocator() {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+  size_t primary_length = 0;
+  getenv_s(&primary_length, NULL, 0, primary_name);
+
+  size_t secondary_length = 0;
+  char buffer[20];
+  getenv_s(&secondary_length, buffer, sizeof(buffer), secondary_name);
+  DCHECK_GT(sizeof(buffer), secondary_length);
+  buffer[sizeof(buffer) - 1] = '\0';
+
+  if (secondary_length || !primary_length) {
+    const char* secondary_value = secondary_length ? buffer : "TCMALLOC";
+    // Force renderer (or other subprocesses) to use secondary_value.
+    int ret_val = _putenv_s(primary_name, secondary_value);
+    DCHECK_EQ(0, ret_val);
+  }
+#endif  // ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+}
+
+void* TCMallocDoMallocForTest(size_t size) {
+  return do_malloc(size);
+}
+
+void TCMallocDoFreeForTest(void* ptr) {
+  do_free(ptr);
+}
+
+size_t ExcludeSpaceForMarkForTest(size_t size) {
+  return ExcludeSpaceForMark(size);
+}
+
+}  // namespace allocator.
+}  // namespace base.
diff --git a/base/allocator/allocator_shim.h b/base/allocator/allocator_shim.h
new file mode 100644
index 0000000..e10fa8d
--- /dev/null
+++ b/base/allocator/allocator_shim.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_ALLOCATOR_ALLOCATOR_SHIM_H_
+#define BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
+
+namespace base {
+namespace allocator {
+
+// Resets the environment variable CHROME_ALLOCATOR to specify the choice to
+// be used by subprocesses.  Priority is given to the current value of
+// CHROME_ALLOCATOR_2 (if specified), then CHROME_ALLOCATOR (if specified), and
+// then a default value (typically set to TCMALLOC).
+void SetupSubprocessAllocator();
+
+// Expose some of tcmalloc functions for test.
+void* TCMallocDoMallocForTest(size_t size);
+void TCMallocDoFreeForTest(void* ptr);
+size_t ExcludeSpaceForMarkForTest(size_t size);
+
+}  // namespace allocator.
+}  // namespace base.
+
+#endif   // BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
diff --git a/base/allocator/allocator_unittests.cc b/base/allocator/allocator_unittests.cc
new file mode 100644
index 0000000..cf8b74d
--- /dev/null
+++ b/base/allocator/allocator_unittests.cc
@@ -0,0 +1,521 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <algorithm>   // for min()
+#include "base/atomicops.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Number of bits in a size_t.
+static const int kSizeBits = 8 * sizeof(size_t);
+// The maximum size of a size_t.
+static const size_t kMaxSize = ~static_cast<size_t>(0);
+// Maximum positive size of a size_t if it were signed.
+static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1);
+// An allocation size which is not too big to be reasonable.
+static const size_t kNotTooBig = 100000;
+// An allocation size which is just too big.
+static const size_t kTooBig = ~static_cast<size_t>(0);
+
+namespace {
+
+using std::min;
+
+// Fill a buffer of the specified size with a predetermined pattern
+static void Fill(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    buffer[i] = (i & 0xff);
+  }
+}
+
+// Check that the specified buffer has the predetermined pattern
+// generated by Fill()
+static bool Valid(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    if (buffer[i] != (i & 0xff)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Check that a buffer is completely zeroed.
+static bool IsZeroed(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    if (buffer[i] != 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Check alignment
+static void CheckAlignment(void* p, int align) {
+  EXPECT_EQ(0, reinterpret_cast<uintptr_t>(p) & (align-1));
+}
+
+// Return the next interesting size/delta to check.  Returns -1 if no more.
+static int NextSize(int size) {
+  if (size < 100)
+    return size+1;
+
+  if (size < 100000) {
+    // Find next power of two
+    int power = 1;
+    while (power < size)
+      power <<= 1;
+
+    // Yield (power-1, power, power+1)
+    if (size < power-1)
+      return power-1;
+
+    if (size == power-1)
+      return power;
+
+    assert(size == power);
+    return power+1;
+  } else {
+    return -1;
+  }
+}
+
+#define GG_ULONGLONG(x)  static_cast<uint64>(x)
+
+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 to do the wrong thing on 64-bit machines.
+  struct {
+    AtomicType prev_word;
+    AtomicType count;
+    AtomicType next_word;
+  } s;
+
+  AtomicType prev_word_value, next_word_value;
+  memset(&prev_word_value, 0xFF, sizeof(AtomicType));
+  memset(&next_word_value, 0xEE, sizeof(AtomicType));
+
+  s.prev_word = prev_word_value;
+  s.count = 0;
+  s.next_word = next_word_value;
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1);
+  EXPECT_EQ(s.count, 1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3);
+  EXPECT_EQ(s.count, 3);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6);
+  EXPECT_EQ(s.count, 6);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3);
+  EXPECT_EQ(s.count, 3);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1);
+  EXPECT_EQ(s.count, 1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0);
+  EXPECT_EQ(s.count, 0);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1);
+  EXPECT_EQ(s.count, -1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5);
+  EXPECT_EQ(s.count, -5);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0);
+  EXPECT_EQ(s.count, 0);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+}
+
+
+#define NUM_BITS(T) (sizeof(T) * 8)
+
+
+template <class AtomicType>
+static void TestCompareAndSwap() {
+  AtomicType value = 0;
+  AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1);
+  EXPECT_EQ(1, value);
+  EXPECT_EQ(0, prev);
+
+  // Use test value that has non-zero bits in both halves, more for testing
+  // 64-bit implementation on 32-bit platforms.
+  const AtomicType k_test_val = (GG_ULONGLONG(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 = (GG_ULONGLONG(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 increment at the half-width boundary of the atomic type.
+  // It is primarily for testing at the 32-bit boundary for 64-bit atomic type.
+  AtomicType test_val = GG_ULONGLONG(1) << (NUM_BITS(AtomicType) / 2);
+  AtomicType value = test_val - 1;
+  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(test_val - 1, value);
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestStore() {
+  const AtomicType kVal1 = static_cast<AtomicType>(0xa5a5a5a5a5a5a5a5LL);
+  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 = static_cast<AtomicType>(0xa5a5a5a5a5a5a5a5LL);
+  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));
+}
+
+template <class AtomicType>
+static void TestAtomicOps() {
+  TestCompareAndSwap<AtomicType>();
+  TestAtomicExchange<AtomicType>();
+  TestAtomicIncrementBounds<AtomicType>();
+  TestStore<AtomicType>();
+  TestLoad<AtomicType>();
+}
+
+static void TestCalloc(size_t n, size_t s, bool ok) {
+  char* p = reinterpret_cast<char*>(calloc(n, s));
+  if (!ok) {
+    EXPECT_EQ(NULL, p) << "calloc(n, s) should not succeed";
+  } else {
+    EXPECT_NE(reinterpret_cast<void*>(NULL), p) <<
+        "calloc(n, s) should succeed";
+    for (int i = 0; i < n*s; i++) {
+      EXPECT_EQ('\0', p[i]);
+    }
+    free(p);
+  }
+}
+
+
+// A global test counter for number of times the NewHandler is called.
+static int news_handled = 0;
+static void TestNewHandler() {
+  ++news_handled;
+  throw std::bad_alloc();
+}
+
+// Because we compile without exceptions, we expect these will not throw.
+static void TestOneNewWithoutExceptions(void* (*func)(size_t),
+                                        bool should_throw) {
+  // success test
+  try {
+    void* ptr = (*func)(kNotTooBig);
+    EXPECT_NE(reinterpret_cast<void*>(NULL), ptr) <<
+        "allocation should not have failed.";
+  } catch(...) {
+    EXPECT_EQ(0, 1) << "allocation threw unexpected exception.";
+  }
+
+  // failure test
+  try {
+    void* rv = (*func)(kTooBig);
+    EXPECT_EQ(NULL, rv);
+    EXPECT_FALSE(should_throw) << "allocation should have thrown.";
+  } catch(...) {
+    EXPECT_TRUE(should_throw) << "allocation threw unexpected exception.";
+  }
+}
+
+static void TestNothrowNew(void* (*func)(size_t)) {
+  news_handled = 0;
+
+  // test without new_handler:
+  std::new_handler saved_handler = std::set_new_handler(0);
+  TestOneNewWithoutExceptions(func, false);
+
+  // test with new_handler:
+  std::set_new_handler(TestNewHandler);
+  TestOneNewWithoutExceptions(func, true);
+  EXPECT_EQ(news_handled, 1) << "nothrow new_handler was not called.";
+  std::set_new_handler(saved_handler);
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+
+TEST(Atomics, AtomicIncrementWord) {
+  TestAtomicIncrement<AtomicWord>();
+}
+
+TEST(Atomics, AtomicIncrement32) {
+  TestAtomicIncrement<Atomic32>();
+}
+
+TEST(Atomics, AtomicOpsWord) {
+  TestAtomicIncrement<AtomicWord>();
+}
+
+TEST(Atomics, AtomicOps32) {
+  TestAtomicIncrement<Atomic32>();
+}
+
+TEST(Allocators, Malloc) {
+  // Try allocating data with a bunch of alignments and sizes
+  for (int size = 1; size < 1048576; size *= 2) {
+    unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size));
+    CheckAlignment(ptr, 2);  // Should be 2 byte aligned
+    Fill(ptr, size);
+    EXPECT_TRUE(Valid(ptr, size));
+    free(ptr);
+  }
+}
+
+TEST(Allocators, Calloc) {
+  TestCalloc(0, 0, true);
+  TestCalloc(0, 1, true);
+  TestCalloc(1, 1, true);
+  TestCalloc(1<<10, 0, true);
+  TestCalloc(1<<20, 0, true);
+  TestCalloc(0, 1<<10, true);
+  TestCalloc(0, 1<<20, true);
+  TestCalloc(1<<20, 2, true);
+  TestCalloc(2, 1<<20, true);
+  TestCalloc(1000, 1000, true);
+
+  TestCalloc(kMaxSize, 2, false);
+  TestCalloc(2, kMaxSize, false);
+  TestCalloc(kMaxSize, kMaxSize, false);
+
+  TestCalloc(kMaxSignedSize, 3, false);
+  TestCalloc(3, kMaxSignedSize, false);
+  TestCalloc(kMaxSignedSize, kMaxSignedSize, false);
+}
+
+TEST(Allocators, New) {
+  TestNothrowNew(&::operator new);
+  TestNothrowNew(&::operator new[]);
+}
+
+// This makes sure that reallocing a small number of bytes in either
+// direction doesn't cause us to allocate new memory.
+TEST(Allocators, Realloc1) {
+  int start_sizes[] = { 100, 1000, 10000, 100000 };
+  int deltas[] = { 1, -2, 4, -8, 16, -32, 64, -128 };
+
+  for (int s = 0; s < sizeof(start_sizes)/sizeof(*start_sizes); ++s) {
+    void* p = malloc(start_sizes[s]);
+    ASSERT_TRUE(p);
+    // The larger the start-size, the larger the non-reallocing delta.
+    for (int d = 0; d < s*2; ++d) {
+      void* new_p = realloc(p, start_sizes[s] + deltas[d]);
+      ASSERT_EQ(p, new_p);  // realloc should not allocate new memory
+    }
+    // Test again, but this time reallocing smaller first.
+    for (int d = 0; d < s*2; ++d) {
+      void* new_p = realloc(p, start_sizes[s] - deltas[d]);
+      ASSERT_EQ(p, new_p);  // realloc should not allocate new memory
+    }
+    free(p);
+  }
+}
+
+TEST(Allocators, Realloc2) {
+  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+      unsigned char* src = reinterpret_cast<unsigned char*>(malloc(src_size));
+      Fill(src, src_size);
+      unsigned char* dst =
+          reinterpret_cast<unsigned char*>(realloc(src, dst_size));
+      EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
+      Fill(dst, dst_size);
+      EXPECT_TRUE(Valid(dst, dst_size));
+      if (dst != NULL) free(dst);
+    }
+  }
+
+  // Now make sure realloc works correctly even when we overflow the
+  // packed cache, so some entries are evicted from the cache.
+  // The cache has 2^12 entries, keyed by page number.
+  const int kNumEntries = 1 << 14;
+  int** p = reinterpret_cast<int**>(malloc(sizeof(*p) * kNumEntries));
+  int sum = 0;
+  for (int i = 0; i < kNumEntries; i++) {
+    // no page size is likely to be bigger than 8192?
+    p[i] = reinterpret_cast<int*>(malloc(8192));
+    p[i][1000] = i;              // use memory deep in the heart of p
+  }
+  for (int i = 0; i < kNumEntries; i++) {
+    p[i] = reinterpret_cast<int*>(realloc(p[i], 9000));
+  }
+  for (int i = 0; i < kNumEntries; i++) {
+    sum += p[i][1000];
+    free(p[i]);
+  }
+  EXPECT_EQ(kNumEntries/2 * (kNumEntries - 1), sum);  // assume kNE is even
+  free(p);
+}
+
+TEST(Allocators, ReallocZero) {
+  // Test that realloc to zero does not return NULL.
+  for (int size = 0; size >= 0; size = NextSize(size)) {
+    char* ptr = reinterpret_cast<char*>(malloc(size));
+    EXPECT_NE(static_cast<char*>(NULL), ptr);
+    ptr = reinterpret_cast<char*>(realloc(ptr, 0));
+    EXPECT_NE(static_cast<char*>(NULL), ptr);
+    if (ptr)
+      free(ptr);
+  }
+}
+
+#ifdef WIN32
+// Test recalloc
+TEST(Allocators, Recalloc) {
+  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+      unsigned char* src =
+          reinterpret_cast<unsigned char*>(_recalloc(NULL, 1, src_size));
+      EXPECT_TRUE(IsZeroed(src, src_size));
+      Fill(src, src_size);
+      unsigned char* dst =
+          reinterpret_cast<unsigned char*>(_recalloc(src, 1, dst_size));
+      EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
+      Fill(dst, dst_size);
+      EXPECT_TRUE(Valid(dst, dst_size));
+      if (dst != NULL)
+        free(dst);
+    }
+  }
+}
+
+// Test windows specific _aligned_malloc() and _aligned_free() methods.
+TEST(Allocators, AlignedMalloc) {
+  // Try allocating data with a bunch of alignments and sizes
+  static const int kTestAlignments[] = {8, 16, 256, 4096, 8192, 16384};
+  for (int size = 1; size > 0; size = NextSize(size)) {
+    for (int i = 0; i < ARRAYSIZE(kTestAlignments); ++i) {
+      unsigned char* ptr = static_cast<unsigned char*>(
+          _aligned_malloc(size, kTestAlignments[i]));
+      CheckAlignment(ptr, kTestAlignments[i]);
+      Fill(ptr, size);
+      EXPECT_TRUE(Valid(ptr, size));
+
+      // Make a second allocation of the same size and alignment to prevent
+      // allocators from passing this test by accident.  Per jar, tcmalloc
+      // provides allocations for new (never before seen) sizes out of a thread
+      // local heap of a given "size class."  Each time the test requests a new
+      // size, it will usually get the first element of a span, which is a
+      // 4K aligned allocation.
+      unsigned char* ptr2 = static_cast<unsigned char*>(
+          _aligned_malloc(size, kTestAlignments[i]));
+      CheckAlignment(ptr2, kTestAlignments[i]);
+      Fill(ptr2, size);
+      EXPECT_TRUE(Valid(ptr2, size));
+
+      // Should never happen, but sanity check just in case.
+      ASSERT_NE(ptr, ptr2);
+      _aligned_free(ptr);
+      _aligned_free(ptr2);
+    }
+  }
+}
+
+#endif
+
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/generic_allocators.cc b/base/allocator/generic_allocators.cc
new file mode 100644
index 0000000..d4cf19e
--- /dev/null
+++ b/base/allocator/generic_allocators.cc
@@ -0,0 +1,168 @@
+// 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.
+
+// When possible, we implement allocator functions on top of the basic
+// low-level functions malloc() and free().  This way, including a new
+// allocator is as simple as providing just a small interface.
+//
+// As such, this file should not contain any allocator-specific code.
+
+// Implement a C++ style allocation, which always calls the new_handler
+// on failure.
+inline void* generic_cpp_alloc(size_t size, bool nothrow) {
+  void* ptr;
+  for (;;) {
+    ptr = malloc(size);
+    if (ptr)
+      return ptr;
+    if (!call_new_handler(nothrow))
+      break;
+  }
+  return ptr;
+}
+
+extern "C++" {
+
+void* __cdecl operator new(size_t size) {
+  return generic_cpp_alloc(size, false);
+}
+
+void operator delete(void* p) __THROW {
+  free(p);
+}
+
+void* operator new[](size_t size) {
+  return generic_cpp_alloc(size, false);
+}
+
+void operator delete[](void* p) __THROW {
+  free(p);
+}
+
+void* operator new(size_t size, const std::nothrow_t& nt) __THROW {
+  return generic_cpp_alloc(size, true);
+}
+
+void* operator new[](size_t size, const std::nothrow_t& nt) __THROW {
+  return generic_cpp_alloc(size, true);
+}
+
+// This function behaves similarly to MSVC's _set_new_mode.
+// If flag is 0 (default), calls to malloc will behave normally.
+// If flag is 1, calls to malloc will behave like calls to new,
+// and the std_new_handler will be invoked on failure.
+// Returns the previous mode.
+int _set_new_mode(int flag) __THROW {
+  int old_mode = new_mode;
+  new_mode = flag;
+  return old_mode;
+}
+
+}  // extern "C++"
+
+extern "C" {
+
+void* calloc(size_t n, size_t elem_size) __THROW {
+  // Overflow check
+  const size_t size = n * elem_size;
+  if (elem_size != 0 && size / elem_size != n) return NULL;
+
+  void* result = malloc(size);
+  if (result != NULL) {
+    memset(result, 0, size);
+  }
+  return result;
+}
+
+void cfree(void* p) __THROW {
+  free(p);
+}
+
+#ifdef WIN32
+
+void* _recalloc(void* p, size_t n, size_t elem_size) {
+  if (!p)
+    return calloc(n, elem_size);
+
+  // This API is a bit odd.
+  // Note: recalloc only guarantees zeroed memory when p is NULL.
+  //   Generally, calls to malloc() have padding.  So a request
+  //   to malloc N bytes actually malloc's N+x bytes.  Later, if
+  //   that buffer is passed to recalloc, we don't know what N
+  //   was anymore.  We only know what N+x is.  As such, there is
+  //   no way to know what to zero out.
+  const size_t size = n * elem_size;
+  if (elem_size != 0 && size / elem_size != n) return NULL;
+  return realloc(p, size);
+}
+
+void* _calloc_impl(size_t n, size_t size) {
+  return calloc(n, size);
+}
+
+#ifndef NDEBUG
+#undef malloc
+#undef free
+#undef calloc
+
+static int error_handler(int reportType) {
+  switch (reportType) {
+    case 0:  // _CRT_WARN
+      __debugbreak();
+      return 0;
+
+    case 1:  // _CRT_ERROR
+      __debugbreak();
+      return 0;
+
+    case 2:  // _CRT_ASSERT
+      __debugbreak();
+      return 0;
+  }
+  char* p = NULL;
+  *p = '\0';
+  return 0;
+}
+
+int _CrtDbgReport(int reportType,
+                  const char*,
+                  int, const char*,
+                  const char*,
+                  ...) {
+  return error_handler(reportType);
+}
+
+int _CrtDbgReportW(int reportType,
+                   const wchar_t*,
+                   int, const wchar_t*,
+                   const wchar_t*,
+                   ...) {
+  return error_handler(reportType);
+}
+
+int _CrtSetReportMode(int, int) {
+  return 0;
+}
+
+void* _malloc_dbg(size_t size, int , const char*, int) {
+  return malloc(size);
+}
+
+void* _realloc_dbg(void* ptr, size_t size, int, const char*, int) {
+  return realloc(ptr, size);
+}
+
+void _free_dbg(void* ptr, int) {
+  free(ptr);
+}
+
+void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
+  return calloc(n, size);
+}
+#endif  // NDEBUG
+
+#endif  // WIN32
+
+}  // extern C
+
diff --git a/base/allocator/prep_libc.py b/base/allocator/prep_libc.py
new file mode 100755
index 0000000..be7030f
--- /dev/null
+++ b/base/allocator/prep_libc.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# This script takes libcmt.lib for VS2005/08/10 and removes the allocation
+# related functions from it.
+#
+# Usage: prep_libc.py <VCInstallDir> <OutputDir>
+#
+# VCInstallDir is the path where VC is installed, something like:
+#    C:\Program Files\Microsoft Visual Studio 8\VC\
+#
+# OutputDir is the directory where the modified libcmt file should be stored.
+
+import os
+import shutil
+import subprocess
+import sys
+
+def run(command, filter=None):
+  """Run |command|, removing any lines that match |filter|. The filter is
+  to remove the echoing of input filename that 'lib' does."""
+  popen = subprocess.Popen(
+      command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+  out, _ = popen.communicate()
+  for line in out.splitlines():
+    if filter and line.strip() != filter:
+      print line
+  return popen.returncode
+
+def main():
+  vs_install_dir = sys.argv[1]
+  outdir = sys.argv[2]
+  output_lib = os.path.join(outdir, 'libcmt.lib')
+  shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.lib'), output_lib)
+  shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.pdb'),
+                  os.path.join(outdir, 'libcmt.pdb'))
+  vspaths = [
+    'build\\intel\\mt_obj\\',
+    'f:\\dd\\vctools\\crt_bld\\SELF_X86\\crt\\src\\build\\INTEL\\mt_obj\\',
+    'F:\\dd\\vctools\\crt_bld\\SELF_X86\\crt\\src\\build\\INTEL\\mt_obj\\nativec\\\\',
+    'F:\\dd\\vctools\\crt_bld\\SELF_X86\\crt\\src\\build\\INTEL\\mt_obj\\nativecpp\\\\',
+  ]
+  objfiles = ['malloc', 'free', 'realloc', 'new', 'delete', 'new2', 'delete2',
+              'align', 'msize', 'heapinit', 'expand', 'heapchk', 'heapwalk',
+              'heapmin', 'sbheap', 'calloc', 'recalloc', 'calloc_impl',
+              'new_mode', 'newopnt']
+  for obj in objfiles:
+    for vspath in vspaths:
+      cmd = ('lib /nologo /ignore:4006,4014,4221 /remove:%s%s.obj %s' %
+             (vspath, obj, output_lib))
+      run(cmd, obj + '.obj')
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/base/allocator/tcmalloc_unittest.cc b/base/allocator/tcmalloc_unittest.cc
new file mode 100644
index 0000000..053a9d5
--- /dev/null
+++ b/base/allocator/tcmalloc_unittest.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 <stdio.h>
+#include "base/allocator/allocator_shim.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// TCMalloc header files
+#include "common.h"  // For TCMalloc constants like page size, etc.
+
+using base::allocator::TCMallocDoMallocForTest;
+using base::allocator::TCMallocDoFreeForTest;
+using base::allocator::ExcludeSpaceForMarkForTest;
+
+TEST(TCMallocFreeCheck, BadPointerInFirstPageOfTheLargeObject) {
+  char* p = reinterpret_cast<char*>(
+      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+  for (int offset = 1; offset < kPageSize ; offset <<= 1) {
+    ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
+                 "Pointer is not pointing to the start of a span");
+  }
+}
+
+TEST(TCMallocFreeCheck, BadPageAlignedPointerInsideLargeObject) {
+  char* p = reinterpret_cast<char*>(
+      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+
+  for (int offset = kPageSize; offset < kMaxSize; offset += kPageSize) {
+    // Only the first and last page of a span are in heap map. So for others
+    // tcmalloc will give a general error of invalid pointer.
+    ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
+                 "Attempt to free invalid pointer");
+  }
+  ASSERT_DEATH(TCMallocDoFreeForTest(p + kMaxSize),
+               "Pointer is not pointing to the start of a span");
+}
+
+TEST(TCMallocFreeCheck, DoubleFreeLargeObject) {
+  char* p = reinterpret_cast<char*>(
+      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+  ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+               "Object was not in-use");
+}
+
+
+#ifdef NDEBUG
+TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
+  for (size_t size = 1;
+       size <= ExcludeSpaceForMarkForTest(kMaxSize);
+       size <<= 1) {
+    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+                 "Circular loop in list detected");
+  }
+}
+#else
+TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
+  size_t size = 1;
+
+  // When the object is small, tcmalloc validation can not distinguish normal
+  // memory corruption or double free, because there's not enough space in
+  // freed objects to keep the mark.
+  for (; size <= ExcludeSpaceForMarkForTest(kMinClassSize); size <<= 1) {
+    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+                 "Memory corrupted");
+  }
+
+  for (; size <= ExcludeSpaceForMarkForTest(kMaxSize); size <<= 1) {
+    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+                 "Attempt to double free");
+  }
+}
+#endif
+
+int main(int argc, char **argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/type_profiler.cc b/base/allocator/type_profiler.cc
new file mode 100644
index 0000000..635fbcf
--- /dev/null
+++ b/base/allocator/type_profiler.cc
@@ -0,0 +1,63 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler.h"
+
+#include <assert.h>
+
+namespace {
+
+void* NopIntercept(void* ptr, size_t size, const std::type_info& type) {
+  return ptr;
+}
+
+base::type_profiler::InterceptFunction* g_new_intercept = NopIntercept;
+base::type_profiler::InterceptFunction* g_delete_intercept = NopIntercept;
+
+}
+
+void* __op_new_intercept__(void* ptr,
+                           size_t size,
+                           const std::type_info& type) {
+  return g_new_intercept(ptr, size, type);
+}
+
+void* __op_delete_intercept__(void* ptr,
+                              size_t size,
+                              const std::type_info& type) {
+  return g_delete_intercept(ptr, size, type);
+}
+
+namespace base {
+namespace type_profiler {
+
+// static
+void InterceptFunctions::SetFunctions(InterceptFunction* new_intercept,
+                                      InterceptFunction* delete_intercept) {
+  // Don't use DCHECK, as this file is injected into targets
+  // that do not and should not depend on base/base.gyp:base
+  assert(g_new_intercept == NopIntercept);
+  assert(g_delete_intercept == NopIntercept);
+
+  g_new_intercept = new_intercept;
+  g_delete_intercept = delete_intercept;
+}
+
+// static
+void InterceptFunctions::ResetFunctions() {
+  g_new_intercept = NopIntercept;
+  g_delete_intercept = NopIntercept;
+}
+
+// static
+bool InterceptFunctions::IsAvailable() {
+  return g_new_intercept != NopIntercept || g_delete_intercept != NopIntercept;
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
diff --git a/base/allocator/type_profiler.h b/base/allocator/type_profiler.h
new file mode 100644
index 0000000..86b5711
--- /dev/null
+++ b/base/allocator/type_profiler.h
@@ -0,0 +1,40 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_TYPE_PROFILER_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_H_
+
+#if defined(TYPE_PROFILING)
+
+#include <stddef.h>  // for size_t
+#include <typeinfo>  // for std::typeinfo
+
+namespace base {
+namespace type_profiler {
+
+typedef void* InterceptFunction(void*, size_t, const std::type_info&);
+
+class InterceptFunctions {
+ public:
+  // It must be called only once in a process while it is in single-thread.
+  // For now, ContentMainRunnerImpl::Initialize is the only supposed caller
+  // of this function except for single-threaded unit tests.
+  static void SetFunctions(InterceptFunction* new_intercept,
+                           InterceptFunction* delete_intercept);
+
+ private:
+  friend class TypeProfilerTest;
+
+  // These functions are not thread safe.
+  // They must be used only from single-threaded unit tests.
+  static void ResetFunctions();
+  static bool IsAvailable();
+};
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+#endif  // BASE_ALLOCATOR_TYPE_PROFILER_H_
diff --git a/base/allocator/type_profiler_control.cc b/base/allocator/type_profiler_control.cc
new file mode 100644
index 0000000..6be7984
--- /dev/null
+++ b/base/allocator/type_profiler_control.cc
@@ -0,0 +1,38 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/type_profiler_control.h"
+
+namespace base {
+namespace type_profiler {
+
+namespace {
+
+#if defined(TYPE_PROFILING)
+const bool kTypeProfilingEnabled = true;
+#else
+const bool kTypeProfilingEnabled = false;
+#endif
+
+bool g_enable_intercept = kTypeProfilingEnabled;
+
+}  // namespace
+
+// static
+void Controller::Stop() {
+  g_enable_intercept = false;
+}
+
+// static
+bool Controller::IsProfiling() {
+  return kTypeProfilingEnabled && g_enable_intercept;
+}
+
+// static
+void Controller::Restart() {
+  g_enable_intercept = kTypeProfilingEnabled;
+}
+
+}  // namespace type_profiler
+}  // namespace base
diff --git a/base/allocator/type_profiler_control.h b/base/allocator/type_profiler_control.h
new file mode 100644
index 0000000..17cf5b6
--- /dev/null
+++ b/base/allocator/type_profiler_control.h
@@ -0,0 +1,31 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
+
+#include "base/gtest_prod_util.h"
+
+namespace base {
+namespace type_profiler {
+
+class Controller {
+ public:
+  static void Stop();
+  static bool IsProfiling();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TypeProfilerTest,
+                           TestProfileNewWithoutProfiledDelete);
+
+  // It must be used only from allowed unit tests.  The following is only
+  // allowed for use in unit tests. Profiling should never be restarted in
+  // regular use.
+  static void Restart();
+};
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
diff --git a/base/allocator/type_profiler_map_unittests.cc b/base/allocator/type_profiler_map_unittests.cc
new file mode 100644
index 0000000..5ac5dd0
--- /dev/null
+++ b/base/allocator/type_profiler_map_unittests.cc
@@ -0,0 +1,99 @@
+// 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.
+
+// This is a unittest set for type_profiler_map in third_party/tcmalloc.  It is
+// independent from other tests and executed manually like allocator_unittests
+// since type_profiler_map is a singleton (like TCMalloc's heap-profiler), and
+// it requires RTTI and different compiling/linking options from others.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+static const void* const g_const_null = static_cast<const void*>(NULL);
+
+TEST(TypeProfilerMapTest, NormalOperation) {
+  // Allocate an object just to get a valid address.
+  // This 'new' is not profiled by type_profiler.
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  type = LookupType(dummy.get());
+  EXPECT_EQ(g_const_null, type);
+
+  InsertType(dummy.get(), 12, typeid(int));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  EraseType(dummy.get());
+  type = LookupType(dummy.get());
+  EXPECT_EQ(g_const_null, type);
+}
+
+TEST(TypeProfilerMapTest, EraseWithoutInsert) {
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  for (int i = 0; i < 10; ++i) {
+    EraseType(dummy.get());
+    type = LookupType(dummy.get());
+    EXPECT_EQ(g_const_null, type);
+  }
+}
+
+TEST(TypeProfilerMapTest, InsertThenMultipleErase) {
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  InsertType(dummy.get(), 12, typeid(int));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  for (int i = 0; i < 10; ++i) {
+    EraseType(dummy.get());
+    type = LookupType(dummy.get());
+    EXPECT_EQ(g_const_null, type);
+  }
+}
+
+TEST(TypeProfilerMapTest, MultipleInsertWithoutErase) {
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  InsertType(dummy.get(), 12, typeid(int));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  InsertType(dummy.get(), 5, typeid(char));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(char).name(), type->name());
+
+  InsertType(dummy.get(), 129, typeid(long));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(long).name(), type->name());
+
+  EraseType(dummy.get());
+  type = LookupType(dummy.get());
+  EXPECT_EQ(g_const_null, type);
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/type_profiler_tcmalloc.cc b/base/allocator/type_profiler_tcmalloc.cc
new file mode 100644
index 0000000..e5e10e0
--- /dev/null
+++ b/base/allocator/type_profiler_tcmalloc.cc
@@ -0,0 +1,37 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler_tcmalloc.h"
+
+#include "base/allocator/type_profiler_control.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+void* NewInterceptForTCMalloc(void* ptr,
+                              size_t size,
+                              const std::type_info& type) {
+  if (Controller::IsProfiling())
+    InsertType(ptr, size, type);
+
+  return ptr;
+}
+
+void* DeleteInterceptForTCMalloc(void* ptr,
+                                 size_t size,
+                                 const std::type_info& type) {
+  if (Controller::IsProfiling())
+    EraseType(ptr);
+
+  return ptr;
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
diff --git a/base/allocator/type_profiler_tcmalloc.h b/base/allocator/type_profiler_tcmalloc.h
new file mode 100644
index 0000000..ac55995
--- /dev/null
+++ b/base/allocator/type_profiler_tcmalloc.h
@@ -0,0 +1,29 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
+
+#if defined(TYPE_PROFILING)
+
+#include <cstddef>  // for size_t
+#include <typeinfo>  // for std::type_info
+
+namespace base {
+namespace type_profiler {
+
+void* NewInterceptForTCMalloc(void* ptr,
+                              size_t size,
+                              const std::type_info& type);
+
+void* DeleteInterceptForTCMalloc(void* ptr,
+                                 size_t size,
+                                 const std::type_info& type);
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+#endif  // BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
diff --git a/base/allocator/type_profiler_unittests.cc b/base/allocator/type_profiler_unittests.cc
new file mode 100644
index 0000000..e8f06ed
--- /dev/null
+++ b/base/allocator/type_profiler_unittests.cc
@@ -0,0 +1,189 @@
+// 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.
+
+// This is a unittest set for type_profiler.  It is independent from other
+// tests and executed manually like allocator_unittests since type_profiler_map
+// used in type_profiler is a singleton (like TCMalloc's heap-profiler), and
+// it requires RTTI and different compiling/linking options from others
+//
+// It tests that the profiler doesn't fail in suspicous cases.  For example,
+// 'new' is not profiled, but 'delete' for the created object is profiled.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler.h"
+#include "base/allocator/type_profiler_control.h"
+#include "base/allocator/type_profiler_tcmalloc.h"
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+class TypeProfilerTest : public testing::Test {
+ public:
+  TypeProfilerTest() {}
+
+  void SetInterceptFunctions() {
+    InterceptFunctions::SetFunctions(NewInterceptForTCMalloc,
+                                     DeleteInterceptForTCMalloc);
+  }
+
+  void ResetInterceptFunctions() {
+    InterceptFunctions::ResetFunctions();
+  }
+
+  void SetUp() {
+    SetInterceptFunctions();
+  }
+
+  void TearDown() {
+    ResetInterceptFunctions();
+  }
+
+ protected:
+  static const size_t kDummyArraySize;
+  static const void* const kConstNull;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TypeProfilerTest);
+};
+
+const size_t TypeProfilerTest::kDummyArraySize = 10;
+const void* const TypeProfilerTest::kConstNull = static_cast<const void*>(NULL);
+
+TEST_F(TypeProfilerTest, TestNormalProfiling) {
+  int* dummy = new int(48);
+  const std::type_info* type;
+
+  type = LookupType(dummy);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+  delete dummy;
+
+  type = LookupType(dummy);
+  EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestNormalArrayProfiling) {
+  int* dummy = new int[kDummyArraySize];
+  const std::type_info* type;
+
+  type = LookupType(dummy);
+  ASSERT_NE(kConstNull, type);
+  // For an array, the profiler remembers its base type.
+  EXPECT_STREQ(typeid(int).name(), type->name());
+  delete[] dummy;
+
+  type = LookupType(dummy);
+  EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestRepeatedNewAndDelete) {
+  int *dummy[kDummyArraySize];
+  const std::type_info* type;
+  for (int i = 0; i < kDummyArraySize; ++i)
+    dummy[i] = new int(i);
+
+  for (int i = 0; i < kDummyArraySize; ++i) {
+    type = LookupType(dummy[i]);
+    ASSERT_NE(kConstNull, type);
+    EXPECT_STREQ(typeid(int).name(), type->name());
+  }
+
+  for (int i = 0; i < kDummyArraySize; ++i) {
+    delete dummy[i];
+    type = LookupType(dummy[i]);
+    ASSERT_EQ(kConstNull, type);
+  }
+}
+
+TEST_F(TypeProfilerTest, TestMultipleNewWithDroppingDelete) {
+  static const size_t large_size = 256 * 1024;
+
+  char* dummy_char = new char[large_size / sizeof(*dummy_char)];
+  const std::type_info* type;
+
+  type = LookupType(dummy_char);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(char).name(), type->name());
+
+  // Call "::operator delete" directly to drop __op_delete_intercept__.
+  ::operator delete[](dummy_char);
+
+  type = LookupType(dummy_char);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(char).name(), type->name());
+
+  // Allocates a little different size.
+  int* dummy_int = new int[large_size / sizeof(*dummy_int) - 1];
+
+  // We expect that tcmalloc returns the same address for these large (over 32k)
+  // allocation calls.  It usually happens, but maybe probablistic.
+  ASSERT_EQ(static_cast<void*>(dummy_char), static_cast<void*>(dummy_int)) <<
+      "two new (malloc) calls didn't return the same address; retry it.";
+
+  type = LookupType(dummy_int);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  delete[] dummy_int;
+
+  type = LookupType(dummy_int);
+  EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestProfileDeleteWithoutProfiledNew) {
+  // 'dummy' should be new'ed in this test before intercept functions are set.
+  ResetInterceptFunctions();
+
+  int* dummy = new int(48);
+  const std::type_info* type;
+
+  // Set intercept functions again after 'dummy' is new'ed.
+  SetInterceptFunctions();
+
+  delete dummy;
+
+  type = LookupType(dummy);
+  EXPECT_EQ(kConstNull, type);
+
+  ResetInterceptFunctions();
+}
+
+TEST_F(TypeProfilerTest, TestProfileNewWithoutProfiledDelete) {
+  int* dummy = new int(48);
+  const std::type_info* type;
+
+  EXPECT_TRUE(Controller::IsProfiling());
+
+  // Stop profiling before deleting 'dummy'.
+  Controller::Stop();
+  EXPECT_FALSE(Controller::IsProfiling());
+
+  delete dummy;
+
+  // NOTE: We accept that a profile entry remains when a profiled object is
+  // deleted after Controller::Stop().
+  type = LookupType(dummy);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  Controller::Restart();
+  EXPECT_TRUE(Controller::IsProfiling());
+
+  // Remove manually since 'dummy' is not removed from type_profiler_map.
+  EraseType(dummy);
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/unittest_utils.cc b/base/allocator/unittest_utils.cc
new file mode 100644
index 0000000..130ba15
--- /dev/null
+++ b/base/allocator/unittest_utils.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The unittests need a this in order to link up without pulling in tons
+// of other libraries
+
+#include <config.h>
+
+inline int snprintf(char* buffer, size_t count, const char* format, ...) {
+    int result;
+    va_list args;
+    va_start(args, format);
+    result = _vsnprintf(buffer, count, format, args);
+    va_end(args);
+    return result;
+}
+
diff --git a/base/allocator/win_allocator.cc b/base/allocator/win_allocator.cc
new file mode 100644
index 0000000..899b867
--- /dev/null
+++ b/base/allocator/win_allocator.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a simple allocator based on the windows heap.
+
+extern "C" {
+
+HANDLE win_heap;
+
+bool win_heap_init(bool use_lfh) {
+  win_heap = HeapCreate(0, 0, 0);
+  if (win_heap == NULL)
+    return false;
+
+  if (use_lfh) {
+    ULONG enable_lfh = 2;
+    HeapSetInformation(win_heap, HeapCompatibilityInformation,
+                       &enable_lfh, sizeof(enable_lfh));
+    // NOTE: Setting LFH may fail.  Vista already has it enabled.
+    //       And under the debugger, it won't use LFH.  So we
+    //       ignore any errors.
+  }
+
+  return true;
+}
+
+void* win_heap_malloc(size_t size) {
+  return HeapAlloc(win_heap, 0, size);
+}
+
+void win_heap_free(void* size) {
+  HeapFree(win_heap, 0, size);
+}
+
+void* win_heap_realloc(void* ptr, size_t size) {
+  if (!ptr)
+    return win_heap_malloc(size);
+  if (!size) {
+    win_heap_free(ptr);
+    return NULL;
+  }
+  return HeapReAlloc(win_heap, 0, ptr, size);
+}
+
+size_t win_heap_msize(void* ptr) {
+  return HeapSize(win_heap, 0, ptr);
+}
+
+void* win_heap_memalign(size_t alignment, size_t size) {
+  // Reserve enough space to ensure we can align and set aligned_ptr[-1] to the
+  // original allocation for use with win_heap_memalign_free() later.
+  size_t allocation_size = size + (alignment - 1) + sizeof(void*);
+
+  // Check for overflow.  Alignment and size are checked in allocator_shim.
+  DCHECK_LT(size, allocation_size);
+  DCHECK_LT(alignment, allocation_size);
+
+  void* ptr = win_heap_malloc(allocation_size);
+  char* aligned_ptr = static_cast<char*>(ptr) + sizeof(void*);
+  aligned_ptr +=
+      alignment - reinterpret_cast<uintptr_t>(aligned_ptr) & (alignment - 1);
+
+  reinterpret_cast<void**>(aligned_ptr)[-1] = ptr;
+  return aligned_ptr;
+}
+
+void win_heap_memalign_free(void* ptr) {
+  if (ptr)
+    win_heap_free(static_cast<void**>(ptr)[-1]);
+}
+
+}  // extern "C"
diff --git a/base/android/OWNERS b/base/android/OWNERS
new file mode 100644
index 0000000..737d4e4
--- /dev/null
+++ b/base/android/OWNERS
@@ -0,0 +1,5 @@
+jrg@chromium.org
+bulach@chromium.org
+joth@chromium.org
+jcivelli@chromium.org
+yfriedman@chromium.org
diff --git a/base/android/base_jni_registrar.cc b/base/android/base_jni_registrar.cc
new file mode 100644
index 0000000..fb93217
--- /dev/null
+++ b/base/android/base_jni_registrar.cc
@@ -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.
+
+#include "base/android/base_jni_registrar.h"
+
+#include "base/basictypes.h"
+#include "base/android/build_info.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_registrar.h"
+#include "base/android/locale_utils.h"
+#include "base/android/path_service_android.h"
+#include "base/android/path_utils.h"
+#include "base/message_pump_android.h"
+#include "base/system_monitor/system_monitor_android.h"
+
+namespace base {
+namespace android {
+
+static RegistrationMethod kBaseRegisteredMethods[] = {
+  { "BuildInfo", base::android::BuildInfo::RegisterBindings },
+  { "LocaleUtils", base::android::RegisterLocaleUtils },
+  { "PathService", base::android::RegisterPathService },
+  { "PathUtils", base::android::RegisterPathUtils },
+  { "SystemMessageHandler", base::MessagePumpForUI::RegisterBindings },
+  { "SystemMonitor", base::RegisterSystemMonitor },
+};
+
+bool RegisterJni(JNIEnv* env) {
+  return RegisterNativeMethods(env, kBaseRegisteredMethods,
+                               arraysize(kBaseRegisteredMethods));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/base_jni_registrar.h b/base/android/base_jni_registrar.h
new file mode 100644
index 0000000..fdaf5f2
--- /dev/null
+++ b/base/android/base_jni_registrar.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_BASE_JNI_REGISTRAR_H_
+#define BASE_ANDROID_BASE_JNI_REGISTRAR_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// Register all JNI bindings necessary for base.
+BASE_EXPORT bool RegisterJni(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_BASE_JNI_REGISTRAR_H_
diff --git a/base/android/build_info.cc b/base/android/build_info.cc
new file mode 100644
index 0000000..273cbbd
--- /dev/null
+++ b/base/android/build_info.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/build_info.h"
+
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "jni/BuildInfo_jni.h"
+
+namespace {
+
+// The caller takes ownership of the returned const char*.
+const char* StrDupJString(const base::android::JavaRef<jstring>& java_string) {
+  std::string str = ConvertJavaStringToUTF8(java_string);
+  return strdup(str.c_str());
+}
+
+}  // namespace
+
+namespace base {
+namespace android {
+
+struct BuildInfoSingletonTraits {
+  static BuildInfo* New() {
+    return new BuildInfo(AttachCurrentThread());
+  }
+
+  static void Delete(BuildInfo* x) {
+    // We're leaking this type, see kRegisterAtExit.
+    NOTREACHED();
+  }
+
+  static const bool kRegisterAtExit = false;
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+};
+
+BuildInfo::BuildInfo(JNIEnv* env)
+    : device_(StrDupJString(Java_BuildInfo_getDevice(env))),
+      model_(StrDupJString(Java_BuildInfo_getDeviceModel(env))),
+      brand_(StrDupJString(Java_BuildInfo_getBrand(env))),
+      android_build_id_(StrDupJString(Java_BuildInfo_getAndroidBuildId(env))),
+      android_build_fp_(StrDupJString(
+          Java_BuildInfo_getAndroidBuildFingerprint(env))),
+      package_version_code_(StrDupJString(Java_BuildInfo_getPackageVersionCode(
+          env, GetApplicationContext()))),
+      package_version_name_(StrDupJString(Java_BuildInfo_getPackageVersionName(
+          env, GetApplicationContext()))),
+      package_label_(StrDupJString(Java_BuildInfo_getPackageLabel(
+          env, GetApplicationContext()))),
+      package_name_(StrDupJString(Java_BuildInfo_getPackageName(
+          env, GetApplicationContext()))),
+      java_exception_info_(NULL) {
+}
+
+// static
+BuildInfo* BuildInfo::GetInstance() {
+  return Singleton<BuildInfo, BuildInfoSingletonTraits >::get();
+}
+
+void BuildInfo::set_java_exception_info(const std::string& info) {
+  DCHECK(!java_exception_info_) << "info should be set only once.";
+  java_exception_info_ = strndup(info.c_str(), 1024);
+}
+
+// static
+bool BuildInfo::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/build_info.h b/base/android/build_info.h
new file mode 100644
index 0000000..65f45b5
--- /dev/null
+++ b/base/android/build_info.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 BASE_ANDROID_BUILD_INFO_H_
+#define BASE_ANDROID_BUILD_INFO_H_
+
+#include <jni.h>
+
+#include <string>
+
+#include "base/memory/singleton.h"
+
+namespace base {
+namespace android {
+
+// BuildInfo is a singleton class that stores android build and device
+// information. It will be called from Android specific code and gets used
+// primarily in crash reporting.
+
+// It is also used to store the last java exception seen during JNI.
+// TODO(nileshagrawal): Find a better place to store this info.
+class BuildInfo {
+ public:
+
+  ~BuildInfo() {}
+
+  // Static factory method for getting the singleton BuildInfo instance.
+  // Note that ownership is not conferred on the caller and the BuildInfo in
+  // question isn't actually freed until shutdown. This is ok because there
+  // should only be one instance of BuildInfo ever created.
+  static BuildInfo* GetInstance();
+
+  // Const char* is used instead of std::strings because these values must be
+  // available even if the process is in a crash state. Sadly
+  // std::string.c_str() doesn't guarantee that memory won't be allocated when
+  // it is called.
+  const char* device() const {
+    return device_;
+  }
+
+  const char* model() const {
+    return model_;
+  }
+
+  const char* brand() const {
+    return brand_;
+  }
+
+  const char* android_build_id() const {
+    return android_build_id_;
+  }
+
+  const char* android_build_fp() const {
+    return android_build_fp_;
+  }
+
+  const char* package_version_code() const {
+    return package_version_code_;
+  }
+
+  const char* package_version_name() const {
+    return package_version_name_;
+  }
+
+  const char* package_label() const {
+    return package_label_;
+  }
+
+  const char* package_name() const {
+    return package_name_;
+  }
+
+  const char* java_exception_info() const {
+    return java_exception_info_;
+  }
+
+  void set_java_exception_info(const std::string& info);
+
+  static bool RegisterBindings(JNIEnv* env);
+
+ private:
+  friend struct BuildInfoSingletonTraits;
+
+  explicit BuildInfo(JNIEnv* env);
+
+  // Const char* is used instead of std::strings because these values must be
+  // available even if the process is in a crash state. Sadly
+  // std::string.c_str() doesn't guarantee that memory won't be allocated when
+  // it is called.
+  const char* const device_;
+  const char* const model_;
+  const char* const brand_;
+  const char* const android_build_id_;
+  const char* const android_build_fp_;
+  const char* const package_version_code_;
+  const char* const package_version_name_;
+  const char* const package_label_;
+  const char* const package_name_;
+  // This is set via set_java_exception_info, not at constructor time.
+  const char* java_exception_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(BuildInfo);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_BUILD_INFO_H_
diff --git a/base/android/java/src/org/chromium/base/AccessedByNative.java b/base/android/java/src/org/chromium/base/AccessedByNative.java
new file mode 100644
index 0000000..8248cc6
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/AccessedByNative.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *  @AccessedByNative is used to ensure proguard will keep this field, since it's
+ *  only accessed by native.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AccessedByNative {
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/ActivityStatus.java b/base/android/java/src/org/chromium/base/ActivityStatus.java
new file mode 100644
index 0000000..765d841
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ActivityStatus.java
@@ -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.
+
+package org.chromium.base;
+
+import android.os.Looper;
+
+import java.util.ArrayList;
+
+/**
+ * Provides information about the parent activity's status.
+ */
+public class ActivityStatus {
+    public interface Listener {
+        /**
+         * Called when the activity's status changes.
+         * @param isPaused true if the activity is paused, false if not.
+         */
+        public void onActivityStatusChanged(boolean isPaused);
+    }
+
+    private boolean mIsPaused = false;
+    private ArrayList<Listener> mListeners = new ArrayList<Listener>();
+    private static ActivityStatus sActivityStatus;
+
+    private ActivityStatus() {
+    }
+
+    public static ActivityStatus getInstance() {
+        // Can only be called on the UI thread.
+        assert Looper.myLooper() == Looper.getMainLooper();
+        if (sActivityStatus == null) {
+            sActivityStatus = new ActivityStatus();
+        }
+        return sActivityStatus;
+    }
+
+    /**
+     * Indicates that the parent activity was paused.
+     */
+    public void onPause() {
+        mIsPaused = true;
+        informAllListeners();
+    }
+
+    /**
+     * Indicates that the parent activity was resumed.
+     */
+    public void onResume() {
+        mIsPaused = false;
+        informAllListeners();
+    }
+
+    /**
+     * Indicates that the parent activity is currently paused.
+     */
+    public boolean isPaused() {
+        return mIsPaused;
+    }
+
+    /**
+     * Registers the given listener to receive activity status updates.
+     * @param listener Listener to receive status updates.
+     */
+    public void registerListener(Listener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Unregisters the given listener from receiving activity status updates.
+     * @param listener Listener that doesn't want to receive status updates.
+     */
+    public void unregisterListener(Listener listener) {
+        mListeners.remove(listener);
+    }
+
+    private void informAllListeners() {
+        for (Listener listener : mListeners) {
+            listener.onActivityStatusChanged(mIsPaused);
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
new file mode 100644
index 0000000..1bd3fa2
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -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.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.util.Log;
+
+import org.chromium.base.CalledByNative;
+
+/**
+ * BuildInfo is a utility class providing easy access to {@link PackageInfo}
+ * information. This is primarly of use for accessesing package information
+ * from native code.
+ */
+public class BuildInfo {
+    private static final String TAG = "BuildInfo";
+    private static final int MAX_FINGERPRINT_LENGTH = 128;
+
+    /**
+     * BuildInfo is a static utility class and therefore shouldn't be
+     * instantiated.
+     */
+    private BuildInfo() {
+    }
+
+    @CalledByNative
+    public static String getDevice() {
+        return Build.DEVICE;
+    }
+
+    @CalledByNative
+    public static String getBrand() {
+        return Build.BRAND;
+    }
+
+    @CalledByNative
+    public static String getAndroidBuildId() {
+        return Build.ID;
+    }
+
+    /**
+     * @return The build fingerprint for the current Android install.  The value is truncated to a
+     *         128 characters as this is used for crash and UMA reporting, which should avoid huge
+     *         strings.
+     */
+    @CalledByNative
+    public static String getAndroidBuildFingerprint() {
+        return Build.FINGERPRINT.substring(
+                0, Math.min(Build.FINGERPRINT.length(), MAX_FINGERPRINT_LENGTH));
+    }
+
+    @CalledByNative
+    public static String getDeviceModel() {
+        return Build.MODEL;
+    }
+
+    @CalledByNative
+    public static String getPackageVersionCode(Context context) {
+        String msg = "versionCode not available.";
+        try {
+            PackageManager pm = context.getPackageManager();
+            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+            msg = "" + pi.versionCode;
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, msg);
+        }
+        return msg;
+
+    }
+
+    @CalledByNative
+    public static String getPackageVersionName(Context context) {
+        String msg = "versionName not available";
+        try {
+            PackageManager pm = context.getPackageManager();
+            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+            msg = pi.versionName;
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, msg);
+        }
+        return msg;
+    }
+
+    @CalledByNative
+    public static String getPackageLabel(Context context) {
+        try {
+            PackageManager packageManager = context.getPackageManager();
+            ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(),
+                    PackageManager.GET_META_DATA);
+            CharSequence label = packageManager.getApplicationLabel(appInfo);
+            return  label != null ? label.toString() : "";
+        } catch (NameNotFoundException e) {
+            return "";
+        }
+    }
+
+    @CalledByNative
+    public static String getPackageName(Context context) {
+        String packageName = context != null ? context.getPackageName() : null;
+        return packageName != null ? packageName : "";
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/CalledByNative.java b/base/android/java/src/org/chromium/base/CalledByNative.java
new file mode 100644
index 0000000..8d3dcad
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CalledByNative.java
@@ -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.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @CalledByNative is used by the JNI generator to create the necessary JNI
+ * bindings and expose this method to native code.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CalledByNative {
+    /*
+     *  If present, tells which inner class the method belongs to.
+     */
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java b/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java
new file mode 100644
index 0000000..cc264a2
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *  @CalledByNativeUnchecked is used to generate JNI bindings that do not check for exceptions.
+ *  It only makes sense to use this annotation on methods that declare a throws... spec.
+ *  However, note that the exception received native side maybe an 'unchecked' (RuntimeExpception)
+ *  such as NullPointerException, so the native code should differentiate these cases.
+ *  Usage of this should be very rare; where possible handle exceptions in the Java side and use a
+ *  return value to indicate success / failure.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CalledByNativeUnchecked {
+    /*
+     *  If present, tells which inner class the method belongs to.
+     */
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/JNINamespace.java b/base/android/java/src/org/chromium/base/JNINamespace.java
new file mode 100644
index 0000000..cfffc91
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JNINamespace.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @JNINamespace is used by the JNI generator to create the necessary JNI
+ * bindings and expose this method to native code using the specified namespace.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface JNINamespace {
+    public String value();
+}
diff --git a/base/android/java/src/org/chromium/base/LocaleUtils.java b/base/android/java/src/org/chromium/base/LocaleUtils.java
new file mode 100644
index 0000000..6bca1f7
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/LocaleUtils.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.util.Locale;
+
+/**
+ * This class provides the locale related methods for the native library.
+ */
+class LocaleUtils {
+
+    private LocaleUtils() { /* cannot be instantiated */ }
+
+    /**
+     * @return the default locale.
+     */
+    @CalledByNative
+    public static String getDefaultLocale() {
+        Locale locale = Locale.getDefault();
+        String language = locale.getLanguage();
+        String country = locale.getCountry();
+        return country.isEmpty() ? language : language + "-" + country;
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java b/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
new file mode 100644
index 0000000..309169b
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
@@ -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.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @NativeClassQualifiedName is used by the JNI generator to create the necessary JNI
+ * bindings to call into the specified native class name.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NativeClassQualifiedName {
+    /*
+     * Tells which native class the method is going to be bound to.
+     * The first parameter of the annotated method must be an int nativePtr pointing to
+     * an instance of this class.
+     */
+    public String value();
+}
diff --git a/base/android/java/src/org/chromium/base/PathService.java b/base/android/java/src/org/chromium/base/PathService.java
new file mode 100644
index 0000000..dfda736
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PathService.java
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * This class provides java side access to the native PathService.
+ */
+@JNINamespace("base::android")
+public abstract class PathService {
+
+    // Must match the value of DIR_MODULE in base/base_paths.h!
+    public static final int DIR_MODULE = 3;
+
+    // Prevent instantiation.
+    private PathService() {}
+
+    public static void override(int what, String path) {
+        nativeOverride(what, path);
+    }
+
+    private static native void nativeOverride(int what, String path);
+}
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
new file mode 100644
index 0000000..c3503a4
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -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.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Environment;
+
+/**
+ * This class provides the path related methods for the native library.
+ */
+public abstract class PathUtils {
+
+    private static String sDataDirectorySuffix;
+
+    // Prevent instantiation.
+    private PathUtils() {}
+
+    /**
+     * Sets the suffix that should be used for the directory where private data is to be stored
+     * by the application.
+     * @param suffix The private data directory suffix.
+     * @see Context#getDir(String, int)
+     */
+    public static void setPrivateDataDirectorySuffix(String suffix) {
+        sDataDirectorySuffix = suffix;
+    }
+
+    /**
+     * @return the private directory that is used to store application data.
+     */
+    @CalledByNative
+    public static String getDataDirectory(Context appContext) {
+        if (sDataDirectorySuffix == null) {
+            throw new IllegalStateException(
+                    "setDataDirectorySuffix must be called before getDataDirectory");
+        }
+        return appContext.getDir(sDataDirectorySuffix, Context.MODE_PRIVATE).getPath();
+    }
+
+    /**
+     * @return the cache directory.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static String getCacheDirectory(Context appContext) {
+        return appContext.getCacheDir().getPath();
+    }
+
+    /**
+     * @return the public downloads directory.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static String getDownloadsDirectory(Context appContext) {
+        return Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_DOWNLOADS).getPath();
+    }
+
+    /**
+     * @return the path to native libraries.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static String getNativeLibraryDirectory(Context appContext) {
+        ApplicationInfo ai = appContext.getApplicationInfo();
+        if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ||
+            (ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+            return ai.nativeLibraryDir;
+        }
+
+        return "/system/lib/";
+    }
+
+    /**
+     * @return the external storage directory.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    public static String getExternalStorageDirectory() {
+        return Environment.getExternalStorageDirectory().getAbsolutePath();
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/PowerStatusReceiver.java b/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
new file mode 100644
index 0000000..89594b8
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
@@ -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.
+
+package org.chromium.base;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+
+/**
+ * A BroadcastReceiver that listens to changes in power status and notifies
+ * SystemMonitor.
+ * It's instantiated by the framework via the application intent-filter
+ * declared in its manifest.
+ */
+public class PowerStatusReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        SystemMonitor.onBatteryChargingChanged(intent);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
new file mode 100644
index 0000000..f7bb19f
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
@@ -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.
+
+package org.chromium.base;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+class SystemMessageHandler extends Handler {
+
+    private static final int TIMER_MESSAGE = 1;
+    private static final int DELAYED_TIMER_MESSAGE = 2;
+
+    // Native class pointer set by the constructor of the SharedClient native class.
+    private int mMessagePumpDelegateNative = 0;
+
+    // Used to ensure we have at most one TIMER_MESSAGE pending at once.
+    private AtomicBoolean mTimerFired = new AtomicBoolean(true);
+
+    // Used to insert TIMER_MESSAGE on the front of the system message queue during startup only.
+    // This is a wee hack, to give a priority boost to native tasks during startup as they tend to
+    // be on the critical path. (After startup, handling the UI with minimum latency is more
+    // important).
+    private boolean mStartupComplete = false;
+    private final long mStartupCompleteTime = System.currentTimeMillis() + 2000;
+    private final boolean startupComplete() {
+        if (!mStartupComplete && System.currentTimeMillis() > mStartupCompleteTime) {
+            mStartupComplete = true;
+        }
+        return mStartupComplete;
+    }
+
+    private SystemMessageHandler(int messagePumpDelegateNative) {
+        mMessagePumpDelegateNative = messagePumpDelegateNative;
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        if (msg.what == TIMER_MESSAGE) {
+            mTimerFired.set(true);
+        }
+        while (nativeDoRunLoopOnce(mMessagePumpDelegateNative)) {
+            if (startupComplete()) {
+                setTimer();
+                break;
+            }
+        }
+    }
+
+    @CalledByNative
+    private void setTimer() {
+        if (!mTimerFired.getAndSet(false)) {
+            // mTimerFired was already false.
+            return;
+        }
+        if (startupComplete()) {
+            sendEmptyMessage(TIMER_MESSAGE);
+        } else {
+            sendMessageAtFrontOfQueue(obtainMessage(TIMER_MESSAGE));
+        }
+    }
+
+    // If millis <=0, it'll send a TIMER_MESSAGE instead of
+    // a DELAYED_TIMER_MESSAGE.
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private void setDelayedTimer(long millis) {
+        if (millis <= 0) {
+            setTimer();
+        } else {
+            removeMessages(DELAYED_TIMER_MESSAGE);
+            sendEmptyMessageDelayed(DELAYED_TIMER_MESSAGE, millis);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private void removeTimer() {
+        removeMessages(TIMER_MESSAGE);
+        removeMessages(DELAYED_TIMER_MESSAGE);
+    }
+
+    @CalledByNative
+    private static SystemMessageHandler create(int messagePumpDelegateNative) {
+        return new SystemMessageHandler(messagePumpDelegateNative);
+    }
+
+    private native boolean nativeDoRunLoopOnce(int messagePumpDelegateNative);
+}
diff --git a/base/android/java/src/org/chromium/base/SystemMonitor.java b/base/android/java/src/org/chromium/base/SystemMonitor.java
new file mode 100644
index 0000000..f43f115
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/SystemMonitor.java
@@ -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.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.Looper;
+
+
+/**
+ * Integrates native SystemMonitor with the java side.
+ */
+@JNINamespace("base::android")
+public class SystemMonitor {
+    private static SystemMonitor sInstance;
+
+    private boolean mIsBatteryPower;
+
+    public static void createForTests(Context context) {
+        // Applications will create this once the
+        // JNI side has been fully wired up both sides.
+        // For tests, we just need native -> java, that is,
+        // we don't need to notify java -> native on creation.
+        sInstance = new SystemMonitor();
+    }
+
+    public static void create(Context context) {
+        if (sInstance == null) {
+            sInstance = new SystemMonitor();
+            IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+            Intent batteryStatusIntent = context.registerReceiver(null, ifilter);
+            onBatteryChargingChanged(batteryStatusIntent);
+        }
+    }
+
+    private SystemMonitor() {
+    }
+
+    public static void onBatteryChargingChanged(Intent intent) {
+        if (sInstance == null) {
+            // We may be called by the framework intent-filter before being
+            // fully initialized. This is not a problem, since our constructor
+            // will check for the state later on.
+            return;
+        }
+        int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+        // If we're not plugged, assume we're running on battery power.
+        sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB &&
+                                    chargePlug != BatteryManager.BATTERY_PLUGGED_AC;
+        nativeOnBatteryChargingChanged();
+    }
+
+    @CalledByNative
+    private static boolean isBatteryPower() {
+        return sInstance.mIsBatteryPower;
+    }
+
+    private static native void nativeOnBatteryChargingChanged();
+
+}
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
new file mode 100644
index 0000000..b827a0b
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -0,0 +1,142 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+/**
+ * Helper methods to deal with threading related tasks.
+ */
+public class ThreadUtils {
+
+    /**
+     * Run the supplied Runnable on the main thread. The method will block until
+     * the Runnable completes.
+     *
+     * @param r The Runnable to run.
+     */
+    public static void runOnUiThreadBlocking(final Runnable r) {
+        if (runningOnUiThread()) {
+            r.run();
+        } else {
+            FutureTask<Void> task = new FutureTask<Void>(r, null);
+            postOnUiThread(task);
+            try {
+                task.get();
+            } catch (Exception e) {
+                throw new RuntimeException("Exception occured while waiting for runnable", e);
+            }
+        }
+    }
+
+    /**
+     * Run the supplied Callable on the main thread, wrapping any exceptions in
+     * a RuntimeException. The method will block until the Callable completes.
+     *
+     * @param c The Callable to run
+     * @return The result of the callable
+     */
+    public static <T> T runOnUiThreadBlockingNoException(Callable<T> c) {
+        try {
+            return runOnUiThreadBlocking(c);
+        } catch (ExecutionException e) {
+            throw new RuntimeException("Error occured waiting for callable", e);
+        }
+    }
+
+    /**
+     * Run the supplied Callable on the main thread, The method will block until
+     * the Callable completes.
+     *
+     * @param c The Callable to run
+     * @return The result of the callable
+     * @throws ExecutionException c's exception
+     */
+    public static <T> T runOnUiThreadBlocking(Callable<T> c) throws ExecutionException {
+        FutureTask<T> task = new FutureTask<T>(c);
+        runOnUiThread(task);
+        try {
+            return task.get();
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Interrupted waiting for callable", e);
+        }
+    }
+
+    /**
+     * Run the supplied FutureTask on the main thread. The method will block
+     * only if the current thread is the main thread.
+     *
+     * @param task The FutureTask to run
+     * @return The queried task (to aid inline construction)
+     */
+    public static <T> FutureTask<T> runOnUiThread(FutureTask<T> task) {
+        if (runningOnUiThread()) {
+            task.run();
+        } else {
+            postOnUiThread(task);
+        }
+        return task;
+    }
+
+    /**
+     * Run the supplied Callable on the main thread. The method will block
+     * only if the current thread is the main thread.
+     *
+     * @param c The Callable to run
+     * @return A FutureTask wrapping the callable to retrieve results
+     */
+    public static <T> FutureTask<T> runOnUiThread(Callable<T> c) {
+        return runOnUiThread(new FutureTask<T>(c));
+    }
+
+    /**
+     * Run the supplied Runnable on the main thread. The method will block
+     * only if the current thread is the main thread.
+     *
+     * @param r The Runnable to run
+     */
+    public static void runOnUiThread(Runnable r) {
+        if (runningOnUiThread()) {
+            r.run();
+        } else {
+            LazyHolder.sUiThreadHandler.post(r);
+        }
+    }
+
+    /**
+     * Post the supplied FutureTask to run on the main thread. The method will
+     * not block, even if called on the UI thread.
+     *
+     * @param task The FutureTask to run
+     * @return The queried task (to aid inline construction)
+     */
+    public static <T> FutureTask<T> postOnUiThread(FutureTask<T> task) {
+        LazyHolder.sUiThreadHandler.post(task);
+        return task;
+    }
+
+    /**
+     * Asserts that the current thread is running on the main thread.
+     */
+    public static void assertOnUiThread() {
+        assert runningOnUiThread();
+    }
+
+    /**
+     * @return true iff the current thread is the main (UI) thread.
+     */
+    public static boolean runningOnUiThread() {
+      return Looper.getMainLooper() == Looper.myLooper();
+    }
+
+    private static class LazyHolder {
+        private static Handler sUiThreadHandler = new Handler(Looper.getMainLooper());
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/WeakContext.java b/base/android/java/src/org/chromium/base/WeakContext.java
new file mode 100644
index 0000000..d660cc9
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/WeakContext.java
@@ -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.
+
+package org.chromium.base;
+
+import android.content.Context;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.Callable;
+
+// Holds a WeakReference to Context to allow it to be GC'd.
+// Also provides utility functions to getSystemService from the UI or any
+// other thread (may return null, if the Context has been nullified).
+public class WeakContext {
+    private static WeakReference<Context> sWeakContext;
+
+    public static void initializeWeakContext(final Context context) {
+        sWeakContext = new WeakReference<Context>(context);
+    }
+
+    public static Context getContext() {
+        return sWeakContext.get();
+    }
+
+    // Returns a system service. May be called from any thread.
+    // If necessary, it will send a message to the main thread to acquire the
+    // service, and block waiting for it to complete.
+    // May return null if context is no longer available.
+    public static Object getSystemService(final String name) {
+        final Context context = sWeakContext.get();
+        if (context == null) {
+            return null;
+        }
+        if (ThreadUtils.runningOnUiThread()) {
+            return context.getSystemService(name);
+        }
+        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Object>() {
+          @Override
+          public Object call() {
+            return context.getSystemService(name);
+          }
+        });
+    }
+}
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
new file mode 100644
index 0000000..fdc2170
--- /dev/null
+++ b/base/android/jni_android.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/android/jni_android.h"
+
+#include <map>
+
+#include "base/android/build_info.h"
+#include "base/android/jni_string.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace {
+using base::android::GetClass;
+using base::android::MethodID;
+using base::android::ScopedJavaLocalRef;
+
+struct MethodIdentifier {
+  const char* class_name;
+  const char* method;
+  const char* jni_signature;
+
+  bool operator<(const MethodIdentifier& other) const {
+    int r = strcmp(class_name, other.class_name);
+    if (r < 0) {
+      return true;
+    } else if (r > 0) {
+      return false;
+    }
+
+    r = strcmp(method, other.method);
+    if (r < 0) {
+      return true;
+    } else if (r > 0) {
+      return false;
+    }
+
+    return strcmp(jni_signature, other.jni_signature) < 0;
+  }
+};
+
+typedef std::map<MethodIdentifier, jmethodID> MethodIDMap;
+
+const base::subtle::AtomicWord kUnlocked = 0;
+const base::subtle::AtomicWord kLocked = 1;
+base::subtle::AtomicWord g_method_id_map_lock = kUnlocked;
+JavaVM* g_jvm = NULL;
+// Leak the global app context, as it is used from a non-joinable worker thread
+// that may still be running at shutdown. There is no harm in doing this.
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
+    g_application_context = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<MethodIDMap> g_method_id_map = LAZY_INSTANCE_INITIALIZER;
+
+std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
+  ScopedJavaLocalRef<jclass> throwable_clazz =
+      GetClass(env, "java/lang/Throwable");
+  jmethodID throwable_printstacktrace =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, throwable_clazz.obj(), "printStackTrace",
+          "(Ljava/io/PrintStream;)V");
+
+  // Create an instance of ByteArrayOutputStream.
+  ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz =
+      GetClass(env, "java/io/ByteArrayOutputStream");
+  jmethodID bytearray_output_stream_constructor =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, bytearray_output_stream_clazz.obj(), "<init>", "()V");
+  jmethodID bytearray_output_stream_tostring =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, bytearray_output_stream_clazz.obj(), "toString",
+          "()Ljava/lang/String;");
+  ScopedJavaLocalRef<jobject> bytearray_output_stream(env,
+      env->NewObject(bytearray_output_stream_clazz.obj(),
+                     bytearray_output_stream_constructor));
+
+  // Create an instance of PrintStream.
+  ScopedJavaLocalRef<jclass> printstream_clazz =
+      GetClass(env, "java/io/PrintStream");
+  jmethodID printstream_constructor =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, printstream_clazz.obj(), "<init>",
+          "(Ljava/io/OutputStream;)V");
+  ScopedJavaLocalRef<jobject> printstream(env,
+      env->NewObject(printstream_clazz.obj(), printstream_constructor,
+                     bytearray_output_stream.obj()));
+
+  // Call Throwable.printStackTrace(PrintStream)
+  env->CallVoidMethod(java_throwable, throwable_printstacktrace,
+      printstream.obj());
+
+  // Call ByteArrayOutputStream.toString()
+  ScopedJavaLocalRef<jstring> exception_string(
+      env, static_cast<jstring>(
+          env->CallObjectMethod(bytearray_output_stream.obj(),
+                                bytearray_output_stream_tostring)));
+
+  return ConvertJavaStringToUTF8(exception_string);
+}
+
+}  // namespace
+
+namespace base {
+namespace android {
+
+JNIEnv* AttachCurrentThread() {
+  DCHECK(g_jvm);
+  JNIEnv* env = NULL;
+  jint ret = g_jvm->AttachCurrentThread(&env, NULL);
+  DCHECK_EQ(JNI_OK, ret);
+  return env;
+}
+
+void DetachFromVM() {
+  // Ignore the return value, if the thread is not attached, DetachCurrentThread
+  // will fail. But it is ok as the native thread may never be attached.
+  if (g_jvm)
+    g_jvm->DetachCurrentThread();
+}
+
+void InitVM(JavaVM* vm) {
+  DCHECK(!g_jvm);
+  g_jvm = vm;
+}
+
+void InitApplicationContext(const JavaRef<jobject>& context) {
+  DCHECK(g_application_context.Get().is_null());
+  g_application_context.Get().Reset(context);
+}
+
+const jobject GetApplicationContext() {
+  DCHECK(!g_application_context.Get().is_null());
+  return g_application_context.Get().obj();
+}
+
+ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) {
+  return ScopedJavaLocalRef<jclass>(env, GetUnscopedClass(env, class_name));
+}
+
+jclass GetUnscopedClass(JNIEnv* env, const char* class_name) {
+  jclass clazz = env->FindClass(class_name);
+  CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name;
+  return clazz;
+}
+
+bool HasClass(JNIEnv* env, const char* class_name) {
+  ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name));
+  if (!clazz.obj()) {
+    ClearException(env);
+    return false;
+  }
+  bool error = ClearException(env);
+  DCHECK(!error);
+  return true;
+}
+
+template<MethodID::Type type>
+jmethodID MethodID::Get(JNIEnv* env,
+                        jclass clazz,
+                        const char* method_name,
+                        const char* jni_signature) {
+  jmethodID id = type == TYPE_STATIC ?
+      env->GetStaticMethodID(clazz, method_name, jni_signature) :
+      env->GetMethodID(clazz, method_name, jni_signature);
+  CHECK(base::android::ClearException(env) || id) <<
+      "Failed to find " <<
+      (type == TYPE_STATIC ? "static " : "") <<
+      "method " << method_name << " " << jni_signature;
+  return id;
+}
+
+// If |atomic_method_id| set, it'll return immediately. Otherwise, it'll call
+// into ::Get() above. If there's a race, it's ok since the values are the same
+// (and the duplicated effort will happen only once).
+template<MethodID::Type type>
+jmethodID MethodID::LazyGet(JNIEnv* env,
+                            jclass clazz,
+                            const char* method_name,
+                            const char* jni_signature,
+                            base::subtle::AtomicWord* atomic_method_id) {
+  COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jmethodID),
+                 AtomicWord_SmallerThan_jMethodID);
+  subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id);
+  if (value)
+    return reinterpret_cast<jmethodID>(value);
+  jmethodID id = MethodID::Get<type>(env, clazz, method_name, jni_signature);
+  base::subtle::Release_Store(
+      atomic_method_id, reinterpret_cast<subtle::AtomicWord>(id));
+  return id;
+}
+
+// Various template instantiations.
+template jmethodID MethodID::Get<MethodID::TYPE_STATIC>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature);
+
+template jmethodID MethodID::Get<MethodID::TYPE_INSTANCE>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature);
+
+template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
+
+template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
+
+jfieldID GetFieldID(JNIEnv* env,
+                    const JavaRef<jclass>& clazz,
+                    const char* field_name,
+                    const char* jni_signature) {
+  jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature);
+  CHECK(!ClearException(env) && field_id) << "Failed to find field " <<
+      field_name << " " << jni_signature;
+  return field_id;
+}
+
+bool HasField(JNIEnv* env,
+              const JavaRef<jclass>& clazz,
+              const char* field_name,
+              const char* jni_signature) {
+  jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature);
+  if (!field_id) {
+    ClearException(env);
+    return false;
+  }
+  bool error = ClearException(env);
+  DCHECK(!error);
+  return true;
+}
+
+jfieldID GetStaticFieldID(JNIEnv* env,
+                          const JavaRef<jclass>& clazz,
+                          const char* field_name,
+                          const char* jni_signature) {
+  jfieldID field_id =
+      env->GetStaticFieldID(clazz.obj(), field_name, jni_signature);
+  CHECK(!ClearException(env) && field_id) << "Failed to find static field " <<
+      field_name << " " << jni_signature;
+  return field_id;
+}
+
+jmethodID GetMethodIDFromClassName(JNIEnv* env,
+                                   const char* class_name,
+                                   const char* method,
+                                   const char* jni_signature) {
+  MethodIdentifier key;
+  key.class_name = class_name;
+  key.method = method;
+  key.jni_signature = jni_signature;
+
+  MethodIDMap* map = g_method_id_map.Pointer();
+  bool found = false;
+
+  while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock,
+                                              kUnlocked,
+                                              kLocked) != kUnlocked) {
+    base::PlatformThread::YieldCurrentThread();
+  }
+  MethodIDMap::const_iterator iter = map->find(key);
+  if (iter != map->end()) {
+    found = true;
+  }
+  base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked);
+
+  // Addition to the map does not invalidate this iterator.
+  if (found) {
+    return iter->second;
+  }
+
+  ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name));
+  jmethodID id = MethodID::Get<MethodID::TYPE_INSTANCE>(
+      env, clazz.obj(), method, jni_signature);
+
+  while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock,
+                                              kUnlocked,
+                                              kLocked) != kUnlocked) {
+    base::PlatformThread::YieldCurrentThread();
+  }
+  // Another thread may have populated the map already.
+  std::pair<MethodIDMap::const_iterator, bool> result =
+      map->insert(std::make_pair(key, id));
+  DCHECK_EQ(id, result.first->second);
+  base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked);
+
+  return id;
+}
+
+bool HasException(JNIEnv* env) {
+  return env->ExceptionCheck() != JNI_FALSE;
+}
+
+bool ClearException(JNIEnv* env) {
+  if (!HasException(env))
+    return false;
+  env->ExceptionDescribe();
+  env->ExceptionClear();
+  return true;
+}
+
+void CheckException(JNIEnv* env) {
+  if (!HasException(env)) return;
+
+  // Exception has been found, might as well tell breakpad about it.
+  jthrowable java_throwable = env->ExceptionOccurred();
+  if (!java_throwable) {
+    // Do nothing but return false.
+    CHECK(false);
+  }
+
+  // Clear the pending exception, since a local reference is now held.
+  env->ExceptionDescribe();
+  env->ExceptionClear();
+
+  // Set the exception_string in BuildInfo so that breakpad can read it.
+  // RVO should avoid any extra copies of the exception string.
+  base::android::BuildInfo::GetInstance()->set_java_exception_info(
+      GetJavaExceptionInfo(env, java_throwable));
+
+  // Now, feel good about it and die.
+  CHECK(false);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_android.h b/base/android/jni_android.h
new file mode 100644
index 0000000..16b85af
--- /dev/null
+++ b/base/android/jni_android.h
@@ -0,0 +1,137 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_ANDROID_H_
+#define BASE_ANDROID_JNI_ANDROID_H_
+
+#include <jni.h>
+#include <sys/types.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace android {
+
+// Used to mark symbols to be exported in a shared library's symbol table.
+#define JNI_EXPORT __attribute__ ((visibility("default")))
+
+// Contains the registration method information for initializing JNI bindings.
+struct RegistrationMethod {
+  const char* name;
+  bool (*func)(JNIEnv* env);
+};
+
+// Attach the current thread to the VM (if necessary) and return the JNIEnv*.
+BASE_EXPORT JNIEnv* AttachCurrentThread();
+
+// Detach the current thread from VM if it is attached.
+BASE_EXPORT void DetachFromVM();
+
+// Initializes the global JVM. It is not necessarily called before
+// InitApplicationContext().
+BASE_EXPORT void InitVM(JavaVM* vm);
+
+// Initializes the global application context object. The |context| can be any
+// valid reference to the application context. Internally holds a global ref to
+// the context. InitVM and InitApplicationContext maybe called in either order.
+BASE_EXPORT void InitApplicationContext(const JavaRef<jobject>& context);
+
+// Gets a global ref to the application context set with
+// InitApplicationContext(). Ownership is retained by the function - the caller
+// must NOT release it.
+const BASE_EXPORT jobject GetApplicationContext();
+
+// Finds the class named |class_name| and returns it.
+// Use this method instead of invoking directly the JNI FindClass method (to
+// prevent leaking local references).
+// This method triggers a fatal assertion if the class could not be found.
+// Use HasClass if you need to check whether the class exists.
+BASE_EXPORT ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env,
+                                                const char* class_name);
+
+// Similar to the above, but the caller is responsible to manage the jclass
+// lifetime.
+BASE_EXPORT jclass GetUnscopedClass(JNIEnv* env,
+                                    const char* class_name) WARN_UNUSED_RESULT;
+
+// Returns true iff the class |class_name| could be found.
+BASE_EXPORT bool HasClass(JNIEnv* env, const char* class_name);
+
+// This class is a wrapper for JNIEnv Get(Static)MethodID.
+class BASE_EXPORT MethodID {
+ public:
+  enum Type {
+    TYPE_STATIC,
+    TYPE_INSTANCE,
+  };
+
+  // Returns the method ID for the method with the specified name and signature.
+  // This method triggers a fatal assertion if the method could not be found.
+  template<Type type>
+  static jmethodID Get(JNIEnv* env,
+                       jclass clazz,
+                       const char* method_name,
+                       const char* jni_signature);
+
+  // The caller is responsible to zero-initialize |atomic_method_id|.
+  // It's fine to simultaneously call this on multiple threads referencing the
+  // same |atomic_method_id|.
+  template<Type type>
+  static jmethodID LazyGet(JNIEnv* env,
+                           jclass clazz,
+                           const char* method_name,
+                           const char* jni_signature,
+                           base::subtle::AtomicWord* atomic_method_id);
+};
+
+// Gets the method ID from the class name. Clears the pending Java exception
+// and returns NULL if the method is not found. Caches results. Note that
+// MethodID::Get() above avoids a class lookup, but does not cache results.
+// Strings passed to this function are held in the cache and MUST remain valid
+// beyond the duration of all future calls to this function, across all
+// threads. In practice, this means that the function should only be used with
+// string constants.
+BASE_EXPORT jmethodID GetMethodIDFromClassName(JNIEnv* env,
+                                               const char* class_name,
+                                               const char* method,
+                                               const char* jni_signature);
+
+// Gets the field ID for a class field.
+// This method triggers a fatal assertion if the field could not be found.
+BASE_EXPORT jfieldID GetFieldID(JNIEnv* env,
+                                const JavaRef<jclass>& clazz,
+                                const char* field_name,
+                                const char* jni_signature);
+
+// Returns true if |clazz| as a field with the given name and signature.
+// TODO(jcivelli): Determine whether we explicitly have to pass the environment.
+BASE_EXPORT bool HasField(JNIEnv* env,
+                          const JavaRef<jclass>& clazz,
+                          const char* field_name,
+                          const char* jni_signature);
+
+// Gets the field ID for a static class field.
+// This method triggers a fatal assertion if the field could not be found.
+BASE_EXPORT jfieldID GetStaticFieldID(JNIEnv* env,
+                                      const JavaRef<jclass>& clazz,
+                                      const char* field_name,
+                                      const char* jni_signature);
+
+// Returns true if an exception is pending in the provided JNIEnv*.
+BASE_EXPORT bool HasException(JNIEnv* env);
+
+// If an exception is pending in the provided JNIEnv*, this function clears it
+// and returns true.
+BASE_EXPORT bool ClearException(JNIEnv* env);
+
+// This function will call CHECK() macro if there's any pending exception.
+BASE_EXPORT void CheckException(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_ANDROID_H_
diff --git a/base/android/jni_android_unittest.cc b/base/android/jni_android_unittest.cc
new file mode 100644
index 0000000..920b395
--- /dev/null
+++ b/base/android/jni_android_unittest.cc
@@ -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.
+
+#include "base/android/jni_android.h"
+
+#include "base/at_exit.h"
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+const char kJavaLangObject[] = "java/lang/Object";
+const char kGetClass[] = "getClass";
+const char kToString[] = "toString";
+const char kReturningJavaLangClass[] = "()Ljava/lang/Class;";
+const char kReturningJavaLangString[] = "()Ljava/lang/String;";
+
+const char* g_last_method;
+const char* g_last_jni_signature;
+jmethodID g_last_method_id;
+
+const JNINativeInterface* g_previous_functions;
+
+jmethodID GetMethodIDWrapper(JNIEnv* env, jclass clazz, const char* method,
+                             const char* jni_signature) {
+  g_last_method = method;
+  g_last_jni_signature = jni_signature;
+  g_last_method_id = g_previous_functions->GetMethodID(env, clazz, method,
+                                                       jni_signature);
+  return g_last_method_id;
+}
+
+}  // namespace
+
+class JNIAndroidTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    JNIEnv* env = AttachCurrentThread();
+    g_previous_functions = env->functions;
+    hooked_functions = *g_previous_functions;
+    env->functions = &hooked_functions;
+    hooked_functions.GetMethodID = &GetMethodIDWrapper;
+  }
+
+  virtual void TearDown() {
+    JNIEnv* env = AttachCurrentThread();
+    env->functions = g_previous_functions;
+    Reset();
+  }
+
+  void Reset() {
+    g_last_method = 0;
+    g_last_jni_signature = 0;
+    g_last_method_id = NULL;
+  }
+  // Needed to cleanup the cached method map in the implementation between
+  // runs (e.g. if using --gtest_repeat)
+  base::ShadowingAtExitManager exit_manager;
+  // From JellyBean release, the instance of this struct provided in JNIEnv is
+  // read-only, so we deep copy it to allow individual functions to be hooked.
+  JNINativeInterface hooked_functions;
+};
+
+TEST_F(JNIAndroidTest, GetMethodIDFromClassNameCaching) {
+  JNIEnv* env = AttachCurrentThread();
+
+  Reset();
+  jmethodID id1 = GetMethodIDFromClassName(env, kJavaLangObject, kGetClass,
+                                           kReturningJavaLangClass);
+  EXPECT_STREQ(kGetClass, g_last_method);
+  EXPECT_STREQ(kReturningJavaLangClass, g_last_jni_signature);
+  EXPECT_EQ(g_last_method_id, id1);
+
+  Reset();
+  jmethodID id2 = GetMethodIDFromClassName(env, kJavaLangObject, kGetClass,
+                                           kReturningJavaLangClass);
+  EXPECT_STREQ(0, g_last_method);
+  EXPECT_STREQ(0, g_last_jni_signature);
+  EXPECT_EQ(NULL, g_last_method_id);
+  EXPECT_EQ(id1, id2);
+
+  Reset();
+  jmethodID id3 = GetMethodIDFromClassName(env, kJavaLangObject, kToString,
+                                           kReturningJavaLangString);
+  EXPECT_STREQ(kToString, g_last_method);
+  EXPECT_STREQ(kReturningJavaLangString, g_last_jni_signature);
+  EXPECT_EQ(g_last_method_id, id3);
+}
+
+namespace {
+
+base::subtle::AtomicWord g_atomic_id = 0;
+int LazyMethodIDCall(JNIEnv* env, jclass clazz, int p) {
+  jmethodID id = base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, clazz,
+      "abs",
+      "(I)I",
+      &g_atomic_id);
+
+  return env->CallStaticIntMethod(clazz, id, p);
+}
+
+int MethodIDCall(JNIEnv* env, jclass clazz, jmethodID id, int p) {
+  return env->CallStaticIntMethod(clazz, id, p);
+}
+
+}  // namespace
+
+TEST(JNIAndroidMicrobenchmark, MethodId) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jclass> clazz(GetClass(env, "java/lang/Math"));
+  base::Time start_lazy = base::Time::Now();
+  int o = 0;
+  for (int i = 0; i < 1024; ++i)
+    o += LazyMethodIDCall(env, clazz.obj(), i);
+  base::Time end_lazy = base::Time::Now();
+
+  jmethodID id = reinterpret_cast<jmethodID>(g_atomic_id);
+  base::Time start = base::Time::Now();
+  for (int i = 0; i < 1024; ++i)
+    o += MethodIDCall(env, clazz.obj(), id, i);
+  base::Time end = base::Time::Now();
+
+  // On a Galaxy Nexus, results were in the range of:
+  // JNI LazyMethodIDCall (us) 1984
+  // JNI MethodIDCall (us) 1861
+  LOG(ERROR) << "JNI LazyMethodIDCall (us) " <<
+      base::TimeDelta(end_lazy - start_lazy).InMicroseconds();
+  LOG(ERROR) << "JNI MethodIDCall (us) " <<
+      base::TimeDelta(end - start).InMicroseconds();
+  LOG(ERROR) << "JNI " << o;
+}
+
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
new file mode 100644
index 0000000..53027c7
--- /dev/null
+++ b/base/android/jni_array.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_array.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/logging.h"
+
+namespace base {
+namespace android {
+
+ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+    JNIEnv* env, const uint8* bytes, size_t len) {
+  jbyteArray byte_array = env->NewByteArray(len);
+  CheckException(env);
+  DCHECK(byte_array);
+
+  jbyte* elements = env->GetByteArrayElements(byte_array, NULL);
+  memcpy(elements, bytes, len);
+  env->ReleaseByteArrayElements(byte_array, elements, 0);
+  CheckException(env);
+
+  return ScopedJavaLocalRef<jbyteArray>(env, byte_array);
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
+    JNIEnv* env, const std::vector<std::string>& v) {
+  ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
+  jobjectArray joa = env->NewObjectArray(v.size(),
+                                         byte_array_clazz.obj(), NULL);
+  CheckException(env);
+
+  for (size_t i = 0; i < v.size(); ++i) {
+    ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(env,
+        reinterpret_cast<const uint8*>(v[i].data()), v[i].length());
+    env->SetObjectArrayElement(joa, i, byte_array.obj());
+  }
+  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env, const std::vector<std::string>& v) {
+  ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
+  jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
+  CheckException(env);
+
+  for (size_t i = 0; i < v.size(); ++i) {
+    ScopedJavaLocalRef<jstring> item = ConvertUTF8ToJavaString(env, v[i]);
+    env->SetObjectArrayElement(joa, i, item.obj());
+  }
+  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env, const std::vector<string16>& v) {
+  ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
+  jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
+  CheckException(env);
+
+  for (size_t i = 0; i < v.size(); ++i) {
+    ScopedJavaLocalRef<jstring> item = ConvertUTF16ToJavaString(env, v[i]);
+    env->SetObjectArrayElement(joa, i, item.obj());
+  }
+  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+void AppendJavaStringArrayToStringVector(JNIEnv* env,
+                                         jobjectArray array,
+                                         std::vector<string16>* out) {
+  DCHECK(out);
+  if (!array)
+    return;
+  jsize len = env->GetArrayLength(array);
+  for (jsize i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jstring> str(env,
+        static_cast<jstring>(env->GetObjectArrayElement(array, i)));
+    out->push_back(ConvertJavaStringToUTF16(str));
+  }
+}
+
+void AppendJavaStringArrayToStringVector(JNIEnv* env,
+                                         jobjectArray array,
+                                         std::vector<std::string>* out) {
+  DCHECK(out);
+  if (!array)
+    return;
+  jsize len = env->GetArrayLength(array);
+  for (jsize i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jstring> str(env,
+        static_cast<jstring>(env->GetObjectArrayElement(array, i)));
+    out->push_back(ConvertJavaStringToUTF8(str));
+  }
+}
+
+void AppendJavaByteArrayToByteVector(JNIEnv* env,
+                                     jbyteArray byte_array,
+                                     std::vector<uint8>* out) {
+  DCHECK(out);
+  if (!byte_array)
+    return;
+  jsize len = env->GetArrayLength(byte_array);
+  jbyte* bytes = env->GetByteArrayElements(byte_array, NULL);
+  out->insert(out->end(), bytes, bytes + len);
+  env->ReleaseByteArrayElements(byte_array, bytes, JNI_ABORT);
+}
+
+void JavaByteArrayToByteVector(JNIEnv* env,
+                               jbyteArray byte_array,
+                               std::vector<uint8>* out) {
+  DCHECK(out);
+  out->clear();
+  AppendJavaByteArrayToByteVector(env, byte_array, out);
+}
+
+void JavaIntArrayToIntVector(JNIEnv* env,
+                             jintArray array,
+                             std::vector<int>* out) {
+  DCHECK(out);
+  out->clear();
+  jsize len = env->GetArrayLength(array);
+  jint* ints = env->GetIntArrayElements(array, NULL);
+  for (jsize i = 0; i < len; ++i) {
+    out->push_back(static_cast<int>(ints[i]));
+  }
+  env->ReleaseIntArrayElements(array, ints, JNI_ABORT);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_array.h b/base/android/jni_array.h
new file mode 100644
index 0000000..86433a3
--- /dev/null
+++ b/base/android/jni_array.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_ARRAY_H_
+#define BASE_ANDROID_JNI_ARRAY_H_
+
+#include <jni.h>
+#include <string>
+#include <vector>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+namespace base {
+namespace android {
+
+// Returns a new Java byte array converted from the given bytes array.
+BASE_EXPORT ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+    JNIEnv* env, const uint8* bytes, size_t len);
+
+// Returns a array of Java byte array converted from |v|.
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
+    JNIEnv* env, const std::vector<std::string>& v);
+
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env,  const std::vector<std::string>& v);
+
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env,  const std::vector<string16>& v);
+
+// Converts a Java string array to a native array.
+BASE_EXPORT void AppendJavaStringArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<string16>* out);
+
+BASE_EXPORT void AppendJavaStringArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::string>* out);
+
+// Appends the Java bytes in |bytes_array| onto the end of |out|.
+BASE_EXPORT void AppendJavaByteArrayToByteVector(
+    JNIEnv* env,
+    jbyteArray byte_array,
+    std::vector<uint8>* out);
+
+// Replaces the content of |out| with the Java bytes in |bytes_array|.
+BASE_EXPORT void JavaByteArrayToByteVector(
+    JNIEnv* env,
+    jbyteArray byte_array,
+    std::vector<uint8>* out);
+
+// Replaces the content of |out| with the Java ints in |int_array|.
+BASE_EXPORT void JavaIntArrayToIntVector(
+    JNIEnv* env,
+    jintArray int_array,
+    std::vector<int>* out);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_ARRAY_H_
diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc
new file mode 100644
index 0000000..7529335
--- /dev/null
+++ b/base/android/jni_array_unittest.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/android/jni_array.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(JniArray, BasicConversions) {
+  const uint8 kBytes[] = { 0, 1, 2, 3 };
+  const size_t kLen = arraysize(kBytes);
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jbyteArray> bytes = ToJavaByteArray(env, kBytes, kLen);
+  ASSERT_TRUE(bytes.obj());
+
+  std::vector<uint8> vec(5);
+  JavaByteArrayToByteVector(env, bytes.obj(), &vec);
+  EXPECT_EQ(4U, vec.size());
+  EXPECT_EQ(std::vector<uint8>(kBytes, kBytes + kLen), vec);
+
+  AppendJavaByteArrayToByteVector(env, bytes.obj(), &vec);
+  EXPECT_EQ(8U, vec.size());
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_generator/SampleForTests.java b/base/android/jni_generator/SampleForTests.java
new file mode 100644
index 0000000..341f0ea
--- /dev/null
+++ b/base/android/jni_generator/SampleForTests.java
@@ -0,0 +1,171 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.example.jni_generator;
+
+import android.graphics.Rect;
+
+// This class serves as a reference test for the bindings generator, and as example documentation
+// for how to use the jni generator.
+// The C++ counter-part is sample_for_tests.cc.
+// jni_generator.gyp has a jni_generator_tests target that will:
+//   * Generate a header file for the JNI bindings based on this file.
+//   * Compile sample_for_tests.cc using the generated header file.
+//   * link a native executable to prove the generated header + cc file are self-contained.
+// All comments are informational only, and are ignored by the jni generator.
+//
+// This JNINamespace annotation indicates that all native methods should be
+// generated inside this namespace, including the native class that this
+// object binds to.
+@JNINamespace("base::android")
+class SampleForTests {
+  // Classes can store their C++ pointer counter part as an int that is normally initialized by
+  // calling out a nativeInit() function.
+  int nativePtr;
+
+  // You can define methods and attributes on the java class just like any other.
+  // Methods without the @CalledByNative annotation won't be exposed to JNI.
+  public SampleForTests() {
+  }
+
+  public void startExample() {
+      // Calls native code and holds a pointer to the C++ class.
+      nativePtr = nativeInit("myParam");
+  }
+
+  public void doStuff() {
+      // This will call CPPClass::Method() using nativePtr as a pointer to the object. This must be
+      // done to:
+      // * avoid leaks.
+      // * using finalizers are not allowed to destroy the cpp class.
+      nativeMethod(nativePtr);
+  }
+
+  public void finishExample() {
+      // We're done, so let's destroy nativePtr object.
+      nativeDestroy(nativePtr);
+  }
+
+  // -----------------------------------------------------------------------------------------------
+  // The following methods demonstrate exporting Java methods for invocation from C++ code.
+  // Java functions are mapping into C global functions by prefixing the method name with
+  // "Java_<Class>_"
+  // This is triggered by the @CalledByNative annotation; the methods may be named as you wish.
+
+  // Exported to C++ as:
+  //   Java_Example_javaMethod(JNIEnv* env, jobject obj, jint foo, jint bar)
+  // Typically the C++ code would have obtained the jobject via the Init() call described above.
+  @CalledByNative
+  public int javaMethod(int foo,
+                        int bar) {
+      return 0;
+  }
+
+  // Exported to C++ as Java_Example_staticJavaMethod(JNIEnv* env)
+  // Note no jobject argument, as it is static.
+  @CalledByNative
+  public static boolean staticJavaMethod() {
+      return true;
+  }
+
+  // No prefix, so this method is package private. It will still be exported.
+  @CalledByNative
+  void packagePrivateJavaMethod() {}
+
+  // Note the "Unchecked" suffix. By default, @CalledByNative will always generate bindings that
+  // call CheckException(). With "@CalledByNativeUnchecked", the client C++ code is responsible to
+  // call ClearException() and act as appropriate.
+  // See more details at the "@CalledByNativeUnchecked" annotation.
+  @CalledByNativeUnchecked
+  void methodThatThrowsException() throws Exception {}
+
+  // The generator is not confused by inline comments:
+  // @CalledByNative void thisShouldNotAppearInTheOutput();
+  // @CalledByNativeUnchecked public static void neitherShouldThis(int foo);
+
+  /**
+   * The generator is not confused by block comments:
+   * @CalledByNative void thisShouldNotAppearInTheOutputEither();
+   * @CalledByNativeUnchecked public static void andDefinitelyNotThis(int foo);
+   */
+
+  // String constants that look like comments don't confuse the generator:
+  private String arrgh = "*/*";
+
+  //------------------------------------------------------------------------------------------------
+  // Java fields which are accessed from C++ code only must be annotated with @AccessedByNative to
+  // prevent them being eliminated when unreferenced code is stripped.
+  @AccessedByNative
+  private int javaField;
+
+  //------------------------------------------------------------------------------------------------
+  // The following methods demonstrate declaring methods to call into C++ from Java.
+  // The generator detects the "native" and "static" keywords, the type and name of the first
+  // parameter, and the "native" prefix to the function name to determine the C++ function
+  // signatures. Besides these constraints the methods can be freely named.
+
+  // This declares a C++ function which the application code must implement:
+  //   static jint Init(JNIEnv* env, jobject obj);
+  // The jobject parameter refers back to this java side object instance.
+  // The implementation must return the pointer to the C++ object cast to jint.
+  // The caller of this method should store it, and supply it as a the nativeCPPClass param to
+  // subsequent native method calls (see the methods below that take an "int native..." as first
+  // param).
+  private native int nativeInit();
+
+  // This defines a function binding to the associated C++ class member function. The name is
+  // derived from |nativeDestroy| and |nativeCPPClass| to arrive at CPPClass::Destroy() (i.e. native
+  // prefixes stripped).
+  // The |nativeCPPClass| is automatically cast to type CPPClass* in order to obtain the object on
+  // which to invoke the member function.
+  private native void nativeDestroy(int nativeCPPClass);
+
+  // This declares a C++ function which the application code must implement:
+  //   static jdouble GetDoubleFunction(JNIEnv* env, jobject obj);
+  // The jobject parameter refers back to this java side object instance.
+  private native double nativeGetDoubleFunction();
+
+  // Similar to nativeGetDoubleFunction(), but here the C++ side will receive a jclass rather than
+  // jobject param, as the function is declared static.
+  private static native float nativeGetFloatFunction();
+
+  // This function takes a non-POD datatype. We have a list mapping them to their full classpath in
+  // jni_generator.py JavaParamToJni. If you require a new datatype, make sure you add to that
+  // function.
+  private native void nativeSetNonPODDatatype(Rect rect);
+
+  // This declares a C++ function which the application code must implement:
+  //   static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, jobject obj);
+  // The jobject parameter refers back to this java side object instance.
+  // Note that it returns a ScopedJavaLocalRef<jobject> so that you don' have to worry about
+  // deleting the JNI local reference.  This is similar with Strings and arrays.
+  private native Object nativeGetNonPODDatatype();
+
+  // Similar to nativeDestroy above, this will cast nativeCPPClass into pointer of CPPClass type and
+  // call its Method member function.
+  private native int nativeMethod(int nativeCPPClass);
+
+  // Similar to nativeMethod above, but here the C++ fully qualified class name is taken from the
+  // annotation rather than parameter name, which can thus be chosen freely.
+  @NativeClassQualifiedName("CPPClass::InnerClass")
+  private native double nativeMethodOtherP0(int nativePtr);
+
+  // An inner class has some special attributes for annotation.
+  class InnerClass {
+    @CalledByNative("InnerClass")
+    public float JavaInnerMethod() {
+    }
+
+    @CalledByNative("InnerClass")
+    public static void javaInnerFunction() {
+    }
+
+    @NativeCall("InnerClass")
+    private static native int nativeInnerFunction();
+
+    @NativeCall("InnerClass")
+    private static native String nativeInnerMethod(int nativeCPPClass);
+
+  }
+}
diff --git a/base/android/jni_generator/golden_sample_for_tests_jni.h b/base/android/jni_generator/golden_sample_for_tests_jni.h
new file mode 100644
index 0000000..08f25a7
--- /dev/null
+++ b/base/android/jni_generator/golden_sample_for_tests_jni.h
@@ -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.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator_tests.py
+// For
+//     org/chromium/example/jni_generator/SampleForTests
+
+#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
+#define org_chromium_example_jni_generator_SampleForTests_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kInnerClassClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests$InnerClass";
+const char kSampleForTestsClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InnerClass_clazz = NULL;
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_SampleForTests_clazz = NULL;
+}  // namespace
+
+namespace base {
+namespace android {
+
+static jint Init(JNIEnv* env, jobject obj);
+
+static jdouble GetDoubleFunction(JNIEnv* env, jobject obj);
+
+static jfloat GetFloatFunction(JNIEnv* env, jclass clazz);
+
+static void SetNonPODDatatype(JNIEnv* env, jobject obj,
+    jobject rect);
+
+static jobject GetNonPODDatatype(JNIEnv* env, jobject obj);
+
+static jint InnerFunction(JNIEnv* env, jclass clazz);
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject obj,
+    jint nativeCPPClass) {
+  DCHECK(nativeCPPClass) << "Destroy";
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  return native->Destroy(env, obj);
+}
+
+static jint Method(JNIEnv* env, jobject obj,
+    jint nativeCPPClass) {
+  DCHECK(nativeCPPClass) << "Method";
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  return native->Method(env, obj);
+}
+
+static jdouble MethodOtherP0(JNIEnv* env, jobject obj,
+    jint nativePtr) {
+  DCHECK(nativePtr) << "MethodOtherP0";
+  CPPClass::InnerClass* native =
+      reinterpret_cast<CPPClass::InnerClass*>(nativePtr);
+  return native->MethodOtherP0(env, obj);
+}
+
+static jstring InnerMethod(JNIEnv* env, jobject obj,
+    jint nativeCPPClass) {
+  DCHECK(nativeCPPClass) << "InnerMethod";
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  return native->InnerMethod(env, obj).Release();
+}
+
+static base::subtle::AtomicWord g_SampleForTests_javaMethod = 0;
+static jint Java_SampleForTests_javaMethod(JNIEnv* env, jobject obj, jint foo,
+    jint bar) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_SampleForTests_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_SampleForTests_clazz,
+      "javaMethod",
+
+"("
+"I"
+"I"
+")"
+"I",
+      &g_SampleForTests_javaMethod);
+
+  jint ret =
+    env->CallIntMethod(obj,
+      method_id, foo, bar);
+  base::android::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_staticJavaMethod = 0;
+static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_SampleForTests_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, g_SampleForTests_clazz,
+      "staticJavaMethod",
+
+"("
+")"
+"Z",
+      &g_SampleForTests_staticJavaMethod);
+
+  jboolean ret =
+    env->CallStaticBooleanMethod(g_SampleForTests_clazz,
+      method_id);
+  base::android::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_packagePrivateJavaMethod = 0;
+static void Java_SampleForTests_packagePrivateJavaMethod(JNIEnv* env, jobject
+    obj) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_SampleForTests_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_SampleForTests_clazz,
+      "packagePrivateJavaMethod",
+
+"("
+")"
+"V",
+      &g_SampleForTests_packagePrivateJavaMethod);
+
+  env->CallVoidMethod(obj,
+      method_id);
+  base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_SampleForTests_methodThatThrowsException = 0;
+static void Java_SampleForTests_methodThatThrowsException(JNIEnv* env, jobject
+    obj) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_SampleForTests_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_SampleForTests_clazz,
+      "methodThatThrowsException",
+
+"("
+")"
+"V",
+      &g_SampleForTests_methodThatThrowsException);
+
+  env->CallVoidMethod(obj,
+      method_id);
+
+}
+
+static base::subtle::AtomicWord g_InnerClass_JavaInnerMethod = 0;
+static jfloat Java_InnerClass_JavaInnerMethod(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InnerClass_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InnerClass_clazz,
+      "JavaInnerMethod",
+
+"("
+")"
+"F",
+      &g_InnerClass_JavaInnerMethod);
+
+  jfloat ret =
+    env->CallFloatMethod(obj,
+      method_id);
+  base::android::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InnerClass_javaInnerFunction = 0;
+static void Java_InnerClass_javaInnerFunction(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InnerClass_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, g_InnerClass_clazz,
+      "javaInnerFunction",
+
+"("
+")"
+"V",
+      &g_InnerClass_javaInnerFunction);
+
+  env->CallStaticVoidMethod(g_InnerClass_clazz,
+      method_id);
+  base::android::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_InnerClass_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetUnscopedClass(env, kInnerClassClassPath)));
+  g_SampleForTests_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetUnscopedClass(env, kSampleForTestsClassPath)));
+  static const JNINativeMethod kMethodsInnerClass[] = {
+    { "nativeInnerFunction",
+"("
+")"
+"I", reinterpret_cast<void*>(InnerFunction) },
+    { "nativeInnerMethod",
+"("
+"I"
+")"
+"Ljava/lang/String;", reinterpret_cast<void*>(InnerMethod) },
+  };
+  const int kMethodsInnerClassSize = arraysize(kMethodsInnerClass);
+
+  if (env->RegisterNatives(g_InnerClass_clazz,
+                           kMethodsInnerClass,
+                           kMethodsInnerClassSize) < 0) {
+    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+    return false;
+  }
+
+  static const JNINativeMethod kMethodsSampleForTests[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+    { "nativeDestroy",
+"("
+"I"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+    { "nativeGetDoubleFunction",
+"("
+")"
+"D", reinterpret_cast<void*>(GetDoubleFunction) },
+    { "nativeGetFloatFunction",
+"("
+")"
+"F", reinterpret_cast<void*>(GetFloatFunction) },
+    { "nativeSetNonPODDatatype",
+"("
+"Landroid/graphics/Rect;"
+")"
+"V", reinterpret_cast<void*>(SetNonPODDatatype) },
+    { "nativeGetNonPODDatatype",
+"("
+")"
+"Ljava/lang/Object;", reinterpret_cast<void*>(GetNonPODDatatype) },
+    { "nativeMethod",
+"("
+"I"
+")"
+"I", reinterpret_cast<void*>(Method) },
+    { "nativeMethodOtherP0",
+"("
+"I"
+")"
+"D", reinterpret_cast<void*>(MethodOtherP0) },
+  };
+  const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
+
+  if (env->RegisterNatives(g_SampleForTests_clazz,
+                           kMethodsSampleForTests,
+                           kMethodsSampleForTestsSize) < 0) {
+    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+    return false;
+  }
+
+  return true;
+}
+}  // namespace android
+}  // namespace base
+
+#endif  // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/jni_generator.gyp b/base/android/jni_generator/jni_generator.gyp
new file mode 100644
index 0000000..dc32d22
--- /dev/null
+++ b/base/android/jni_generator/jni_generator.gyp
@@ -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.
+
+{
+  'targets': [
+    {
+      'target_name': 'jni_generator_py_tests',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'run_jni_generator_py_tests',
+          'inputs': [
+            'jni_generator.py',
+            'jni_generator_tests.py',
+            'SampleForTests.java',
+            'golden_sample_for_tests_jni.h',
+          ],
+          'outputs': [
+            '',
+          ],
+          'action': [
+            'python', 'jni_generator_tests.py',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'jni_sample_header',
+      'type': 'none',
+      'sources': [
+        'SampleForTests.java',
+      ],
+      'variables': {
+        'jni_gen_dir': 'base',
+      },
+      'includes': [ '../../../build/jni_generator.gypi' ],
+    },
+    {
+      'target_name': 'jni_generator_tests',
+      'type': 'executable',
+      'dependencies': [
+        '../../base.gyp:test_support_base',
+        'jni_generator_py_tests',
+        'jni_sample_header',
+      ],
+      'include_dirs': [
+        '<(SHARED_INTERMEDIATE_DIR)/base',
+      ],
+      'sources': [
+        'sample_for_tests.cc',
+      ],
+    },
+  ],
+}
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
new file mode 100755
index 0000000..8616240
--- /dev/null
+++ b/base/android/jni_generator/jni_generator.py
@@ -0,0 +1,977 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Extracts native methods from a Java file and generates the JNI bindings.
+If you change this, please run and update the tests."""
+
+import collections
+import optparse
+import os
+import re
+import string
+from string import Template
+import subprocess
+import sys
+import textwrap
+import zipfile
+
+
+class ParseError(Exception):
+  """Exception thrown when we can't parse the input file."""
+
+  def __init__(self, description, *context_lines):
+    Exception.__init__(self)
+    self.description = description
+    self.context_lines = context_lines
+
+  def __str__(self):
+    context = '\n'.join(self.context_lines)
+    return '***\nERROR: %s\n\n%s\n***' % (self.description, context)
+
+
+class Param(object):
+  """Describes a param for a method, either java or native."""
+
+  def __init__(self, **kwargs):
+    self.datatype = kwargs['datatype']
+    self.name = kwargs['name']
+
+
+class NativeMethod(object):
+  """Describes a C/C++ method that is called by Java code"""
+
+  def __init__(self, **kwargs):
+    self.static = kwargs['static']
+    self.java_class_name = kwargs['java_class_name']
+    self.return_type = kwargs['return_type']
+    self.name = kwargs['name']
+    self.params = kwargs['params']
+    if self.params:
+      assert type(self.params) is list
+      assert type(self.params[0]) is Param
+    if (self.params and
+        self.params[0].datatype == 'int' and
+        self.params[0].name.startswith('native')):
+      self.type = 'method'
+      self.p0_type = self.params[0].name[len('native'):]
+      if kwargs.get('native_class_name'):
+        self.p0_type = kwargs['native_class_name']
+    else:
+      self.type = 'function'
+    self.method_id_var_name = kwargs.get('method_id_var_name', None)
+
+
+class CalledByNative(object):
+  """Describes a java method exported to c/c++"""
+
+  def __init__(self, **kwargs):
+    self.system_class = kwargs['system_class']
+    self.unchecked = kwargs['unchecked']
+    self.static = kwargs['static']
+    self.java_class_name = kwargs['java_class_name']
+    self.return_type = kwargs['return_type']
+    self.name = kwargs['name']
+    self.params = kwargs['params']
+    self.method_id_var_name = kwargs.get('method_id_var_name', None)
+    self.is_constructor = kwargs.get('is_constructor', False)
+    self.env_call = GetEnvCall(self.is_constructor, self.static,
+                               self.return_type)
+    self.static_cast = GetStaticCastForReturnType(self.return_type)
+
+
+def JavaDataTypeToC(java_type):
+  """Returns a C datatype for the given java type."""
+  java_pod_type_map = {
+      'int': 'jint',
+      'byte': 'jbyte',
+      'boolean': 'jboolean',
+      'long': 'jlong',
+      'double': 'jdouble',
+      'float': 'jfloat',
+  }
+  java_type_map = {
+      'void': 'void',
+      'String': 'jstring',
+      'java/lang/String': 'jstring',
+  }
+  if java_type in java_pod_type_map:
+    return java_pod_type_map[java_type]
+  elif java_type in java_type_map:
+    return java_type_map[java_type]
+  elif java_type.endswith('[]'):
+    if java_type[:-2] in java_pod_type_map:
+      return java_pod_type_map[java_type[:-2]] + 'Array'
+    return 'jobjectArray'
+  else:
+    return 'jobject'
+
+
+class JniParams(object):
+  _imports = []
+  _fully_qualified_class = ''
+  _package = ''
+  _inner_classes = []
+
+  @staticmethod
+  def SetFullyQualifiedClass(fully_qualified_class):
+    JniParams._fully_qualified_class = 'L' + fully_qualified_class
+    JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1])
+
+  @staticmethod
+  def ExtractImportsAndInnerClasses(contents):
+    contents = contents.replace('\n', '')
+    re_import = re.compile(r'import.*?(?P<class>\S*?);')
+    for match in re.finditer(re_import, contents):
+      JniParams._imports += ['L' + match.group('class').replace('.', '/')]
+
+    re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W')
+    for match in re.finditer(re_inner, contents):
+      inner = match.group('name')
+      if not JniParams._fully_qualified_class.endswith(inner):
+        JniParams._inner_classes += [JniParams._fully_qualified_class + '$' +
+                                     inner]
+
+  @staticmethod
+  def JavaToJni(param):
+    """Converts a java param into a JNI signature type."""
+    pod_param_map = {
+        'int': 'I',
+        'boolean': 'Z',
+        'long': 'J',
+        'double': 'D',
+        'float': 'F',
+        'byte': 'B',
+        'void': 'V',
+    }
+    object_param_list = [
+        'Ljava/lang/Boolean',
+        'Ljava/lang/Integer',
+        'Ljava/lang/Long',
+        'Ljava/lang/Object',
+        'Ljava/lang/String',
+    ]
+    if param == 'byte[][]':
+      return '[[B'
+    prefix = ''
+    # Array?
+    if param[-2:] == '[]':
+      prefix = '['
+      param = param[:-2]
+    # Generic?
+    if '<' in param:
+      param = param[:param.index('<')]
+    if param in pod_param_map:
+      return prefix + pod_param_map[param]
+    if '/' in param:
+      # Coming from javap, use the fully qualified param directly.
+      return 'L' + param + ';'
+    for qualified_name in (object_param_list +
+                           JniParams._imports +
+                           [JniParams._fully_qualified_class] +
+                           JniParams._inner_classes):
+      if (qualified_name.endswith('/' + param) or
+          qualified_name.endswith('$' + param.replace('.', '$')) or
+          qualified_name == 'L' + param):
+        return prefix + qualified_name + ';'
+    # Type not found, falling back to same package as this class.
+    return prefix + 'L' + JniParams._package + '/' + param + ';'
+
+  @staticmethod
+  def Signature(params, returns, wrap):
+    """Returns the JNI signature for the given datatypes."""
+    items = ['(']
+    items += [JniParams.JavaToJni(param.datatype) for param in params]
+    items += [')']
+    items += [JniParams.JavaToJni(returns)]
+    if wrap:
+      return '\n' + '\n'.join(['"' + item + '"' for item in items])
+    else:
+      return '"' + ''.join(items) + '"'
+
+  @staticmethod
+  def Parse(params):
+    """Parses the params into a list of Param objects."""
+    if not params:
+      return []
+    ret = []
+    for p in [p.strip() for p in params.split(',')]:
+      items = p.split(' ')
+      if 'final' in items:
+        items.remove('final')
+      param = Param(
+          datatype=items[0],
+          name=(items[1] if len(items) > 1 else 'p%s' % len(ret)),
+      )
+      ret += [param]
+    return ret
+
+
+def ExtractJNINamespace(contents):
+  re_jni_namespace = re.compile('.*?@JNINamespace\("(.*?)"\)')
+  m = re.findall(re_jni_namespace, contents)
+  if not m:
+    return ''
+  return m[0]
+
+
+def ExtractFullyQualifiedJavaClassName(java_file_name, contents):
+  re_package = re.compile('.*?package (.*?);')
+  matches = re.findall(re_package, contents)
+  if not matches:
+    raise SyntaxError('Unable to find "package" line in %s' % java_file_name)
+  return (matches[0].replace('.', '/') + '/' +
+          os.path.splitext(os.path.basename(java_file_name))[0])
+
+
+def ExtractNatives(contents):
+  """Returns a list of dict containing information about a native method."""
+  contents = contents.replace('\n', '')
+  natives = []
+  re_native = re.compile(r'(@NativeClassQualifiedName'
+                         '\(\"(?P<native_class_name>.*?)\"\))?\s*'
+                         '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\)))?\s*'
+                         '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*?native '
+                         '(?P<return>\S*?) '
+                         '(?P<name>\w+?)\((?P<params>.*?)\);')
+  for match in re.finditer(re_native, contents):
+    native = NativeMethod(
+        static='static' in match.group('qualifiers'),
+        java_class_name=match.group('java_class_name'),
+        native_class_name=match.group('native_class_name'),
+        return_type=match.group('return'),
+        name=match.group('name').replace('native', ''),
+        params=JniParams.Parse(match.group('params')))
+    natives += [native]
+  return natives
+
+
+def GetStaticCastForReturnType(return_type):
+  if return_type in ['String', 'java/lang/String']:
+    return 'jstring'
+  elif return_type.endswith('[]'):
+    return 'jobjectArray'
+  return None
+
+
+def GetEnvCall(is_constructor, is_static, return_type):
+  """Maps the types availabe via env->Call__Method."""
+  if is_constructor:
+    return 'NewObject'
+  env_call_map = {'boolean': 'Boolean',
+                  'byte': 'Byte',
+                  'char': 'Char',
+                  'short': 'Short',
+                  'int': 'Int',
+                  'long': 'Long',
+                  'float': 'Float',
+                  'void': 'Void',
+                  'double': 'Double',
+                  'Object': 'Object',
+                 }
+  call = env_call_map.get(return_type, 'Object')
+  if is_static:
+    call = 'Static' + call
+  return 'Call' + call + 'Method'
+
+
+def GetMangledParam(datatype):
+  """Returns a mangled identifier for the datatype."""
+  if len(datatype) <= 2:
+    return datatype.replace('[', 'A')
+  ret = ''
+  for i in range(1, len(datatype)):
+    c = datatype[i]
+    if c == '[':
+      ret += 'A'
+    elif c.isupper() or datatype[i - 1] in ['/', 'L']:
+      ret += c.upper()
+  return ret
+
+
+def GetMangledMethodName(name, params, return_type):
+  """Returns a mangled method name for the given signature.
+
+     The returned name can be used as a C identifier and will be unique for all
+     valid overloads of the same method.
+
+  Args:
+     name: string.
+     params: list of Param.
+     return_type: string.
+
+  Returns:
+      A mangled name.
+  """
+  mangled_items = []
+  for datatype in [return_type] + [x.datatype for x in params]:
+    mangled_items += [GetMangledParam(JniParams.JavaToJni(datatype))]
+  mangled_name = name + '_'.join(mangled_items)
+  assert re.match(r'[0-9a-zA-Z_]+', mangled_name)
+  return mangled_name
+
+
+def MangleCalledByNatives(called_by_natives):
+  """Mangles all the overloads from the call_by_natives list."""
+  method_counts = collections.defaultdict(
+      lambda: collections.defaultdict(lambda: 0))
+  for called_by_native in called_by_natives:
+    java_class_name = called_by_native.java_class_name
+    name = called_by_native.name
+    method_counts[java_class_name][name] += 1
+  for called_by_native in called_by_natives:
+    java_class_name = called_by_native.java_class_name
+    method_name = called_by_native.name
+    method_id_var_name = method_name
+    if method_counts[java_class_name][method_name] > 1:
+      method_id_var_name = GetMangledMethodName(method_name,
+                                                called_by_native.params,
+                                                called_by_native.return_type)
+    called_by_native.method_id_var_name = method_id_var_name
+  return called_by_natives
+
+
+# Regex to match the JNI return types that should be included in a
+# ScopedJavaLocalRef.
+RE_SCOPED_JNI_RETURN_TYPES = re.compile('jobject|jclass|jstring|.*Array')
+
+# Regex to match a string like "@CalledByNative public void foo(int bar)".
+RE_CALLED_BY_NATIVE = re.compile(
+    '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?'
+    '\s+(?P<prefix>[\w ]*?)'
+    '\s*(?P<return_type>\w+)'
+    '\s+(?P<name>\w+)'
+    '\s*\((?P<params>[^\)]*)\)')
+
+
+def ExtractCalledByNatives(contents):
+  """Parses all methods annotated with @CalledByNative.
+
+  Args:
+    contents: the contents of the java file.
+
+  Returns:
+    A list of dict with information about the annotated methods.
+    TODO(bulach): return a CalledByNative object.
+
+  Raises:
+    ParseError: if unable to parse.
+  """
+  called_by_natives = []
+  for match in re.finditer(RE_CALLED_BY_NATIVE, contents):
+    called_by_natives += [CalledByNative(
+        system_class=False,
+        unchecked='Unchecked' in match.group('Unchecked'),
+        static='static' in match.group('prefix'),
+        java_class_name=match.group('annotation') or '',
+        return_type=match.group('return_type'),
+        name=match.group('name'),
+        params=JniParams.Parse(match.group('params')))]
+  # Check for any @CalledByNative occurrences that weren't matched.
+  unmatched_lines = re.sub(RE_CALLED_BY_NATIVE, '', contents).split('\n')
+  for line1, line2 in zip(unmatched_lines, unmatched_lines[1:]):
+    if '@CalledByNative' in line1:
+      raise ParseError('could not parse @CalledByNative method signature',
+                       line1, line2)
+  return MangleCalledByNatives(called_by_natives)
+
+
+class JNIFromJavaP(object):
+  """Uses 'javap' to parse a .class file and generate the JNI header file."""
+
+  def __init__(self, contents, namespace):
+    self.contents = contents
+    self.namespace = namespace
+    self.fully_qualified_class = re.match('.*?class (?P<class_name>.*?) ',
+                                          contents[1]).group('class_name')
+    self.fully_qualified_class = self.fully_qualified_class.replace('.', '/')
+    JniParams.SetFullyQualifiedClass(self.fully_qualified_class)
+    self.java_class_name = self.fully_qualified_class.split('/')[-1]
+    if not self.namespace:
+      self.namespace = 'JNI_' + self.java_class_name
+    re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
+                           '\((?P<params>.*?)\)')
+    self.called_by_natives = []
+    for content in contents[2:]:
+      match = re.match(re_method, content)
+      if not match:
+        continue
+      self.called_by_natives += [CalledByNative(
+          system_class=True,
+          unchecked=False,
+          static='static' in match.group('prefix'),
+          java_class_name='',
+          return_type=match.group('return_type').replace('.', '/'),
+          name=match.group('name'),
+          params=JniParams.Parse(match.group('params').replace('.', '/')))]
+    re_constructor = re.compile('.*? public ' +
+                                self.fully_qualified_class.replace('/', '.') +
+                                '\((?P<params>.*?)\)')
+    for content in contents[2:]:
+      match = re.match(re_constructor, content)
+      if not match:
+        continue
+      self.called_by_natives += [CalledByNative(
+          system_class=True,
+          unchecked=False,
+          static=False,
+          java_class_name='',
+          return_type=self.fully_qualified_class,
+          name='Constructor',
+          params=JniParams.Parse(match.group('params').replace('.', '/')),
+          is_constructor=True)]
+    self.called_by_natives = MangleCalledByNatives(self.called_by_natives)
+    self.inl_header_file_generator = InlHeaderFileGenerator(
+        self.namespace, self.fully_qualified_class, [], self.called_by_natives)
+
+  def GetContent(self):
+    return self.inl_header_file_generator.GetContent()
+
+  @staticmethod
+  def CreateFromClass(class_file, namespace):
+    class_name = os.path.splitext(os.path.basename(class_file))[0]
+    p = subprocess.Popen(args=['javap', class_name],
+                         cwd=os.path.dirname(class_file),
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE)
+    stdout, _ = p.communicate()
+    jni_from_javap = JNIFromJavaP(stdout.split('\n'), namespace)
+    return jni_from_javap
+
+
+class JNIFromJavaSource(object):
+  """Uses the given java source file to generate the JNI header file."""
+
+  def __init__(self, contents, fully_qualified_class):
+    contents = self._RemoveComments(contents)
+    JniParams.SetFullyQualifiedClass(fully_qualified_class)
+    JniParams.ExtractImportsAndInnerClasses(contents)
+    jni_namespace = ExtractJNINamespace(contents)
+    natives = ExtractNatives(contents)
+    called_by_natives = ExtractCalledByNatives(contents)
+    if len(natives) == 0 and len(called_by_natives) == 0:
+      raise SyntaxError('Unable to find any JNI methods for %s.' %
+                        fully_qualified_class)
+    inl_header_file_generator = InlHeaderFileGenerator(
+        jni_namespace, fully_qualified_class, natives, called_by_natives)
+    self.content = inl_header_file_generator.GetContent()
+
+  def _RemoveComments(self, contents):
+    # We need to support both inline and block comments, and we need to handle
+    # strings that contain '//' or '/*'. Rather than trying to do all that with
+    # regexps, we just pipe the contents through the C preprocessor. We tell cpp
+    # the file has already been preprocessed, so it just removes comments and
+    # doesn't try to parse #include, #pragma etc.
+    #
+    # TODO(husky): This is a bit hacky. It would be cleaner to use a real Java
+    # parser. Maybe we could ditch JNIFromJavaSource and just always use
+    # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT.
+    # http://code.google.com/p/chromium/issues/detail?id=138941
+    p = subprocess.Popen(args=['cpp', '-fpreprocessed'],
+                         stdin=subprocess.PIPE,
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE)
+    stdout, _ = p.communicate(contents)
+    return stdout
+
+  def GetContent(self):
+    return self.content
+
+  @staticmethod
+  def CreateFromFile(java_file_name):
+    contents = file(java_file_name).read()
+    fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name,
+                                                               contents)
+    return JNIFromJavaSource(contents, fully_qualified_class)
+
+
+class InlHeaderFileGenerator(object):
+  """Generates an inline header file for JNI integration."""
+
+  def __init__(self, namespace, fully_qualified_class, natives,
+               called_by_natives):
+    self.namespace = namespace
+    self.fully_qualified_class = fully_qualified_class
+    self.class_name = self.fully_qualified_class.split('/')[-1]
+    self.natives = natives
+    self.called_by_natives = called_by_natives
+    self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'
+
+  def GetContent(self):
+    """Returns the content of the JNI binding file."""
+    template = Template("""\
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+// This file is autogenerated by
+//     ${SCRIPT_NAME}
+// For
+//     ${FULLY_QUALIFIED_CLASS}
+
+#ifndef ${HEADER_GUARD}
+#define ${HEADER_GUARD}
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+$CLASS_PATH_DEFINITIONS
+}  // namespace
+
+$OPEN_NAMESPACE
+$FORWARD_DECLARATIONS
+
+// Step 2: method stubs.
+$METHOD_STUBS
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+$REGISTER_NATIVES_IMPL
+  return true;
+}
+$CLOSE_NAMESPACE
+#endif  // ${HEADER_GUARD}
+""")
+    script_components = os.path.abspath(sys.argv[0]).split(os.path.sep)
+    base_index = script_components.index('base')
+    script_name = os.sep.join(script_components[base_index:])
+    values = {
+        'SCRIPT_NAME': script_name,
+        'FULLY_QUALIFIED_CLASS': self.fully_qualified_class,
+        'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(),
+        'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(),
+        'METHOD_STUBS': self.GetMethodStubsString(),
+        'OPEN_NAMESPACE': self.GetOpenNamespaceString(),
+        'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString(),
+        'CLOSE_NAMESPACE': self.GetCloseNamespaceString(),
+        'HEADER_GUARD': self.header_guard,
+    }
+    return WrapOutput(template.substitute(values))
+
+  def GetClassPathDefinitionsString(self):
+    ret = []
+    ret += [self.GetClassPathDefinitions()]
+    return '\n'.join(ret)
+
+  def GetForwardDeclarationsString(self):
+    ret = []
+    for native in self.natives:
+      if native.type != 'method':
+        ret += [self.GetForwardDeclaration(native)]
+    return '\n'.join(ret)
+
+  def GetMethodStubsString(self):
+    ret = []
+    for native in self.natives:
+      if native.type == 'method':
+        ret += [self.GetNativeMethodStub(native)]
+    for called_by_native in self.called_by_natives:
+      ret += [self.GetCalledByNativeMethodStub(called_by_native)]
+    return '\n'.join(ret)
+
+  def GetKMethodsString(self, clazz):
+    ret = []
+    for native in self.natives:
+      if (native.java_class_name == clazz or
+          (not native.java_class_name and clazz == self.class_name)):
+        ret += [self.GetKMethodArrayEntry(native)]
+    return '\n'.join(ret)
+
+  def GetRegisterNativesImplString(self):
+    """Returns the implementation for RegisterNatives."""
+    template = Template("""\
+  static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
+${KMETHODS}
+  };
+  const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
+
+  if (env->RegisterNatives(g_${JAVA_CLASS}_clazz,
+                           kMethods${JAVA_CLASS},
+                           kMethods${JAVA_CLASS}Size) < 0) {
+    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+    return false;
+  }
+""")
+    ret = [self.GetFindClasses()]
+    all_classes = self.GetUniqueClasses(self.natives)
+    all_classes[self.class_name] = self.fully_qualified_class
+    for clazz in all_classes:
+      kmethods = self.GetKMethodsString(clazz)
+      if kmethods:
+        values = {'JAVA_CLASS': clazz,
+                  'KMETHODS': kmethods}
+        ret += [template.substitute(values)]
+    if not ret: return ''
+    return '\n' + '\n'.join(ret)
+
+  def GetOpenNamespaceString(self):
+    if self.namespace:
+      all_namespaces = ['namespace %s {' % ns
+                        for ns in self.namespace.split('::')]
+      return '\n'.join(all_namespaces)
+    return ''
+
+  def GetCloseNamespaceString(self):
+    if self.namespace:
+      all_namespaces = ['}  // namespace %s' % ns
+                        for ns in self.namespace.split('::')]
+      all_namespaces.reverse()
+      return '\n'.join(all_namespaces) + '\n'
+    return ''
+
+  def GetJNIFirstParam(self, native):
+    ret = []
+    if native.type == 'method':
+      ret = ['jobject obj']
+    elif native.type == 'function':
+      if native.static:
+        ret = ['jclass clazz']
+      else:
+        ret = ['jobject obj']
+    return ret
+
+  def GetParamsInDeclaration(self, native):
+    """Returns the params for the stub declaration.
+
+    Args:
+      native: the native dictionary describing the method.
+
+    Returns:
+      A string containing the params.
+    """
+    return ',\n    '.join(self.GetJNIFirstParam(native) +
+                          [JavaDataTypeToC(param.datatype) + ' ' +
+                           param.name
+                           for param in native.params])
+
+  def GetCalledByNativeParamsInDeclaration(self, called_by_native):
+    return ',\n    '.join([JavaDataTypeToC(param.datatype) + ' ' +
+                           param.name
+                           for param in called_by_native.params])
+
+  def GetForwardDeclaration(self, native):
+    template = Template("""
+static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
+""")
+    values = {'RETURN': JavaDataTypeToC(native.return_type),
+              'NAME': native.name,
+              'PARAMS': self.GetParamsInDeclaration(native)}
+    return template.substitute(values)
+
+  def GetNativeMethodStub(self, native):
+    """Returns stubs for native methods."""
+    template = Template("""\
+static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {
+  DCHECK(${PARAM0_NAME}) << "${NAME}";
+  ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
+  return native->${NAME}(env, obj${PARAMS_IN_CALL})${POST_CALL};
+}
+""")
+    params_for_call = ', '.join(p.name for p in native.params[1:])
+    if params_for_call:
+      params_for_call = ', ' + params_for_call
+
+    return_type = JavaDataTypeToC(native.return_type)
+    if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
+      scoped_return_type = 'ScopedJavaLocalRef<' + return_type + '>'
+      post_call = '.Release()'
+    else:
+      scoped_return_type = return_type
+      post_call = ''
+    values = {
+        'RETURN': return_type,
+        'SCOPED_RETURN': scoped_return_type,
+        'NAME': native.name,
+        'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
+        'PARAM0_NAME': native.params[0].name,
+        'P0_TYPE': native.p0_type,
+        'PARAMS_IN_CALL': params_for_call,
+        'POST_CALL': post_call
+    }
+    return template.substitute(values)
+
+  def GetCalledByNativeMethodStub(self, called_by_native):
+    """Returns a string."""
+    function_signature_template = Template("""\
+static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\
+JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""")
+    function_header_template = Template("""\
+${FUNCTION_SIGNATURE} {""")
+    function_header_with_unused_template = Template("""\
+${FUNCTION_SIGNATURE} __attribute__ ((unused));
+${FUNCTION_SIGNATURE} {""")
+    template = Template("""
+static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
+${FUNCTION_HEADER}
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_${JAVA_CLASS}_clazz);
+  jmethodID method_id =
+    ${GET_METHOD_ID_IMPL}
+  ${RETURN_DECLARATION}
+  ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
+      method_id${PARAMS_IN_CALL})${POST_CALL};
+  ${CHECK_EXCEPTION}
+  ${RETURN_CLAUSE}
+}""")
+    if called_by_native.static or called_by_native.is_constructor:
+      first_param_in_declaration = ''
+      first_param_in_call = ('g_%s_clazz' %
+                             (called_by_native.java_class_name or
+                              self.class_name))
+    else:
+      first_param_in_declaration = ', jobject obj'
+      first_param_in_call = 'obj'
+    params_in_declaration = self.GetCalledByNativeParamsInDeclaration(
+        called_by_native)
+    if params_in_declaration:
+      params_in_declaration = ', ' + params_in_declaration
+    params_for_call = ', '.join(param.name
+                                for param in called_by_native.params)
+    if params_for_call:
+      params_for_call = ', ' + params_for_call
+    pre_call = ''
+    post_call = ''
+    if called_by_native.static_cast:
+      pre_call = 'static_cast<%s>(' % called_by_native.static_cast
+      post_call = ')'
+    check_exception = ''
+    if not called_by_native.unchecked:
+      check_exception = 'base::android::CheckException(env);'
+    return_type = JavaDataTypeToC(called_by_native.return_type)
+    return_declaration = ''
+    return_clause = ''
+    if return_type != 'void':
+      pre_call = '  ' + pre_call
+      return_declaration = return_type + ' ret ='
+      if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
+        return_type = 'ScopedJavaLocalRef<' + return_type + '>'
+        return_clause = 'return ' + return_type + '(env, ret);'
+      else:
+        return_clause = 'return ret;'
+    values = {
+        'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+        'METHOD': called_by_native.name,
+        'RETURN_TYPE': return_type,
+        'RETURN_DECLARATION': return_declaration,
+        'RETURN_CLAUSE': return_clause,
+        'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration,
+        'PARAMS_IN_DECLARATION': params_in_declaration,
+        'STATIC': 'Static' if called_by_native.static else '',
+        'PRE_CALL': pre_call,
+        'POST_CALL': post_call,
+        'ENV_CALL': called_by_native.env_call,
+        'FIRST_PARAM_IN_CALL': first_param_in_call,
+        'PARAMS_IN_CALL': params_for_call,
+        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+        'CHECK_EXCEPTION': check_exception,
+        'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native)
+    }
+    values['FUNCTION_SIGNATURE'] = (
+        function_signature_template.substitute(values))
+    if called_by_native.system_class:
+      values['FUNCTION_HEADER'] = (
+          function_header_with_unused_template.substitute(values))
+    else:
+      values['FUNCTION_HEADER'] = function_header_template.substitute(values)
+    return template.substitute(values)
+
+  def GetKMethodArrayEntry(self, native):
+    template = Template("""\
+    { "native${NAME}", ${JNI_SIGNATURE}, reinterpret_cast<void*>(${NAME}) },""")
+    values = {'NAME': native.name,
+              'JNI_SIGNATURE': JniParams.Signature(native.params,
+                                                   native.return_type,
+                                                   True)}
+    return template.substitute(values)
+
+  def GetUniqueClasses(self, origin):
+    ret = {self.class_name: self.fully_qualified_class}
+    for entry in origin:
+      class_name = self.class_name
+      jni_class_path = self.fully_qualified_class
+      if entry.java_class_name:
+        class_name = entry.java_class_name
+        jni_class_path = self.fully_qualified_class + '$' + class_name
+      ret[class_name] = jni_class_path
+    return ret
+
+  def GetClassPathDefinitions(self):
+    """Returns the ClassPath constants."""
+    ret = []
+    template = Template("""\
+const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""")
+    native_classes = self.GetUniqueClasses(self.natives)
+    called_by_native_classes = self.GetUniqueClasses(self.called_by_natives)
+    all_classes = native_classes
+    all_classes.update(called_by_native_classes)
+    for clazz in all_classes:
+      values = {
+          'JAVA_CLASS': clazz,
+          'JNI_CLASS_PATH': all_classes[clazz],
+      }
+      ret += [template.substitute(values)]
+    ret += ''
+    for clazz in called_by_native_classes:
+      template = Template("""\
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_${JAVA_CLASS}_clazz = NULL;""")
+      values = {
+          'JAVA_CLASS': clazz,
+      }
+      ret += [template.substitute(values)]
+    return '\n'.join(ret)
+
+  def GetFindClasses(self):
+    """Returns the imlementation of FindClass for all known classes."""
+    template = Template("""\
+  g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetUnscopedClass(env, k${JAVA_CLASS}ClassPath)));""")
+    ret = []
+    for clazz in self.GetUniqueClasses(self.called_by_natives):
+      values = {'JAVA_CLASS': clazz}
+      ret += [template.substitute(values)]
+    return '\n'.join(ret)
+
+  def GetMethodIDImpl(self, called_by_native):
+    """Returns the implementation of GetMethodID."""
+    template = Template("""\
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_${STATIC}>(
+      env, g_${JAVA_CLASS}_clazz,
+      "${JNI_NAME}",
+      ${JNI_SIGNATURE},
+      &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME});
+""")
+    jni_name = called_by_native.name
+    jni_return_type = called_by_native.return_type
+    if called_by_native.is_constructor:
+      jni_name = '<init>'
+      jni_return_type = 'void'
+    values = {
+        'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+        'JNI_NAME': jni_name,
+        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+        'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE',
+        'JNI_SIGNATURE': JniParams.Signature(called_by_native.params,
+                                             jni_return_type,
+                                             True)
+    }
+    return template.substitute(values)
+
+
+def WrapOutput(output):
+  ret = []
+  for line in output.splitlines():
+    # Do not wrap lines under 80 characters or preprocessor directives.
+    if len(line) < 80 or line.lstrip()[:1] == '#':
+      stripped = line.rstrip()
+      if len(ret) == 0 or len(ret[-1]) or len(stripped):
+        ret.append(stripped)
+    else:
+      first_line_indent = ' ' * (len(line) - len(line.lstrip()))
+      subsequent_indent =  first_line_indent + ' ' * 4
+      if line.startswith('//'):
+        subsequent_indent = '//' + subsequent_indent
+      wrapper = textwrap.TextWrapper(width=80,
+                                     subsequent_indent=subsequent_indent,
+                                     break_long_words=False)
+      ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)]
+  ret += ['']
+  return '\n'.join(ret)
+
+
+def ExtractJarInputFile(jar_file, input_file, out_dir):
+  """Extracts input file from jar and returns the filename.
+
+  The input file is extracted to the same directory that the generated jni
+  headers will be placed in.  This is passed as an argument to script.
+
+  Args:
+    jar_file: the jar file containing the input files to extract.
+    input_files: the list of files to extract from the jar file.
+    out_dir: the name of the directories to extract to.
+
+  Returns:
+    the name of extracted input file.
+  """
+  jar_file = zipfile.ZipFile(jar_file)
+
+  out_dir = os.path.join(out_dir, os.path.dirname(input_file))
+  if not os.path.exists(out_dir):
+    os.makedirs(out_dir)
+  extracted_file_name = os.path.join(out_dir, os.path.basename(input_file))
+  with open(extracted_file_name, 'w') as outfile:
+    outfile.write(jar_file.read(input_file))
+
+  return extracted_file_name
+
+
+def GenerateJNIHeader(input_file, output_file, namespace):
+  try:
+    if os.path.splitext(input_file)[1] == '.class':
+      jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, namespace)
+      content = jni_from_javap.GetContent()
+    else:
+      jni_from_java_source = JNIFromJavaSource.CreateFromFile(input_file)
+      content = jni_from_java_source.GetContent()
+  except ParseError, e:
+    print e
+    sys.exit(1)
+  if output_file:
+    if not os.path.exists(os.path.dirname(os.path.abspath(output_file))):
+      os.makedirs(os.path.dirname(os.path.abspath(output_file)))
+    with file(output_file, 'w') as f:
+      f.write(content)
+  else:
+    print output
+
+
+def main(argv):
+  usage = """usage: %prog [OPTIONS]
+This script will parse the given java source code extracting the native
+declarations and print the header file to stdout (or a file).
+See SampleForTests.java for more details.
+  """
+  option_parser = optparse.OptionParser(usage=usage)
+  option_parser.add_option('-j', dest='jar_file',
+                           help='Extract the list of input files from'
+                           ' a specified jar file.'
+                           ' Uses javap to extract the methods from a'
+                           ' pre-compiled class. --input should point'
+                           ' to pre-compiled Java .class files.')
+  option_parser.add_option('-n', dest='namespace',
+                           help='Uses as a namespace in the generated header,'
+                           ' instead of the javap class name.')
+  option_parser.add_option('--input_file',
+                           help='Single input file name. The output file name '
+                           'will be derived from it. Must be used with '
+                           '--output_dir.')
+  option_parser.add_option('--output_dir',
+                           help='The output directory. Must be used with '
+                           '--input')
+  options, args = option_parser.parse_args(argv)
+  if options.jar_file:
+    input_file = ExtractJarInputFile(options.jar_file, options.input_file,
+                                     options.output_dir)
+  else:
+    input_file = options.input_file
+  output_file = None
+  if options.output_dir:
+    root_name = os.path.splitext(os.path.basename(input_file))[0]
+    output_file = os.path.join(options.output_dir, root_name) + '_jni.h'
+  GenerateJNIHeader(input_file, output_file, options.namespace)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
new file mode 100755
index 0000000..886b731
--- /dev/null
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -0,0 +1,1583 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for jni_generator.py.
+
+This test suite contains various tests for the JNI generator.
+It exercises the low-level parser all the way up to the
+code generator and ensures the output matches a golden
+file.
+"""
+
+import difflib
+import os
+import sys
+import unittest
+import jni_generator
+from jni_generator import CalledByNative, NativeMethod, Param
+
+
+class TestGenerator(unittest.TestCase):
+  def assertObjEquals(self, first, second):
+    dict_first = first.__dict__
+    dict_second = second.__dict__
+    self.assertEquals(dict_first.keys(), dict_second.keys())
+    for key, value in dict_first.iteritems():
+      if (type(value) is list and len(value) and
+          isinstance(type(value[0]), object)):
+        self.assertListEquals(value, second.__getattribute__(key))
+      else:
+        actual = second.__getattribute__(key)
+        self.assertEquals(value, actual,
+                          'Key ' + key + ': ' + str(value) + '!=' + str(actual))
+
+  def assertListEquals(self, first, second):
+    self.assertEquals(len(first), len(second))
+    for i in xrange(len(first)):
+      if isinstance(first[i], object):
+        self.assertObjEquals(first[i], second[i])
+      else:
+        self.assertEquals(first[i], second[i])
+
+  def assertTextEquals(self, golden_text, generated_text):
+    stripped_golden = [l.strip() for l in golden_text.split('\n')]
+    stripped_generated = [l.strip() for l in generated_text.split('\n')]
+    if stripped_golden != stripped_generated:
+      print self.id()
+      for line in difflib.context_diff(stripped_golden, stripped_generated):
+        print line
+      print '\n\nGenerated'
+      print '=' * 80
+      print generated_text
+      print '=' * 80
+      self.fail('Golden text mismatch')
+
+  def testNatives(self):
+    test_data = """"
+    interface OnFrameAvailableListener {}
+    private native int nativeInit();
+    private native void nativeDestroy(int nativeChromeBrowserProvider);
+    private native long nativeAddBookmark(
+            int nativeChromeBrowserProvider,
+            String url, String title, boolean isFolder, long parentId);
+    private static native String nativeGetDomainAndRegistry(String url);
+    private static native void nativeCreateHistoricalTabFromState(
+            byte[] state, int tab_index);
+    private native byte[] nativeGetStateAsByteArray(View view);
+    private static native String[] nativeGetAutofillProfileGUIDs();
+    private native void nativeSetRecognitionResults(
+            int sessionId, String[] results);
+    private native long nativeAddBookmarkFromAPI(
+            int nativeChromeBrowserProvider,
+            String url, Long created, Boolean isBookmark,
+            Long date, byte[] favicon, String title, Integer visits);
+    native int nativeFindAll(String find);
+    private static native OnFrameAvailableListener nativeGetInnerClass();
+    private native Bitmap nativeQueryBitmap(
+            int nativeChromeBrowserProvider,
+            String[] projection, String selection,
+            String[] selectionArgs, String sortOrder);
+    private native void nativeGotOrientation(
+            int nativeDataFetcherImplAndroid,
+            double alpha, double beta, double gamma);
+    """
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+    natives = jni_generator.ExtractNatives(test_data)
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init',
+                     params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='void', static=False, name='Destroy',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='long', static=False, name='AddBookmark',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider'),
+                             Param(datatype='String',
+                                   name='url'),
+                             Param(datatype='String',
+                                   name='title'),
+                             Param(datatype='boolean',
+                                   name='isFolder'),
+                             Param(datatype='long',
+                                   name='parentId')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='String', static=True,
+                     name='GetDomainAndRegistry',
+                     params=[Param(datatype='String',
+                                   name='url')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='void', static=True,
+                     name='CreateHistoricalTabFromState',
+                     params=[Param(datatype='byte[]',
+                                   name='state'),
+                             Param(datatype='int',
+                                   name='tab_index')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='byte[]', static=False,
+                     name='GetStateAsByteArray',
+                     params=[Param(datatype='View', name='view')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='String[]', static=True,
+                     name='GetAutofillProfileGUIDs', params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='void', static=False,
+                     name='SetRecognitionResults',
+                     params=[Param(datatype='int', name='sessionId'),
+                             Param(datatype='String[]', name='results')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='long', static=False,
+                     name='AddBookmarkFromAPI',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider'),
+                             Param(datatype='String',
+                                   name='url'),
+                             Param(datatype='Long',
+                                   name='created'),
+                             Param(datatype='Boolean',
+                                   name='isBookmark'),
+                             Param(datatype='Long',
+                                   name='date'),
+                             Param(datatype='byte[]',
+                                   name='favicon'),
+                             Param(datatype='String',
+                                   name='title'),
+                             Param(datatype='Integer',
+                                   name='visits')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='int', static=False,
+                     name='FindAll',
+                     params=[Param(datatype='String',
+                                   name='find')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='OnFrameAvailableListener', static=True,
+                     name='GetInnerClass',
+                     params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='Bitmap',
+                     static=False,
+                     name='QueryBitmap',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider'),
+                             Param(datatype='String[]',
+                                   name='projection'),
+                             Param(datatype='String',
+                                   name='selection'),
+                             Param(datatype='String[]',
+                                   name='selectionArgs'),
+                             Param(datatype='String',
+                                   name='sortOrder'),
+                            ],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='void', static=False,
+                     name='GotOrientation',
+                     params=[Param(datatype='int',
+                                   name='nativeDataFetcherImplAndroid'),
+                             Param(datatype='double',
+                                   name='alpha'),
+                             Param(datatype='double',
+                                   name='beta'),
+                             Param(datatype='double',
+                                   name='gamma'),
+                            ],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='content::DataFetcherImplAndroid'),
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [])
+    golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator_tests.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject obj);
+
+static jstring GetDomainAndRegistry(JNIEnv* env, jclass clazz,
+    jstring url);
+
+static void CreateHistoricalTabFromState(JNIEnv* env, jclass clazz,
+    jbyteArray state,
+    jint tab_index);
+
+static jbyteArray GetStateAsByteArray(JNIEnv* env, jobject obj,
+    jobject view);
+
+static jobjectArray GetAutofillProfileGUIDs(JNIEnv* env, jclass clazz);
+
+static void SetRecognitionResults(JNIEnv* env, jobject obj,
+    jint sessionId,
+    jobjectArray results);
+
+static jint FindAll(JNIEnv* env, jobject obj,
+    jstring find);
+
+static jobject GetInnerClass(JNIEnv* env, jclass clazz);
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject obj,
+    jint nativeChromeBrowserProvider) {
+  DCHECK(nativeChromeBrowserProvider) << "Destroy";
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  return native->Destroy(env, obj);
+}
+
+static jlong AddBookmark(JNIEnv* env, jobject obj,
+    jint nativeChromeBrowserProvider,
+    jstring url,
+    jstring title,
+    jboolean isFolder,
+    jlong parentId) {
+  DCHECK(nativeChromeBrowserProvider) << "AddBookmark";
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  return native->AddBookmark(env, obj, url, title, isFolder, parentId);
+}
+
+static jlong AddBookmarkFromAPI(JNIEnv* env, jobject obj,
+    jint nativeChromeBrowserProvider,
+    jstring url,
+    jobject created,
+    jobject isBookmark,
+    jobject date,
+    jbyteArray favicon,
+    jstring title,
+    jobject visits) {
+  DCHECK(nativeChromeBrowserProvider) << "AddBookmarkFromAPI";
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  return native->AddBookmarkFromAPI(env, obj, url, created, isBookmark, date,
+      favicon, title, visits);
+}
+
+static jobject QueryBitmap(JNIEnv* env, jobject obj,
+    jint nativeChromeBrowserProvider,
+    jobjectArray projection,
+    jstring selection,
+    jobjectArray selectionArgs,
+    jstring sortOrder) {
+  DCHECK(nativeChromeBrowserProvider) << "QueryBitmap";
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  return native->QueryBitmap(env, obj, projection, selection, selectionArgs,
+      sortOrder).Release();
+}
+
+static void GotOrientation(JNIEnv* env, jobject obj,
+    jint nativeDataFetcherImplAndroid,
+    jdouble alpha,
+    jdouble beta,
+    jdouble gamma) {
+  DCHECK(nativeDataFetcherImplAndroid) << "GotOrientation";
+  DataFetcherImplAndroid* native =
+      reinterpret_cast<DataFetcherImplAndroid*>(nativeDataFetcherImplAndroid);
+  return native->GotOrientation(env, obj, alpha, beta, gamma);
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetUnscopedClass(env, kTestJniClassPath)));
+  static const JNINativeMethod kMethodsTestJni[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+    { "nativeDestroy",
+"("
+"I"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+    { "nativeAddBookmark",
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Z"
+"J"
+")"
+"J", reinterpret_cast<void*>(AddBookmark) },
+    { "nativeGetDomainAndRegistry",
+"("
+"Ljava/lang/String;"
+")"
+"Ljava/lang/String;", reinterpret_cast<void*>(GetDomainAndRegistry) },
+    { "nativeCreateHistoricalTabFromState",
+"("
+"[B"
+"I"
+")"
+"V", reinterpret_cast<void*>(CreateHistoricalTabFromState) },
+    { "nativeGetStateAsByteArray",
+"("
+"Landroid/view/View;"
+")"
+"[B", reinterpret_cast<void*>(GetStateAsByteArray) },
+    { "nativeGetAutofillProfileGUIDs",
+"("
+")"
+"[Ljava/lang/String;", reinterpret_cast<void*>(GetAutofillProfileGUIDs) },
+    { "nativeSetRecognitionResults",
+"("
+"I"
+"[Ljava/lang/String;"
+")"
+"V", reinterpret_cast<void*>(SetRecognitionResults) },
+    { "nativeAddBookmarkFromAPI",
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/Long;"
+"Ljava/lang/Boolean;"
+"Ljava/lang/Long;"
+"[B"
+"Ljava/lang/String;"
+"Ljava/lang/Integer;"
+")"
+"J", reinterpret_cast<void*>(AddBookmarkFromAPI) },
+    { "nativeFindAll",
+"("
+"Ljava/lang/String;"
+")"
+"I", reinterpret_cast<void*>(FindAll) },
+    { "nativeGetInnerClass",
+"("
+")"
+"Lorg/chromium/example/jni_generator/SampleForTests$OnFrameAvailableListener;",
+    reinterpret_cast<void*>(GetInnerClass) },
+    { "nativeQueryBitmap",
+"("
+"I"
+"[Ljava/lang/String;"
+"Ljava/lang/String;"
+"[Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Landroid/graphics/Bitmap;", reinterpret_cast<void*>(QueryBitmap) },
+    { "nativeGotOrientation",
+"("
+"I"
+"D"
+"D"
+"D"
+")"
+"V", reinterpret_cast<void*>(GotOrientation) },
+  };
+  const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+  if (env->RegisterNatives(g_TestJni_clazz,
+                           kMethodsTestJni,
+                           kMethodsTestJniSize) < 0) {
+    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
+"""
+    self.assertTextEquals(golden_content, h.GetContent())
+
+  def testInnerClassNatives(self):
+    test_data = """
+    class MyInnerClass {
+      @NativeCall("MyInnerClass")
+      private native int nativeInit();
+    }
+    """
+    natives = jni_generator.ExtractNatives(test_data)
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyInnerClass',
+                     type='function')
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [])
+    golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator_tests.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject obj);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetUnscopedClass(env, kTestJniClassPath)));
+  static const JNINativeMethod kMethodsMyInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+  };
+  const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
+
+  if (env->RegisterNatives(g_MyInnerClass_clazz,
+                           kMethodsMyInnerClass,
+                           kMethodsMyInnerClassSize) < 0) {
+    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
+"""
+    self.assertTextEquals(golden_content, h.GetContent())
+
+  def testInnerClassNativesMultiple(self):
+    test_data = """
+    class MyInnerClass {
+      @NativeCall("MyInnerClass")
+      private native int nativeInit();
+    }
+    class MyOtherInnerClass {
+      @NativeCall("MyOtherInnerClass")
+      private native int nativeInit();
+    }
+    """
+    natives = jni_generator.ExtractNatives(test_data)
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyInnerClass',
+                     type='function'),
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyOtherInnerClass',
+                     type='function')
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [])
+    golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator_tests.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kMyOtherInnerClassClassPath[] =
+    "org/chromium/TestJni$MyOtherInnerClass";
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject obj);
+
+static jint Init(JNIEnv* env, jobject obj);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetUnscopedClass(env, kTestJniClassPath)));
+  static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+  };
+  const int kMethodsMyOtherInnerClassSize =
+      arraysize(kMethodsMyOtherInnerClass);
+
+  if (env->RegisterNatives(g_MyOtherInnerClass_clazz,
+                           kMethodsMyOtherInnerClass,
+                           kMethodsMyOtherInnerClassSize) < 0) {
+    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+    return false;
+  }
+
+  static const JNINativeMethod kMethodsMyInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+  };
+  const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
+
+  if (env->RegisterNatives(g_MyInnerClass_clazz,
+                           kMethodsMyInnerClass,
+                           kMethodsMyInnerClassSize) < 0) {
+    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
+"""
+    self.assertTextEquals(golden_content, h.GetContent())
+
+  def testInnerClassNativesBothInnerAndOuter(self):
+    test_data = """
+    class MyOuterClass {
+      private native int nativeInit();
+      class MyOtherInnerClass {
+        @NativeCall("MyOtherInnerClass")
+        private native int nativeInit();
+      }
+    }
+    """
+    natives = jni_generator.ExtractNatives(test_data)
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyOtherInnerClass',
+                     type='function')
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [])
+    golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator_tests.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kMyOtherInnerClassClassPath[] =
+    "org/chromium/TestJni$MyOtherInnerClass";
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject obj);
+
+static jint Init(JNIEnv* env, jobject obj);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetUnscopedClass(env, kTestJniClassPath)));
+  static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+  };
+  const int kMethodsMyOtherInnerClassSize =
+      arraysize(kMethodsMyOtherInnerClass);
+
+  if (env->RegisterNatives(g_MyOtherInnerClass_clazz,
+                           kMethodsMyOtherInnerClass,
+                           kMethodsMyOtherInnerClassSize) < 0) {
+    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+    return false;
+  }
+
+  static const JNINativeMethod kMethodsTestJni[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+  };
+  const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+  if (env->RegisterNatives(g_TestJni_clazz,
+                           kMethodsTestJni,
+                           kMethodsTestJniSize) < 0) {
+    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
+"""
+    self.assertTextEquals(golden_content, h.GetContent())
+
+  def testCalledByNatives(self):
+    test_data = """"
+    import android.graphics.Bitmap;
+    import android.view.View;
+    import java.io.InputStream;
+
+    class InnerClass {}
+
+    @CalledByNative
+    InnerClass showConfirmInfoBar(int nativeInfoBar,
+            String buttonOk, String buttonCancel, String title, Bitmap icon) {
+        InfoBar infobar = new ConfirmInfoBar(nativeInfoBar, mContext,
+                                             buttonOk, buttonCancel,
+                                             title, icon);
+        return infobar;
+    }
+    @CalledByNative
+    InnerClass showAutoLoginInfoBar(int nativeInfoBar,
+            String realm, String account, String args) {
+        AutoLoginInfoBar infobar = new AutoLoginInfoBar(nativeInfoBar, mContext,
+                realm, account, args);
+        if (infobar.displayedAccountCount() == 0)
+            infobar = null;
+        return infobar;
+    }
+    @CalledByNative("InfoBar")
+    void dismiss();
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static boolean shouldShowAutoLogin(View view,
+            String realm, String account, String args) {
+        AccountManagerContainer accountManagerContainer =
+            new AccountManagerContainer((Activity)contentView.getContext(),
+            realm, account, args);
+        String[] logins = accountManagerContainer.getAccountLogins(null);
+        return logins.length != 0;
+    }
+    @CalledByNative
+    static InputStream openUrl(String url) {
+        return null;
+    }
+    @CalledByNative
+    private void activateHardwareAcceleration(final boolean activated,
+            final int iPid, final int iType,
+            final int iPrimaryID, final int iSecondaryID) {
+      if (!activated) {
+          return
+      }
+    }
+    @CalledByNativeUnchecked
+    private void uncheckedCall(int iParam);
+    """
+    jni_generator.JniParams.SetFullyQualifiedClass('org/chromium/Foo')
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+    called_by_natives = jni_generator.ExtractCalledByNatives(test_data)
+    golden_called_by_natives = [
+        CalledByNative(
+            return_type='InnerClass',
+            system_class=False,
+            static=False,
+            name='showConfirmInfoBar',
+            method_id_var_name='showConfirmInfoBar',
+            java_class_name='',
+            params=[Param(datatype='int', name='nativeInfoBar'),
+                    Param(datatype='String', name='buttonOk'),
+                    Param(datatype='String', name='buttonCancel'),
+                    Param(datatype='String', name='title'),
+                    Param(datatype='Bitmap', name='icon')],
+            env_call=('Object', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='InnerClass',
+            system_class=False,
+            static=False,
+            name='showAutoLoginInfoBar',
+            method_id_var_name='showAutoLoginInfoBar',
+            java_class_name='',
+            params=[Param(datatype='int', name='nativeInfoBar'),
+                    Param(datatype='String', name='realm'),
+                    Param(datatype='String', name='account'),
+                    Param(datatype='String', name='args')],
+            env_call=('Object', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='void',
+            system_class=False,
+            static=False,
+            name='dismiss',
+            method_id_var_name='dismiss',
+            java_class_name='InfoBar',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='boolean',
+            system_class=False,
+            static=True,
+            name='shouldShowAutoLogin',
+            method_id_var_name='shouldShowAutoLogin',
+            java_class_name='',
+            params=[Param(datatype='View', name='view'),
+                    Param(datatype='String', name='realm'),
+                    Param(datatype='String', name='account'),
+                    Param(datatype='String', name='args')],
+            env_call=('Boolean', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='InputStream',
+            system_class=False,
+            static=True,
+            name='openUrl',
+            method_id_var_name='openUrl',
+            java_class_name='',
+            params=[Param(datatype='String', name='url')],
+            env_call=('Object', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='void',
+            system_class=False,
+            static=False,
+            name='activateHardwareAcceleration',
+            method_id_var_name='activateHardwareAcceleration',
+            java_class_name='',
+            params=[Param(datatype='boolean', name='activated'),
+                    Param(datatype='int', name='iPid'),
+                    Param(datatype='int', name='iType'),
+                    Param(datatype='int', name='iPrimaryID'),
+                    Param(datatype='int', name='iSecondaryID'),
+                   ],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='void',
+            system_class=False,
+            static=False,
+            name='uncheckedCall',
+            method_id_var_name='uncheckedCall',
+            java_class_name='',
+            params=[Param(datatype='int', name='iParam')],
+            env_call=('Void', ''),
+            unchecked=True,
+        ),
+    ]
+    self.assertListEquals(golden_called_by_natives, called_by_natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             [], called_by_natives)
+    golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator_tests.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+const char kInfoBarClassPath[] = "org/chromium/TestJni$InfoBar";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InfoBar_clazz = NULL;
+}  // namespace
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_TestJni_showConfirmInfoBar = 0;
+static ScopedJavaLocalRef<jobject> Java_TestJni_showConfirmInfoBar(JNIEnv* env,
+    jobject obj, jint nativeInfoBar,
+    jstring buttonOk,
+    jstring buttonCancel,
+    jstring title,
+    jobject icon) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_TestJni_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_TestJni_clazz,
+      "showConfirmInfoBar",
+
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Landroid/graphics/Bitmap;"
+")"
+"Lorg/chromium/Foo$InnerClass;",
+      &g_TestJni_showConfirmInfoBar);
+
+  jobject ret =
+    env->CallObjectMethod(obj,
+      method_id, nativeInfoBar, buttonOk, buttonCancel, title, icon);
+  base::android::CheckException(env);
+  return ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_showAutoLoginInfoBar = 0;
+static ScopedJavaLocalRef<jobject> Java_TestJni_showAutoLoginInfoBar(JNIEnv*
+    env, jobject obj, jint nativeInfoBar,
+    jstring realm,
+    jstring account,
+    jstring args) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_TestJni_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_TestJni_clazz,
+      "showAutoLoginInfoBar",
+
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Lorg/chromium/Foo$InnerClass;",
+      &g_TestJni_showAutoLoginInfoBar);
+
+  jobject ret =
+    env->CallObjectMethod(obj,
+      method_id, nativeInfoBar, realm, account, args);
+  base::android::CheckException(env);
+  return ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_InfoBar_dismiss = 0;
+static void Java_InfoBar_dismiss(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InfoBar_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InfoBar_clazz,
+      "dismiss",
+
+"("
+")"
+"V",
+      &g_InfoBar_dismiss);
+
+  env->CallVoidMethod(obj,
+      method_id);
+  base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_TestJni_shouldShowAutoLogin = 0;
+static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, jobject view,
+    jstring realm,
+    jstring account,
+    jstring args) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_TestJni_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, g_TestJni_clazz,
+      "shouldShowAutoLogin",
+
+"("
+"Landroid/view/View;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Z",
+      &g_TestJni_shouldShowAutoLogin);
+
+  jboolean ret =
+    env->CallStaticBooleanMethod(g_TestJni_clazz,
+      method_id, view, realm, account, args);
+  base::android::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_TestJni_openUrl = 0;
+static ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv* env, jstring
+    url) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_TestJni_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, g_TestJni_clazz,
+      "openUrl",
+
+"("
+"Ljava/lang/String;"
+")"
+"Ljava/io/InputStream;",
+      &g_TestJni_openUrl);
+
+  jobject ret =
+    env->CallStaticObjectMethod(g_TestJni_clazz,
+      method_id, url);
+  base::android::CheckException(env);
+  return ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_activateHardwareAcceleration = 0;
+static void Java_TestJni_activateHardwareAcceleration(JNIEnv* env, jobject obj,
+    jboolean activated,
+    jint iPid,
+    jint iType,
+    jint iPrimaryID,
+    jint iSecondaryID) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_TestJni_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_TestJni_clazz,
+      "activateHardwareAcceleration",
+
+"("
+"Z"
+"I"
+"I"
+"I"
+"I"
+")"
+"V",
+      &g_TestJni_activateHardwareAcceleration);
+
+  env->CallVoidMethod(obj,
+      method_id, activated, iPid, iType, iPrimaryID, iSecondaryID);
+  base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_TestJni_uncheckedCall = 0;
+static void Java_TestJni_uncheckedCall(JNIEnv* env, jobject obj, jint iParam) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_TestJni_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_TestJni_clazz,
+      "uncheckedCall",
+
+"("
+"I"
+")"
+"V",
+      &g_TestJni_uncheckedCall);
+
+  env->CallVoidMethod(obj,
+      method_id, iParam);
+
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetUnscopedClass(env, kTestJniClassPath)));
+  g_InfoBar_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetUnscopedClass(env, kInfoBarClassPath)));
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
+"""
+    self.assertTextEquals(golden_content, h.GetContent())
+
+  def testCalledByNativeParseError(self):
+    try:
+      jni_generator.ExtractCalledByNatives("""
+@CalledByNative
+public static int foo(); // This one is fine
+
+@CalledByNative
+scooby doo
+""")
+      self.fail('Expected a ParseError')
+    except jni_generator.ParseError, e:
+      self.assertEquals(('@CalledByNative', 'scooby doo'), e.context_lines)
+
+  def testFullyQualifiedClassName(self):
+    contents = """
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser;
+
+import org.chromium.base.BuildInfo;
+"""
+    self.assertEquals('org/chromium/content/browser/Foo',
+                      jni_generator.ExtractFullyQualifiedJavaClassName(
+                          'org/chromium/content/browser/Foo.java', contents))
+    self.assertEquals('org/chromium/content/browser/Foo',
+                      jni_generator.ExtractFullyQualifiedJavaClassName(
+                          'frameworks/Foo.java', contents))
+    self.assertRaises(SyntaxError,
+                      jni_generator.ExtractFullyQualifiedJavaClassName,
+                      'com/foo/Bar', 'no PACKAGE line')
+
+  def testMethodNameMangling(self):
+    self.assertEquals('closeV',
+        jni_generator.GetMangledMethodName('close', [], 'void'))
+    self.assertEquals('readI_AB_I_I',
+        jni_generator.GetMangledMethodName('read',
+            [Param(name='p1',
+                   datatype='byte[]'),
+             Param(name='p2',
+                   datatype='int'),
+             Param(name='p3',
+                   datatype='int'),],
+             'int'))
+    self.assertEquals('openJIIS_JLS',
+        jni_generator.GetMangledMethodName('open',
+            [Param(name='p1',
+                   datatype='java/lang/String'),],
+             'java/io/InputStream'))
+
+  def testFromJavaP(self):
+    contents = """
+public abstract class java.io.InputStream extends java.lang.Object
+      implements java.io.Closeable{
+    public java.io.InputStream();
+    public int available()       throws java.io.IOException;
+    public void close()       throws java.io.IOException;
+    public void mark(int);
+    public boolean markSupported();
+    public abstract int read()       throws java.io.IOException;
+    public int read(byte[])       throws java.io.IOException;
+    public int read(byte[], int, int)       throws java.io.IOException;
+    public synchronized void reset()       throws java.io.IOException;
+    public long skip(long)       throws java.io.IOException;
+}
+"""
+    jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), None)
+    self.assertEquals(10, len(jni_from_javap.called_by_natives))
+    golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator_tests.py
+// For
+//     java/io/InputStream
+
+#ifndef java_io_InputStream_JNI
+#define java_io_InputStream_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kInputStreamClassPath[] = "java/io/InputStream";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InputStream_clazz = NULL;
+}  // namespace
+
+namespace JNI_InputStream {
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_InputStream_available = 0;
+static jint Java_InputStream_available(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_InputStream_available(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InputStream_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InputStream_clazz,
+      "available",
+
+"("
+")"
+"I",
+      &g_InputStream_available);
+
+  jint ret =
+    env->CallIntMethod(obj,
+      method_id);
+  base::android::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_close = 0;
+static void Java_InputStream_close(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_InputStream_close(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InputStream_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InputStream_clazz,
+      "close",
+
+"("
+")"
+"V",
+      &g_InputStream_close);
+
+  env->CallVoidMethod(obj,
+      method_id);
+  base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_mark = 0;
+static void Java_InputStream_mark(JNIEnv* env, jobject obj, jint p0)
+    __attribute__ ((unused));
+static void Java_InputStream_mark(JNIEnv* env, jobject obj, jint p0) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InputStream_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InputStream_clazz,
+      "mark",
+
+"("
+"I"
+")"
+"V",
+      &g_InputStream_mark);
+
+  env->CallVoidMethod(obj,
+      method_id, p0);
+  base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_markSupported = 0;
+static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InputStream_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InputStream_clazz,
+      "markSupported",
+
+"("
+")"
+"Z",
+      &g_InputStream_markSupported);
+
+  jboolean ret =
+    env->CallBooleanMethod(obj,
+      method_id);
+  base::android::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI = 0;
+static jint Java_InputStream_readI(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_InputStream_readI(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InputStream_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InputStream_clazz,
+      "read",
+
+"("
+")"
+"I",
+      &g_InputStream_readI);
+
+  jint ret =
+    env->CallIntMethod(obj,
+      method_id);
+  base::android::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI_AB = 0;
+static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0)
+    __attribute__ ((unused));
+static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InputStream_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InputStream_clazz,
+      "read",
+
+"("
+"[B"
+")"
+"I",
+      &g_InputStream_readI_AB);
+
+  jint ret =
+    env->CallIntMethod(obj,
+      method_id, p0);
+  base::android::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI_AB_I_I = 0;
+static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
+    p0,
+    jint p1,
+    jint p2) __attribute__ ((unused));
+static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
+    p0,
+    jint p1,
+    jint p2) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InputStream_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InputStream_clazz,
+      "read",
+
+"("
+"[B"
+"I"
+"I"
+")"
+"I",
+      &g_InputStream_readI_AB_I_I);
+
+  jint ret =
+    env->CallIntMethod(obj,
+      method_id, p0, p1, p2);
+  base::android::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_reset = 0;
+static void Java_InputStream_reset(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_InputStream_reset(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InputStream_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InputStream_clazz,
+      "reset",
+
+"("
+")"
+"V",
+      &g_InputStream_reset);
+
+  env->CallVoidMethod(obj,
+      method_id);
+  base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_skip = 0;
+static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0)
+    __attribute__ ((unused));
+static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InputStream_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InputStream_clazz,
+      "skip",
+
+"("
+"J"
+")"
+"J",
+      &g_InputStream_skip);
+
+  jlong ret =
+    env->CallLongMethod(obj,
+      method_id, p0);
+  base::android::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_Constructor = 0;
+static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env)
+    __attribute__ ((unused));
+static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_InputStream_clazz);
+  jmethodID method_id =
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_InputStream_clazz,
+      "<init>",
+
+"("
+")"
+"V",
+      &g_InputStream_Constructor);
+
+  jobject ret =
+    env->NewObject(g_InputStream_clazz,
+      method_id);
+  base::android::CheckException(env);
+  return ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_InputStream_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetUnscopedClass(env, kInputStreamClassPath)));
+  return true;
+}
+}  // namespace JNI_InputStream
+
+#endif  // java_io_InputStream_JNI
+"""
+    self.assertTextEquals(golden_content, jni_from_javap.GetContent())
+
+  def testREForNatives(self):
+    # We should not match "native SyncSetupFlow" inside the comment.
+    test_data = """
+    /**
+     * Invoked when the setup process is complete so we can disconnect from the
+     * native-side SyncSetupFlowHandler.
+     */
+    public void destroy() {
+        Log.v(TAG, "Destroying native SyncSetupFlow");
+        if (mNativeSyncSetupFlow != 0) {
+            nativeSyncSetupEnded(mNativeSyncSetupFlow);
+            mNativeSyncSetupFlow = 0;
+        }
+    }
+    private native void nativeSyncSetupEnded(
+        int nativeAndroidSyncSetupFlowHandler);
+    """
+    jni_from_java = jni_generator.JNIFromJavaSource(test_data, 'foo/bar')
+
+  def testRaisesOnNonJNIMethod(self):
+    test_data = """
+    class MyInnerClass {
+      private int Foo(int p0) {
+      }
+    }
+    """
+    self.assertRaises(SyntaxError,
+                      jni_generator.JNIFromJavaSource,
+                      test_data, 'foo/bar')
+
+  def testJniSelfDocumentingExample(self):
+    script_dir = os.path.dirname(sys.argv[0])
+    content = file(os.path.join(script_dir, 'SampleForTests.java')).read()
+    golden_content = file(os.path.join(script_dir,
+                                       'golden_sample_for_tests_jni.h')).read()
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        content, 'org/chromium/example/jni_generator/SampleForTests')
+    self.assertTextEquals(golden_content, jni_from_java.GetContent())
+
+  def testNoWrappingPreprocessorLines(self):
+    test_data = """
+    package com.google.lookhowextremelylongiam.snarf.icankeepthisupallday;
+
+    class ReallyLongClassNamesAreAllTheRage {
+        private static native int nativeTest();
+    }
+    """
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, ('com/google/lookhowextremelylongiam/snarf/'
+                    'icankeepthisupallday/ReallyLongClassNamesAreAllTheRage'))
+    jni_lines = jni_from_java.GetContent().split('\n')
+    line = filter(lambda line: line.lstrip().startswith('#ifndef'),
+                  jni_lines)[0]
+    self.assertTrue(len(line) > 80,
+                    ('Expected #ifndef line to be > 80 chars: ', line))
+
+  def testImports(self):
+    import_header = """
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.app;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Surface;
+
+import java.util.ArrayList;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.content.app.ContentMain;
+import org.chromium.content.browser.SandboxedProcessConnection;
+import org.chromium.content.common.ISandboxedProcessCallback;
+import org.chromium.content.common.ISandboxedProcessService;
+import org.chromium.content.common.SurfaceCallback;
+
+import static org.chromium.Bar.Zoo;
+
+class Foo {
+  public static class BookmarkNode implements Parcelable {
+  }
+  public interface PasswordListObserver {
+  }
+}
+    """
+    jni_generator.JniParams.SetFullyQualifiedClass(
+        'org/chromium/content/app/Foo')
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(import_header)
+    self.assertTrue('Lorg/chromium/content/common/ISandboxedProcessService' in
+                    jni_generator.JniParams._imports)
+    self.assertTrue('Lorg/chromium/Bar/Zoo' in
+                    jni_generator.JniParams._imports)
+    self.assertTrue('Lorg/chromium/content/app/Foo$BookmarkNode' in
+                    jni_generator.JniParams._inner_classes)
+    self.assertTrue('Lorg/chromium/content/app/Foo$PasswordListObserver' in
+                    jni_generator.JniParams._inner_classes)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/base/android/jni_generator/sample_for_tests.cc b/base/android/jni_generator/sample_for_tests.cc
new file mode 100644
index 0000000..5b5cfc5
--- /dev/null
+++ b/base/android/jni_generator/sample_for_tests.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/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+
+// The main purpose of this is to ensure sample_for_tests_jni.h
+// compiles and the functions declared in it as expected.
+
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
+
+namespace base {
+namespace android {
+
+class CPPClass {
+ public:
+  class InnerClass {
+   public:
+    jdouble MethodOtherP0(JNIEnv* env, jobject obj) {
+      return 0.0;
+    }
+  };
+
+  void Destroy(JNIEnv* env, jobject obj) {
+    delete this;
+  }
+
+  jint Method(JNIEnv* env, jobject obj) {
+    return 0;
+  }
+
+  ScopedJavaLocalRef<jstring> InnerMethod(JNIEnv* env, jobject obj) {
+    return ScopedJavaLocalRef<jstring>();
+  }
+};
+
+static jint Init(JNIEnv* env, jobject obj) {
+  return 0;
+}
+
+static jdouble GetDoubleFunction(JNIEnv*, jobject) {
+  return 0;
+}
+
+static jfloat GetFloatFunction(JNIEnv*, jclass) {
+  return 0;
+}
+
+static void SetNonPODDatatype(JNIEnv*, jobject, jobject) {}
+
+static jobject GetNonPODDatatype(JNIEnv*, jobject) {
+  return NULL;
+}
+
+static jint InnerFunction(JNIEnv*, jclass) {
+  return 0;
+}
+
+} // namespace android
+} // namespace base
+
+#include "jni/SampleForTests_jni.h"
+
+int main() {
+  // On a regular application, you'd call AttachCurrentThread(). This sample is
+  // not yet linking with all the libraries.
+  JNIEnv* env = /* AttachCurrentThread() */ NULL;
+
+  // This is how you call a java static method from C++.
+  bool foo = base::android::Java_SampleForTests_staticJavaMethod(env);
+
+  // This is how you call a java method from C++. Note that you must have
+  // obtained the jobject somehow.
+  jobject my_java_object = NULL;
+  int bar = base::android::Java_SampleForTests_javaMethod(
+      env, my_java_object, 1, 2);
+
+  return 0;
+}
diff --git a/base/android/jni_helper.cc b/base/android/jni_helper.cc
new file mode 100644
index 0000000..c0833c9
--- /dev/null
+++ b/base/android/jni_helper.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/android/jni_helper.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+
+using base::android::AttachCurrentThread;
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef()
+  : obj_(NULL) {
+}
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(
+    const JavaObjectWeakGlobalRef& orig) {
+  Assign(orig);
+}
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj)
+    : obj_(env->NewWeakGlobalRef(obj)) {
+  DCHECK(obj_);
+}
+
+JavaObjectWeakGlobalRef::~JavaObjectWeakGlobalRef() {
+  reset();
+}
+
+void JavaObjectWeakGlobalRef::operator=(const JavaObjectWeakGlobalRef& rhs) {
+  Assign(rhs);
+}
+
+void JavaObjectWeakGlobalRef::reset() {
+  if (obj_) {
+    AttachCurrentThread()->DeleteWeakGlobalRef(obj_);
+    obj_ = NULL;
+  }
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+    JavaObjectWeakGlobalRef::get(JNIEnv* env) const {
+  return GetRealObject(env, obj_);
+}
+
+base::android::ScopedJavaLocalRef<jobject> GetRealObject(
+    JNIEnv* env, jweak obj) {
+  jobject real = NULL;
+  if (obj) {
+    real = env->NewLocalRef(obj);
+    if (!real)
+      DLOG(ERROR) << "The real object has been deleted!";
+  }
+  return base::android::ScopedJavaLocalRef<jobject>(env, real);
+}
+
+void JavaObjectWeakGlobalRef::Assign(const JavaObjectWeakGlobalRef& other) {
+  JNIEnv* env = AttachCurrentThread();
+  obj_ = env->NewWeakGlobalRef(other.obj_);
+}
diff --git a/base/android/jni_helper.h b/base/android/jni_helper.h
new file mode 100644
index 0000000..895bf95
--- /dev/null
+++ b/base/android/jni_helper.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_ANDROID_JNI_HELPER_H_
+#define BASE_ANDROID_JNI_HELPER_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+#include "base/android/scoped_java_ref.h"
+
+// Manages WeakGlobalRef lifecycle.
+// This class is not thread-safe w.r.t. get() and reset(). Multiple threads may
+// safely use get() concurrently, but if the user calls reset() (or of course,
+// calls the destructor) they'll need to provide their own synchronization.
+class BASE_EXPORT JavaObjectWeakGlobalRef {
+ public:
+  JavaObjectWeakGlobalRef();
+  JavaObjectWeakGlobalRef(const JavaObjectWeakGlobalRef& orig);
+  JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj);
+  virtual ~JavaObjectWeakGlobalRef();
+
+  void operator=(const JavaObjectWeakGlobalRef& rhs);
+
+  base::android::ScopedJavaLocalRef<jobject> get(JNIEnv* env) const;
+
+  void reset();
+
+ private:
+  void Assign(const JavaObjectWeakGlobalRef& rhs);
+
+  jweak obj_;
+};
+
+// Get the real object stored in the weak reference returned as a
+// ScopedJavaLocalRef.
+BASE_EXPORT base::android::ScopedJavaLocalRef<jobject> GetRealObject(
+    JNIEnv* env, jweak obj);
+
+#endif  // BASE_ANDROID_JNI_HELPER_H_
diff --git a/base/android/jni_registrar.cc b/base/android/jni_registrar.cc
new file mode 100644
index 0000000..696924a
--- /dev/null
+++ b/base/android/jni_registrar.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/android/jni_registrar.h"
+
+#include "base/logging.h"
+#include "base/android/jni_android.h"
+
+namespace base {
+namespace android {
+
+bool RegisterNativeMethods(JNIEnv* env,
+                           const RegistrationMethod* method,
+                           size_t count) {
+  const RegistrationMethod* end = method + count;
+  while (method != end) {
+    if (!method->func(env) < 0) {
+      DLOG(ERROR) << method->name << " failed registration!";
+      return false;
+    }
+    method++;
+  }
+  return true;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_registrar.h b/base/android/jni_registrar.h
new file mode 100644
index 0000000..849d07f
--- /dev/null
+++ b/base/android/jni_registrar.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_REGISTRAR_H_
+#define BASE_ANDROID_JNI_REGISTRAR_H_
+
+#include <jni.h>
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace android {
+
+struct RegistrationMethod;
+
+// Registers the JNI bindings for the specified |method| definition containing
+// |count| elements.  Returns whether the registration of the given methods
+// succeeded.
+BASE_EXPORT bool RegisterNativeMethods(JNIEnv* env,
+                                       const RegistrationMethod* method,
+                                       size_t count);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_REGISTRAR_H_
diff --git a/base/android/jni_string.cc b/base/android/jni_string.cc
new file mode 100644
index 0000000..b830ddb
--- /dev/null
+++ b/base/android/jni_string.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+
+namespace {
+
+// Internal version that does not use a scoped local pointer.
+jstring ConvertUTF16ToJavaStringImpl(JNIEnv* env,
+                                     const base::StringPiece16& str) {
+  jstring result = env->NewString(str.data(), str.length());
+  base::android::CheckException(env);
+  return result;
+}
+
+}
+
+namespace base {
+namespace android {
+
+std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) {
+  // JNI's GetStringUTFChars() returns strings in Java-modified UTF8, so we
+  // instead get the String in UTF16 and convert using our own utility function.
+  return UTF16ToUTF8(ConvertJavaStringToUTF16(env, str));
+}
+
+std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str) {
+  return ConvertJavaStringToUTF8(AttachCurrentThread(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece& str) {
+  // JNI's NewStringUTF expects "modified" UTF8 so instead create the string
+  // via our own UTF16 conversion utility.
+  // Further, Dalvik requires the string passed into NewStringUTF() to come from
+  // a trusted source. We can't guarantee that all UTF8 will be sanitized before
+  // it gets here, so constructing via UTF16 side-steps this issue.
+  // (Dalvik stores strings internally as UTF16 anyway, so there shouldn't be
+  // a significant performance hit by doing it this way).
+  return ScopedJavaLocalRef<jstring>(env, ConvertUTF16ToJavaStringImpl(
+      env, UTF8ToUTF16(str)));
+}
+
+string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) {
+  if (!str) {
+    LOG(WARNING) << " ConvertJavaStringToUTF16 called with null string.";
+    return string16();
+  }
+  const jchar* chars = env->GetStringChars(str, NULL);
+  DCHECK(chars);
+  // GetStringChars isn't required to NULL-terminate the strings
+  // it returns, so the length must be explicitly checked.
+  string16 result(chars, env->GetStringLength(str));
+  env->ReleaseStringChars(str, chars);
+  CheckException(env);
+  return result;
+}
+
+string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str) {
+  return ConvertJavaStringToUTF16(AttachCurrentThread(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece16& str) {
+  return ScopedJavaLocalRef<jstring>(env,
+                                     ConvertUTF16ToJavaStringImpl(env, str));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_string.h b/base/android/jni_string.h
new file mode 100644
index 0000000..62c4d02
--- /dev/null
+++ b/base/android/jni_string.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_ANDROID_JNI_STRING_H_
+#define BASE_ANDROID_JNI_STRING_H_
+
+#include <jni.h>
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+#include "base/string_piece.h"
+
+namespace base {
+namespace android {
+
+// Convert a Java string to UTF8. Returns a std string.
+BASE_EXPORT std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str);
+BASE_EXPORT std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str);
+
+// Convert a std string to Java string.
+BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece& str);
+
+// Convert a Java string to UTF16. Returns a string16.
+BASE_EXPORT string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str);
+BASE_EXPORT string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str);
+
+// Convert a string16 to a Java string.
+BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece16& str);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_STRING_H_
diff --git a/base/android/locale_utils.cc b/base/android/locale_utils.cc
new file mode 100644
index 0000000..60b8f84
--- /dev/null
+++ b/base/android/locale_utils.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/android/locale_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "jni/LocaleUtils_jni.h"
+#include "unicode/uloc.h"
+
+namespace base {
+namespace android {
+
+std::string GetDefaultLocale() {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> locale = Java_LocaleUtils_getDefaultLocale(env);
+  return ConvertJavaStringToUTF8(locale);
+}
+
+namespace {
+
+// Common prototype of ICU uloc_getXXX() functions.
+typedef int32_t (*UlocGetComponentFunc)(const char*, char*, int32_t,
+                                        UErrorCode*);
+
+std::string GetLocaleComponent(const std::string& locale,
+                               UlocGetComponentFunc uloc_func,
+                               int32_t max_capacity) {
+  std::string result;
+  UErrorCode error = U_ZERO_ERROR;
+  int32_t actual_length = uloc_func(locale.c_str(),
+                                    WriteInto(&result, max_capacity),
+                                    max_capacity,
+                                    &error);
+  DCHECK(U_SUCCESS(error));
+  DCHECK(actual_length < max_capacity);
+  result.resize(actual_length);
+  return result;
+}
+
+ScopedJavaLocalRef<jobject> NewJavaLocale(
+    JNIEnv* env,
+    ScopedJavaLocalRef<jclass> locale_class,
+    jmethodID constructor_id,
+    const std::string& locale) {
+  // TODO(wangxianzhu): Use new Locale API once Android supports scripts.
+  std::string language = GetLocaleComponent(
+      locale, uloc_getLanguage, ULOC_LANG_CAPACITY);
+  std::string country = GetLocaleComponent(
+      locale, uloc_getCountry, ULOC_COUNTRY_CAPACITY);
+  std::string variant = GetLocaleComponent(
+      locale, uloc_getVariant, ULOC_FULLNAME_CAPACITY);
+  return ScopedJavaLocalRef<jobject>(
+      env, env->NewObject(
+          locale_class.obj(), constructor_id,
+          ConvertUTF8ToJavaString(env, language).obj(),
+          ConvertUTF8ToJavaString(env, country).obj(),
+          ConvertUTF8ToJavaString(env, variant).obj()));
+}
+
+}  // namespace
+
+string16 GetDisplayNameForLocale(const std::string& locale,
+                                 const std::string& display_locale) {
+  JNIEnv* env = AttachCurrentThread();
+
+  ScopedJavaLocalRef<jclass> locale_class = GetClass(env, "java/util/Locale");
+  jmethodID constructor_id = MethodID::Get<MethodID::TYPE_INSTANCE>(
+      env, locale_class.obj(), "<init>",
+      "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+  ScopedJavaLocalRef<jobject> java_locale = NewJavaLocale(
+      env, locale_class, constructor_id, locale);
+  ScopedJavaLocalRef<jobject> java_display_locale = NewJavaLocale(
+      env, locale_class, constructor_id, display_locale);
+
+  jmethodID method_id = MethodID::Get<MethodID::TYPE_INSTANCE>(
+      env, locale_class.obj(), "getDisplayName",
+      "(Ljava/util/Locale;)Ljava/lang/String;");
+  ScopedJavaLocalRef<jstring> java_result(
+      env,
+      static_cast<jstring>(env->CallObjectMethod(java_locale.obj(), method_id,
+                                                 java_display_locale.obj())));
+  return ConvertJavaStringToUTF16(java_result);
+}
+
+bool RegisterLocaleUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/locale_utils.h b/base/android/locale_utils.h
new file mode 100644
index 0000000..cef39f4
--- /dev/null
+++ b/base/android/locale_utils.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_ANDROID_LOCALE_UTILS_H_
+#define BASE_ANDROID_LOCALE_UTILS_H_
+
+#include <jni.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/string16.h"
+
+namespace base {
+namespace android {
+
+// Return the current default locale of the device.
+BASE_EXPORT std::string GetDefaultLocale();
+
+BASE_EXPORT string16 GetDisplayNameForLocale(const std::string& locale,
+                                 const std::string& display_locale);
+
+bool RegisterLocaleUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_LOCALE_UTILS_H_
diff --git a/base/android/path_service_android.cc b/base/android/path_service_android.cc
new file mode 100644
index 0000000..a9bf92d
--- /dev/null
+++ b/base/android/path_service_android.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/path_service_android.h"
+
+#include "base/file_path.h"
+#include "base/path_service.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "jni/PathService_jni.h"
+
+namespace base {
+namespace android {
+
+void Override(JNIEnv* env, jclass clazz, jint what, jstring path) {
+  FilePath file_path(ConvertJavaStringToUTF8(env, path));
+  PathService::Override(what, file_path);
+}
+
+bool RegisterPathService(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/path_service_android.h b/base/android/path_service_android.h
new file mode 100644
index 0000000..26040f9
--- /dev/null
+++ b/base/android/path_service_android.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_PATH_SERVICE_ANDROID_H_
+#define BASE_ANDROID_PATH_SERVICE_ANDROID_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterPathService(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_PATH_SERVICE_ANDROID_H_
diff --git a/base/android/path_utils.cc b/base/android/path_utils.cc
new file mode 100644
index 0000000..3d86177
--- /dev/null
+++ b/base/android/path_utils.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/android/path_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/file_path.h"
+
+#include "jni/PathUtils_jni.h"
+
+namespace base {
+namespace android {
+
+bool GetDataDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getDataDirectory(env, GetApplicationContext());
+  FilePath data_path(ConvertJavaStringToUTF8(path));
+  *result = data_path;
+  return true;
+}
+
+bool GetCacheDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getCacheDirectory(env, GetApplicationContext());
+  FilePath cache_path(ConvertJavaStringToUTF8(path));
+  *result = cache_path;
+  return true;
+}
+
+bool GetDownloadsDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getDownloadsDirectory(env, GetApplicationContext());
+  FilePath downloads_path(ConvertJavaStringToUTF8(path));
+  *result = downloads_path;
+  return true;
+}
+
+bool GetNativeLibraryDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getNativeLibraryDirectory(env, GetApplicationContext());
+  FilePath library_path(ConvertJavaStringToUTF8(path));
+  *result = library_path;
+  return true;
+}
+
+bool GetExternalStorageDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getExternalStorageDirectory(env);
+  FilePath storage_path(ConvertJavaStringToUTF8(path));
+  *result = storage_path;
+  return true;
+}
+
+bool RegisterPathUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/path_utils.h b/base/android/path_utils.h
new file mode 100644
index 0000000..0d95cd3
--- /dev/null
+++ b/base/android/path_utils.h
@@ -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.
+
+#ifndef BASE_ANDROID_PATH_UTILS_H_
+#define BASE_ANDROID_PATH_UTILS_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+class FilePath;
+
+namespace base {
+namespace android {
+
+// Retrieves the absolute path to the data directory of the current
+// application. The result is placed in the FilePath pointed to by 'result'.
+// This method is dedicated for base_paths_android.c, Using
+// PathService::Get(base::DIR_ANDROID_APP_DATA, ...) gets the data dir.
+BASE_EXPORT bool GetDataDirectory(FilePath* result);
+
+// Retrieves the absolute path to the cache directory. The result is placed in
+// the FilePath pointed to by 'result'. This method is dedicated for
+// base_paths_android.c, Using PathService::Get(base::DIR_CACHE, ...) gets the
+// cache dir.
+BASE_EXPORT bool GetCacheDirectory(FilePath* result);
+
+// Retrieves the path to the public downloads directory. The result is placed
+// in the FilePath pointed to by 'result'.
+bool GetDownloadsDirectory(FilePath* result);
+
+// Retrieves the path to the native JNI libraries via
+// ApplicationInfo.nativeLibraryDir on the Java side. The result is placed in
+// the FilePath pointed to by 'result'.
+bool GetNativeLibraryDirectory(FilePath* result);
+
+// Retrieves the absolute path to the external storage directory. The result
+// is placed in the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetExternalStorageDirectory(FilePath* result);
+
+bool RegisterPathUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_PATH_UTILS_H_
diff --git a/base/android/path_utils_unittest.cc b/base/android/path_utils_unittest.cc
new file mode 100644
index 0000000..92728b5
--- /dev/null
+++ b/base/android/path_utils_unittest.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/android/path_utils.h"
+#include "base/file_path.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+typedef testing::Test PathUtilsTest;
+
+TEST_F(PathUtilsTest, TestGetDataDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that we are packaged in
+  // org.chromium.native_test
+  FilePath path;
+  GetDataDirectory(&path);
+  EXPECT_STREQ("/data/data/org.chromium.native_test/app_chrome",
+               path.value().c_str());
+}
+
+TEST_F(PathUtilsTest, TestGetCacheDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that we are packaged in
+  // org.chromium.native_test
+  FilePath path;
+  GetCacheDirectory(&path);
+  EXPECT_STREQ("/data/data/org.chromium.native_test/cache",
+               path.value().c_str());
+}
+
+TEST_F(PathUtilsTest, TestGetNativeLibraryDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that we are packaged in
+  // org.chromium.native_test
+  FilePath path;
+  GetNativeLibraryDirectory(&path);
+  EXPECT_STREQ("/data/data/org.chromium.native_test/lib",
+               path.value().c_str());
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/scoped_java_ref.cc b/base/android/scoped_java_ref.cc
new file mode 100644
index 0000000..21b466e
--- /dev/null
+++ b/base/android/scoped_java_ref.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/scoped_java_ref.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+
+namespace base {
+namespace android {
+
+JavaRef<jobject>::JavaRef() : obj_(NULL) {}
+
+JavaRef<jobject>::JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {
+  if (obj) {
+    DCHECK(env && env->GetObjectRefType(obj) == JNILocalRefType);
+  }
+}
+
+JavaRef<jobject>::~JavaRef() {
+}
+
+JNIEnv* JavaRef<jobject>::SetNewLocalRef(JNIEnv* env, jobject obj) {
+  if (!env) {
+    env = AttachCurrentThread();
+  } else {
+    DCHECK_EQ(env, AttachCurrentThread());  // Is |env| on correct thread.
+  }
+  if (obj)
+    obj = env->NewLocalRef(obj);
+  if (obj_)
+    env->DeleteLocalRef(obj_);
+  obj_ = obj;
+  return env;
+}
+
+void JavaRef<jobject>::SetNewGlobalRef(JNIEnv* env, jobject obj) {
+  if (!env) {
+    env = AttachCurrentThread();
+  } else {
+    DCHECK_EQ(env, AttachCurrentThread());  // Is |env| on correct thread.
+  }
+  if (obj)
+    obj = env->NewGlobalRef(obj);
+  if (obj_)
+    env->DeleteGlobalRef(obj_);
+  obj_ = obj;
+}
+
+void JavaRef<jobject>::ResetLocalRef(JNIEnv* env) {
+  if (obj_) {
+    DCHECK_EQ(env, AttachCurrentThread());  // Is |env| on correct thread.
+    env->DeleteLocalRef(obj_);
+    obj_ = NULL;
+  }
+}
+
+void JavaRef<jobject>::ResetGlobalRef() {
+  if (obj_) {
+    AttachCurrentThread()->DeleteGlobalRef(obj_);
+    obj_ = NULL;
+  }
+}
+
+jobject JavaRef<jobject>::ReleaseInternal() {
+  jobject obj = obj_;
+  obj_ = NULL;
+  return obj;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h
new file mode 100644
index 0000000..a5d71e2
--- /dev/null
+++ b/base/android/scoped_java_ref.h
@@ -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.
+
+#ifndef BASE_ANDROID_SCOPED_JAVA_REF_H_
+#define BASE_ANDROID_SCOPED_JAVA_REF_H_
+
+#include <jni.h>
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace android {
+
+// Forward declare the generic java reference template class.
+template<typename T> class JavaRef;
+
+// Template specialization of JavaRef, which acts as the base class for all
+// other JavaRef<> template types. This allows you to e.g. pass
+// ScopedJavaLocalRef<jstring> into a function taking const JavaRef<jobject>&
+template<>
+class BASE_EXPORT JavaRef<jobject> {
+ public:
+  jobject obj() const { return obj_; }
+
+  bool is_null() const { return obj_ == NULL; }
+
+ protected:
+  // Initializes a NULL reference.
+  JavaRef();
+
+  // Takes ownership of the |obj| reference passed; requires it to be a local
+  // reference type.
+  JavaRef(JNIEnv* env, jobject obj);
+
+  ~JavaRef();
+
+  // The following are implementation detail convenience methods, for
+  // use by the sub-classes.
+  JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj);
+  void SetNewGlobalRef(JNIEnv* env, jobject obj);
+  void ResetLocalRef(JNIEnv* env);
+  void ResetGlobalRef();
+  jobject ReleaseInternal();
+
+ private:
+  jobject obj_;
+
+  DISALLOW_COPY_AND_ASSIGN(JavaRef);
+};
+
+// Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful
+// for allowing functions to accept a reference without having to mandate
+// whether it is a local or global type.
+template<typename T>
+class JavaRef : public JavaRef<jobject> {
+ public:
+  T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); }
+
+ protected:
+  JavaRef() {}
+  ~JavaRef() {}
+
+  JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(JavaRef);
+};
+
+// Holds a local reference to a Java object. The local reference is scoped
+// to the lifetime of this object.
+// Instances of this class may hold onto any JNIEnv passed into it until
+// destroyed. Therefore, since a JNIEnv is only suitable for use on a single
+// thread, objects of this class must be created, used, and destroyed, on a
+// single thread.
+// Therefore, this class should only be used as a stack-based object and from a
+// single thread. If you wish to have the reference outlive the current
+// callstack (e.g. as a class member) or you wish to pass it across threads,
+// use a ScopedJavaGlobalRef instead.
+template<typename T>
+class ScopedJavaLocalRef : public JavaRef<T> {
+ public:
+  ScopedJavaLocalRef() : env_(NULL) {}
+
+  // Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned
+  // by value as this is the normal usage pattern.
+  ScopedJavaLocalRef(const ScopedJavaLocalRef<T>& other)
+      : env_(other.env_) {
+    this->SetNewLocalRef(env_, other.obj());
+  }
+
+  template<typename U>
+  explicit ScopedJavaLocalRef(const U& other)
+      : env_(NULL) {
+    this->Reset(other);
+  }
+
+  // Assumes that |obj| is a local reference to a Java object and takes
+  // ownership  of this local reference.
+  ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj), env_(env) {}
+
+  ~ScopedJavaLocalRef() {
+    this->Reset();
+  }
+
+  // Overloaded assignment operator defined for consistency with the implicit
+  // copy constructor.
+  void operator=(const ScopedJavaLocalRef<T>& other) {
+    this->Reset(other);
+  }
+
+  void Reset() {
+    this->ResetLocalRef(env_);
+  }
+
+  template<typename U>
+  void Reset(const ScopedJavaLocalRef<U>& other) {
+    // We can copy over env_ here as |other| instance must be from the same
+    // thread as |this| local ref. (See class comment for multi-threading
+    // limitations, and alternatives).
+    this->Reset(other.env_, other.obj());
+  }
+
+  template<typename U>
+  void Reset(const U& other) {
+    // If |env_| was not yet set (is still NULL) it will be attached to the
+    // current thread in SetNewLocalRef().
+    this->Reset(env_, other.obj());
+  }
+
+  template<typename U>
+  void Reset(JNIEnv* env, U obj) {
+    implicit_cast<T>(obj);  // Ensure U is assignable to T
+    env_ = this->SetNewLocalRef(env, obj);
+  }
+
+  // Releases the local reference to the caller. The caller *must* delete the
+  // local reference when it is done with it.
+  T Release() {
+    return static_cast<T>(this->ReleaseInternal());
+  }
+
+ private:
+  // This class is only good for use on the thread it was created on so
+  // it's safe to cache the non-threadsafe JNIEnv* inside this object.
+  JNIEnv* env_;
+};
+
+// Holds a global reference to a Java object. The global reference is scoped
+// to the lifetime of this object. This class does not hold onto any JNIEnv*
+// passed to it, hence it is safe to use across threads (within the constraints
+// imposed by the underlying Java object that it references).
+template<typename T>
+class ScopedJavaGlobalRef : public JavaRef<T> {
+ public:
+  ScopedJavaGlobalRef() {}
+
+  explicit ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) {
+    this->Reset(other);
+  }
+
+  template<typename U>
+  explicit ScopedJavaGlobalRef(const U& other) {
+    this->Reset(other);
+  }
+
+  ~ScopedJavaGlobalRef() {
+    this->Reset();
+  }
+
+  void Reset() {
+    this->ResetGlobalRef();
+  }
+
+  template<typename U>
+  void Reset(const U& other) {
+    this->Reset(NULL, other.obj());
+  }
+
+  template<typename U>
+  void Reset(JNIEnv* env, U obj) {
+    implicit_cast<T>(obj);  // Ensure U is assignable to T
+    this->SetNewGlobalRef(env, obj);
+  }
+
+  // Releases the global reference to the caller. The caller *must* delete the
+  // global reference when it is done with it.
+  T Release() {
+    return static_cast<T>(this->ReleaseInternal());
+  }
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_SCOPED_JAVA_REF_H_
diff --git a/base/android/scoped_java_ref_unittest.cc b/base/android/scoped_java_ref_unittest.cc
new file mode 100644
index 0000000..36f253c
--- /dev/null
+++ b/base/android/scoped_java_ref_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/scoped_java_ref.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+int g_local_refs = 0;
+int g_global_refs = 0;
+
+const JNINativeInterface* g_previous_functions;
+
+jobject NewGlobalRef(JNIEnv* env, jobject obj) {
+  ++g_global_refs;
+  return g_previous_functions->NewGlobalRef(env, obj);
+}
+
+void DeleteGlobalRef(JNIEnv* env, jobject obj) {
+  --g_global_refs;
+  return g_previous_functions->DeleteGlobalRef(env, obj);
+}
+
+jobject NewLocalRef(JNIEnv* env, jobject obj) {
+  ++g_local_refs;
+  return g_previous_functions->NewLocalRef(env, obj);
+}
+
+void DeleteLocalRef(JNIEnv* env, jobject obj) {
+  --g_local_refs;
+  return g_previous_functions->DeleteLocalRef(env, obj);
+}
+}  // namespace
+
+class ScopedJavaRefTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    g_local_refs = 0;
+    g_global_refs = 0;
+    JNIEnv* env = AttachCurrentThread();
+    g_previous_functions = env->functions;
+    hooked_functions = *g_previous_functions;
+    env->functions = &hooked_functions;
+    // We inject our own functions in JNINativeInterface so we can keep track
+    // of the reference counting ourselves.
+    hooked_functions.NewGlobalRef = &NewGlobalRef;
+    hooked_functions.DeleteGlobalRef = &DeleteGlobalRef;
+    hooked_functions.NewLocalRef = &NewLocalRef;
+    hooked_functions.DeleteLocalRef = &DeleteLocalRef;
+  }
+
+  virtual void TearDown() {
+    JNIEnv* env = AttachCurrentThread();
+    env->functions = g_previous_functions;
+  }
+  // From JellyBean release, the instance of this struct provided in JNIEnv is
+  // read-only, so we deep copy it to allow individual functions to be hooked.
+  JNINativeInterface hooked_functions;
+};
+
+// The main purpose of this is testing the various conversions compile.
+TEST_F(ScopedJavaRefTest, Conversions) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, "string");
+  ScopedJavaGlobalRef<jstring> global(str);
+  {
+    ScopedJavaGlobalRef<jobject> global_obj(str);
+    ScopedJavaLocalRef<jobject> local_obj(global);
+    const JavaRef<jobject>& obj_ref1(str);
+    const JavaRef<jobject>& obj_ref2(global);
+    EXPECT_TRUE(env->IsSameObject(obj_ref1.obj(), obj_ref2.obj()));
+    EXPECT_TRUE(env->IsSameObject(global_obj.obj(), obj_ref2.obj()));
+  }
+  global.Reset(str);
+  const JavaRef<jstring>& str_ref = str;
+  EXPECT_EQ("string", ConvertJavaStringToUTF8(str_ref));
+  str.Reset();
+}
+
+TEST_F(ScopedJavaRefTest, RefCounts) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> str;
+  // The ConvertJavaStringToUTF8 below creates a new string that would normally
+  // return a local ref. We simulate that by starting the g_local_refs count at
+  // 1.
+  g_local_refs = 1;
+  str.Reset(ConvertUTF8ToJavaString(env, "string"));
+  EXPECT_EQ(1, g_local_refs);
+  EXPECT_EQ(0, g_global_refs);
+  {
+    ScopedJavaGlobalRef<jstring> global_str(str);
+    ScopedJavaGlobalRef<jobject> global_obj(global_str);
+    EXPECT_EQ(1, g_local_refs);
+    EXPECT_EQ(2, g_global_refs);
+
+    ScopedJavaLocalRef<jstring> str2(env, str.Release());
+    EXPECT_EQ(1, g_local_refs);
+    {
+      ScopedJavaLocalRef<jstring> str3(str2);
+      EXPECT_EQ(2, g_local_refs);
+    }
+    EXPECT_EQ(1, g_local_refs);
+    str2.Reset();
+    EXPECT_EQ(0, g_local_refs);
+    global_str.Reset();
+    EXPECT_EQ(1, g_global_refs);
+    ScopedJavaGlobalRef<jobject> global_obj2(global_obj);
+    EXPECT_EQ(2, g_global_refs);
+  }
+
+  EXPECT_EQ(0, g_local_refs);
+  EXPECT_EQ(0, g_global_refs);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/at_exit.cc b/base/at_exit.cc
new file mode 100644
index 0000000..0fba355
--- /dev/null
+++ b/base/at_exit.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+
+#include <stddef.h>
+#include <ostream>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+
+namespace base {
+
+// Keep a stack of registered AtExitManagers.  We always operate on the most
+// recent, and we should never have more than one outside of testing (for a
+// statically linked version of this library).  Testing may use the shadow
+// version of the constructor, and if we are building a dynamic library we may
+// end up with multiple AtExitManagers on the same process.  We don't protect
+// this for thread-safe access, since it will only be modified in testing.
+static AtExitManager* g_top_manager = NULL;
+
+AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
+// If multiple modules instantiate AtExitManagers they'll end up living in this
+// module... they have to coexist.
+#if !defined(COMPONENT_BUILD)
+  DCHECK(!g_top_manager);
+#endif
+  g_top_manager = this;
+}
+
+AtExitManager::~AtExitManager() {
+  if (!g_top_manager) {
+    NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
+    return;
+  }
+  DCHECK_EQ(this, g_top_manager);
+
+  ProcessCallbacksNow();
+  g_top_manager = next_manager_;
+}
+
+// static
+void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
+  DCHECK(func);
+  RegisterTask(base::Bind(func, param));
+}
+
+// static
+void AtExitManager::RegisterTask(base::Closure task) {
+  if (!g_top_manager) {
+    NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
+    return;
+  }
+
+  AutoLock lock(g_top_manager->lock_);
+  g_top_manager->stack_.push(task);
+}
+
+// static
+void AtExitManager::ProcessCallbacksNow() {
+  if (!g_top_manager) {
+    NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
+    return;
+  }
+
+  AutoLock lock(g_top_manager->lock_);
+
+  while (!g_top_manager->stack_.empty()) {
+    base::Closure task = g_top_manager->stack_.top();
+    task.Run();
+    g_top_manager->stack_.pop();
+  }
+}
+
+AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
+  DCHECK(shadow || !g_top_manager);
+  g_top_manager = this;
+}
+
+}  // namespace base
diff --git a/base/at_exit.h b/base/at_exit.h
new file mode 100644
index 0000000..6fe7361
--- /dev/null
+++ b/base/at_exit.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_AT_EXIT_H_
+#define BASE_AT_EXIT_H_
+
+#include <stack>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// This class provides a facility similar to the CRT atexit(), except that
+// we control when the callbacks are executed. Under Windows for a DLL they
+// happen at a really bad time and under the loader lock. This facility is
+// mostly used by base::Singleton.
+//
+// The usage is simple. Early in the main() or WinMain() scope create an
+// AtExitManager object on the stack:
+// int main(...) {
+//    base::AtExitManager exit_manager;
+//
+// }
+// When the exit_manager object goes out of scope, all the registered
+// callbacks and singleton destructors will be called.
+
+class BASE_EXPORT AtExitManager {
+ public:
+  typedef void (*AtExitCallbackType)(void*);
+
+  AtExitManager();
+
+  // The dtor calls all the registered callbacks. Do not try to register more
+  // callbacks after this point.
+  ~AtExitManager();
+
+  // Registers the specified function to be called at exit. The prototype of
+  // the callback function is void func(void*).
+  static void RegisterCallback(AtExitCallbackType func, void* param);
+
+  // Registers the specified task to be called at exit.
+  static void RegisterTask(base::Closure task);
+
+  // Calls the functions registered with RegisterCallback in LIFO order. It
+  // is possible to register new callbacks after calling this function.
+  static void ProcessCallbacksNow();
+
+ protected:
+  // This constructor will allow this instance of AtExitManager to be created
+  // even if one already exists.  This should only be used for testing!
+  // AtExitManagers are kept on a global stack, and it will be removed during
+  // destruction.  This allows you to shadow another AtExitManager.
+  explicit AtExitManager(bool shadow);
+
+ private:
+  base::Lock lock_;
+  std::stack<base::Closure> stack_;
+  AtExitManager* next_manager_;  // Stack of managers to allow shadowing.
+
+  DISALLOW_COPY_AND_ASSIGN(AtExitManager);
+};
+
+#if defined(UNIT_TEST)
+class ShadowingAtExitManager : public AtExitManager {
+ public:
+  ShadowingAtExitManager() : AtExitManager(true) {}
+};
+#endif  // defined(UNIT_TEST)
+
+}  // namespace base
+
+#endif  // BASE_AT_EXIT_H_
diff --git a/base/at_exit_unittest.cc b/base/at_exit_unittest.cc
new file mode 100644
index 0000000..cda7340
--- /dev/null
+++ b/base/at_exit_unittest.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int g_test_counter_1 = 0;
+int g_test_counter_2 = 0;
+
+void IncrementTestCounter1(void* unused) {
+  ++g_test_counter_1;
+}
+
+void IncrementTestCounter2(void* unused) {
+  ++g_test_counter_2;
+}
+
+void ZeroTestCounters() {
+  g_test_counter_1 = 0;
+  g_test_counter_2 = 0;
+}
+
+void ExpectCounter1IsZero(void* unused) {
+  EXPECT_EQ(0, g_test_counter_1);
+}
+
+void ExpectParamIsNull(void* param) {
+  EXPECT_EQ(static_cast<void*>(NULL), param);
+}
+
+void ExpectParamIsCounter(void* param) {
+  EXPECT_EQ(&g_test_counter_1, param);
+}
+
+}  // namespace
+
+class AtExitTest : public testing::Test {
+ private:
+  // Don't test the global AtExitManager, because asking it to process its
+  // AtExit callbacks can ruin the global state that other tests may depend on.
+  base::ShadowingAtExitManager exit_manager_;
+};
+
+TEST_F(AtExitTest, Basic) {
+  ZeroTestCounters();
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter2, NULL);
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+
+  EXPECT_EQ(0, g_test_counter_1);
+  EXPECT_EQ(0, g_test_counter_2);
+  base::AtExitManager::ProcessCallbacksNow();
+  EXPECT_EQ(2, g_test_counter_1);
+  EXPECT_EQ(1, g_test_counter_2);
+}
+
+TEST_F(AtExitTest, LIFOOrder) {
+  ZeroTestCounters();
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+  base::AtExitManager::RegisterCallback(&ExpectCounter1IsZero, NULL);
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter2, NULL);
+
+  EXPECT_EQ(0, g_test_counter_1);
+  EXPECT_EQ(0, g_test_counter_2);
+  base::AtExitManager::ProcessCallbacksNow();
+  EXPECT_EQ(1, g_test_counter_1);
+  EXPECT_EQ(1, g_test_counter_2);
+}
+
+TEST_F(AtExitTest, Param) {
+  base::AtExitManager::RegisterCallback(&ExpectParamIsNull, NULL);
+  base::AtExitManager::RegisterCallback(&ExpectParamIsCounter,
+                                        &g_test_counter_1);
+  base::AtExitManager::ProcessCallbacksNow();
+}
+
+TEST_F(AtExitTest, Task) {
+  ZeroTestCounters();
+  base::AtExitManager::RegisterTask(base::Bind(&ExpectParamIsCounter,
+                                               &g_test_counter_1));
+  base::AtExitManager::ProcessCallbacksNow();
+}
diff --git a/base/atomic_ref_count.h b/base/atomic_ref_count.h
new file mode 100644
index 0000000..5130860
--- /dev/null
+++ b/base/atomic_ref_count.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a low level implementation of atomic semantics for reference
+// counting.  Please use base/memory/ref_counted.h directly instead.
+//
+// The implementation includes annotations to avoid some false positives
+// when using data race detection tools.
+
+#ifndef BASE_ATOMIC_REF_COUNT_H_
+#define BASE_ATOMIC_REF_COUNT_H_
+
+#include "base/atomicops.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.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) {
+  ANNOTATE_HAPPENS_BEFORE(ptr);
+  bool res = (subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0);
+  if (!res) {
+    ANNOTATE_HAPPENS_AFTER(ptr);
+  }
+  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);
+  if (res) {
+    ANNOTATE_HAPPENS_AFTER(ptr);
+  }
+  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);
+  if (res) {
+    ANNOTATE_HAPPENS_AFTER(ptr);
+  }
+  return res;
+}
+
+}  // namespace base
+
+#endif  // BASE_ATOMIC_REF_COUNT_H_
diff --git a/base/atomic_sequence_num.h b/base/atomic_sequence_num.h
new file mode 100644
index 0000000..7bf2778
--- /dev/null
+++ b/base/atomic_sequence_num.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ATOMIC_SEQUENCE_NUM_H_
+#define BASE_ATOMIC_SEQUENCE_NUM_H_
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class AtomicSequenceNumber;
+
+// Static (POD) AtomicSequenceNumber that MUST be used in global scope (or
+// non-function scope) ONLY. This implementation does not generate any static
+// initializer.  Note that it does not implement any constructor which means
+// that its fields are not initialized except when it is stored in the global
+// data section (.data in ELF). If you want to allocate an atomic sequence
+// number on the stack (or heap), please use the AtomicSequenceNumber class
+// declared below.
+class StaticAtomicSequenceNumber {
+ public:
+  inline int GetNext() {
+    return static_cast<int>(
+        base::subtle::NoBarrier_AtomicIncrement(&seq_, 1) - 1);
+  }
+
+ private:
+  friend class AtomicSequenceNumber;
+
+  inline void Reset() {
+    base::subtle::Release_Store(&seq_, 0);
+  }
+
+  base::subtle::Atomic32 seq_;
+};
+
+// AtomicSequenceNumber that can be stored and used safely (i.e. its fields are
+// always initialized as opposed to StaticAtomicSequenceNumber declared above).
+// Please use StaticAtomicSequenceNumber if you want to declare an atomic
+// sequence number in the global scope.
+class AtomicSequenceNumber {
+ public:
+  AtomicSequenceNumber() {
+    seq_.Reset();
+  }
+
+  inline int GetNext() {
+    return seq_.GetNext();
+  }
+
+ private:
+  StaticAtomicSequenceNumber seq_;
+  DISALLOW_COPY_AND_ASSIGN(AtomicSequenceNumber);
+};
+
+}  // namespace base
+
+#endif  // BASE_ATOMIC_SEQUENCE_NUM_H_
diff --git a/base/atomicops.h b/base/atomicops.h
new file mode 100644
index 0000000..de5554e
--- /dev/null
+++ b/base/atomicops.h
@@ -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.
+
+// 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 "base/basictypes.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace subtle {
+
+typedef int32 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(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 base::subtle
+}  // namespace base
+
+// Include our platform specific implementation.
+#if defined(THREAD_SANITIZER)
+#include "base/atomicops_internals_tsan.h"
+#elif defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)
+#include "base/atomicops_internals_x86_msvc.h"
+#elif defined(OS_MACOSX)
+#include "base/atomicops_internals_mac.h"
+#elif (defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY)) || \
+       defined(OS_NACL)
+#include "base/atomicops_internals_gcc.h"
+#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
+#include "base/atomicops_internals_x86_gcc.h"
+#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY)
+#include "base/atomicops_internals_mips_gcc.h"
+#else
+#error "Atomic operations are not supported on your platform"
+#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/base/atomicops_internals_atomicword_compat.h b/base/atomicops_internals_atomicword_compat.h
new file mode 100644
index 0000000..e02d11d
--- /dev/null
+++ b/base/atomicops_internals_atomicword_compat.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+#define BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+
+// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32,
+// which in turn means int. On some LP32 platforms, intptr_t is an int, but
+// on others, it's a long. When AtomicWord and Atomic32 are based on different
+// fundamental types, their pointers are incompatible.
+//
+// This file defines function overloads to allow both AtomicWord and Atomic32
+// data to be used with this interface.
+//
+// On LP64 platforms, AtomicWord and Atomic64 are both always long,
+// so this problem doesn't occur.
+
+#if !defined(ARCH_CPU_64_BITS)
+
+namespace base {
+namespace subtle {
+
+inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
+                                           AtomicWord old_value,
+                                           AtomicWord new_value) {
+  return NoBarrier_CompareAndSwap(
+      reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
+                                           AtomicWord new_value) {
+  return NoBarrier_AtomicExchange(
+      reinterpret_cast<volatile Atomic32*>(ptr), new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr,
+                                            AtomicWord increment) {
+  return NoBarrier_AtomicIncrement(
+      reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
+                                          AtomicWord increment) {
+  return Barrier_AtomicIncrement(
+      reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
+                                         AtomicWord old_value,
+                                         AtomicWord new_value) {
+  return base::subtle::Acquire_CompareAndSwap(
+      reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
+                                         AtomicWord old_value,
+                                         AtomicWord new_value) {
+  return base::subtle::Release_CompareAndSwap(
+      reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
+  NoBarrier_Store(
+      reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
+  return base::subtle::Acquire_Store(
+      reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
+  return base::subtle::Release_Store(
+      reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
+  return NoBarrier_Load(
+      reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
+  return base::subtle::Acquire_Load(
+      reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
+  return base::subtle::Release_Load(
+      reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+}   // namespace base::subtle
+}   // namespace base
+
+#endif  // !defined(ARCH_CPU_64_BITS)
+
+#endif  // BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
diff --git a/base/atomicops_internals_gcc.h b/base/atomicops_internals_gcc.h
new file mode 100644
index 0000000..ed1b2d7
--- /dev/null
+++ b/base/atomicops_internals_gcc.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, include base/atomicops.h
+// instead. This file is for platforms that use GCC intrinsics rather than
+// platform-specific assembly code for atomic operations.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_GCC_H_
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value;
+  do {
+    if (__sync_bool_compare_and_swap(ptr, old_value, new_value))
+      return old_value;
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  do {
+    old_value = *ptr;
+  } while (!__sync_bool_compare_and_swap(ptr, old_value, new_value));
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  for (;;) {
+    // Atomic exchange the old value with an incremented one.
+    Atomic32 old_value = *ptr;
+    Atomic32 new_value = old_value + increment;
+    if (__sync_bool_compare_and_swap(ptr, old_value, new_value)) {
+      // The exchange took place as expected.
+      return new_value;
+    }
+    // Otherwise, *ptr changed mid-loop and we need to retry.
+  }
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  // Since NoBarrier_CompareAndSwap uses __sync_bool_compare_and_swap, which
+  // is a full memory barrier, none is needed here or below in Release.
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() {
+  __sync_synchronize();
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+}  // namespace base::subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_GCC_H_
+
diff --git a/base/atomicops_internals_mac.h b/base/atomicops_internals_mac.h
new file mode 100644
index 0000000..658ed54
--- /dev/null
+++ b/base/atomicops_internals_mac.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_MAC_H_
+#define BASE_ATOMICOPS_INTERNALS_MAC_H_
+
+#include <libkern/OSAtomic.h>
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap32(old_value, new_value,
+                                 const_cast<Atomic32*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  do {
+    old_value = *ptr;
+  } while (!OSAtomicCompareAndSwap32(old_value, new_value,
+                                     const_cast<Atomic32*>(ptr)));
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
+                                          Atomic32 increment) {
+  return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
+                                          Atomic32 increment) {
+  return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
+}
+
+inline void MemoryBarrier() {
+  OSMemoryBarrier();
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap32Barrier(old_value, new_value,
+                                        const_cast<Atomic32*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#ifdef __LP64__
+
+// 64-bit implementation on 64-bit platform
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap64(old_value, new_value,
+                                 reinterpret_cast<volatile int64_t*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
+                                         Atomic64 new_value) {
+  Atomic64 old_value;
+  do {
+    old_value = *ptr;
+  } while (!OSAtomicCompareAndSwap64(old_value, new_value,
+                                     reinterpret_cast<volatile int64_t*>(ptr)));
+  return old_value;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
+                                          Atomic64 increment) {
+  return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr));
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
+                                        Atomic64 increment) {
+  return OSAtomicAdd64Barrier(increment,
+                              reinterpret_cast<volatile int64_t*>(ptr));
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap64Barrier(
+        old_value, new_value, reinterpret_cast<volatile int64_t*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  // The lib kern interface does not distinguish between
+  // Acquire and Release memory barriers; they are equivalent.
+  return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
+  Atomic64 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#endif  // defined(__LP64__)
+
+}   // namespace base::subtle
+}   // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_MAC_H_
diff --git a/base/atomicops_internals_mips_gcc.h b/base/atomicops_internals_mips_gcc.h
new file mode 100644
index 0000000..505597e
--- /dev/null
+++ b/base/atomicops_internals_mips_gcc.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.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+//
+// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace base {
+namespace subtle {
+
+// Atomically execute:
+//      result = *ptr;
+//      if (*ptr == old_value)
+//        *ptr = new_value;
+//      return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev, tmp;
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "ll %0, %5\n"  // prev = *ptr
+                       "bne %0, %3, 2f\n"  // if (prev != old_value) goto 2
+                       "move %2, %4\n"  // tmp = new_value
+                       "sc %2, %1\n"  // *ptr = tmp (with atomic check)
+                       "beqz %2, 1b\n"  // start again on atomic error
+                       "nop\n"  // delay slot nop
+                       "2:\n"
+                       ".set pop\n"
+                       : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
+                       : "Ir" (old_value), "r" (new_value), "m" (*ptr)
+                       : "memory");
+  return prev;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr.  This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 temp, old;
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "ll %1, %2\n"  // old = *ptr
+                       "move %0, %3\n"  // temp = new_value
+                       "sc %0, %2\n"  // *ptr = temp (with atomic check)
+                       "beqz %0, 1b\n"  // start again on atomic error
+                       "nop\n"  // delay slot nop
+                       ".set pop\n"
+                       : "=&r" (temp), "=&r" (old), "=m" (*ptr)
+                       : "r" (new_value), "m" (*ptr)
+                       : "memory");
+
+  return old;
+}
+
+// Atomically increment *ptr by "increment".  Returns the new value of
+// *ptr with the increment applied.  This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 temp, temp2;
+
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "ll %0, %2\n"  // temp = *ptr
+                       "addu %1, %0, %3\n"  // temp2 = temp + increment
+                       "sc %1, %2\n"  // *ptr = temp2 (with atomic check)
+                       "beqz %1, 1b\n"  // start again on atomic error
+                       "addu %1, %0, %3\n"  // temp2 = temp + increment
+                       ".set pop\n"
+                       : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
+                       : "Ir" (increment), "m" (*ptr)
+                       : "memory");
+  // temp2 now holds the final value.
+  return temp2;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  ATOMICOPS_COMPILER_BARRIER();
+  Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
+  ATOMICOPS_COMPILER_BARRIER();
+  return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation.  "Barrier" operations have both "Acquire" and "Release"
+// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  ATOMICOPS_COMPILER_BARRIER();
+  Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  ATOMICOPS_COMPILER_BARRIER();
+  return res;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  ATOMICOPS_COMPILER_BARRIER();
+  Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  ATOMICOPS_COMPILER_BARRIER();
+  return res;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() {
+  __asm__ __volatile__("sync" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+} // namespace base::subtle
+} // namespace base
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif  // BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
diff --git a/base/atomicops_internals_tsan.h b/base/atomicops_internals_tsan.h
new file mode 100644
index 0000000..94fe983
--- /dev/null
+++ b/base/atomicops_internals_tsan.h
@@ -0,0 +1,313 @@
+// Copyright (c) 2012 The Chromium 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 for compiler-based
+// ThreadSanitizer. Use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_TSAN_H_
+#define BASE_ATOMICOPS_INTERNALS_TSAN_H_
+
+#include "base/base_export.h"
+
+// This struct is not part of the public API of this module; clients may not
+// use it.  (However, it's exported via BASE_EXPORT because clients implicitly
+// do use it at link time by inlining these functions.)
+// Features of this x86.  Values may not be correct before main() is run,
+// but are set conservatively.
+struct AtomicOps_x86CPUFeatureStruct {
+  bool has_amd_lock_mb_bug;  // Processor has AMD memory-barrier bug; do lfence
+                             // after acquire compare-and-swap.
+  bool has_sse2;             // Processor has SSE2.
+};
+BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
+    AtomicOps_Internalx86CPUFeatures;
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace base {
+namespace subtle {
+
+#ifndef TSAN_INTERFACE_ATOMIC_H
+#define TSAN_INTERFACE_ATOMIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef char  __tsan_atomic8;
+typedef short __tsan_atomic16;  // NOLINT
+typedef int   __tsan_atomic32;
+typedef long  __tsan_atomic64;  // NOLINT
+
+typedef enum {
+  __tsan_memory_order_relaxed = 1 << 0,
+  __tsan_memory_order_consume = 1 << 1,
+  __tsan_memory_order_acquire = 1 << 2,
+  __tsan_memory_order_release = 1 << 3,
+  __tsan_memory_order_acq_rel = 1 << 4,
+  __tsan_memory_order_seq_cst = 1 << 5,
+} __tsan_memory_order;
+
+__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
+    __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
+    __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
+    __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
+    __tsan_memory_order mo);
+
+void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
+    __tsan_memory_order mo);
+void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
+    __tsan_memory_order mo);
+void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
+    __tsan_memory_order mo);
+void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
+    __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+
+int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo);
+int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo);
+int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo);
+int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo);
+
+int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo);
+int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo);
+int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo);
+int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo);
+
+void __tsan_atomic_thread_fence(__tsan_memory_order mo);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // #ifndef TSAN_INTERFACE_ATOMIC_H
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
+                                  Atomic32 old_value,
+                                  Atomic32 new_value) {
+  Atomic32 cmp = old_value;
+  __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+    __tsan_memory_order_relaxed);
+  return cmp;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
+                                  Atomic32 new_value) {
+  return __tsan_atomic32_exchange(ptr, new_value,
+      __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr,
+                                Atomic32 new_value) {
+  return __tsan_atomic32_exchange(ptr, new_value,
+      __tsan_memory_order_acquire);
+}
+
+inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr,
+                                Atomic32 new_value) {
+  return __tsan_atomic32_exchange(ptr, new_value,
+      __tsan_memory_order_release);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
+                                   Atomic32 increment) {
+  return increment + __tsan_atomic32_fetch_add(ptr, increment,
+      __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
+                                 Atomic32 increment) {
+  return increment + __tsan_atomic32_fetch_add(ptr, increment,
+      __tsan_memory_order_acq_rel);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
+                                Atomic32 old_value,
+                                Atomic32 new_value) {
+  Atomic32 cmp = old_value;
+  __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_acquire);
+  return cmp;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
+                                Atomic32 old_value,
+                                Atomic32 new_value) {
+  Atomic32 cmp = old_value;
+  __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_release);
+  return cmp;
+}
+
+inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
+  __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  __tsan_atomic32_store(ptr, value, __tsan_memory_order_release);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
+  return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
+  return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
+  __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+  return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
+                                      Atomic64 old_value,
+                                      Atomic64 new_value) {
+  Atomic64 cmp = old_value;
+  __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_relaxed);
+  return cmp;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
+                                      Atomic64 new_value) {
+  return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr,
+                                    Atomic64 new_value) {
+  return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_acquire);
+}
+
+inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr,
+                                    Atomic64 new_value) {
+  return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_release);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
+                                       Atomic64 increment) {
+  return increment + __tsan_atomic64_fetch_add(ptr, increment,
+      __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
+                                     Atomic64 increment) {
+  return increment + __tsan_atomic64_fetch_add(ptr, increment,
+      __tsan_memory_order_acq_rel);
+}
+
+inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
+  __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  __tsan_atomic64_store(ptr, value, __tsan_memory_order_release);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
+  return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
+  return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
+  __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+  return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
+                                    Atomic64 old_value,
+                                    Atomic64 new_value) {
+  Atomic64 cmp = old_value;
+  __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_acquire);
+  return cmp;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
+                                    Atomic64 old_value,
+                                    Atomic64 new_value) {
+  Atomic64 cmp = old_value;
+  __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_release);
+  return cmp;
+}
+
+inline void MemoryBarrier() {
+  __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+}  // namespace base::subtle
+}  // namespace base
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif  // BASE_ATOMICOPS_INTERNALS_TSAN_H_
diff --git a/base/atomicops_internals_x86_gcc.cc b/base/atomicops_internals_x86_gcc.cc
new file mode 100644
index 0000000..933ca51
--- /dev/null
+++ b/base/atomicops_internals_x86_gcc.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This module gets enough CPU information to optimize the
+// atomicops module on x86.
+
+#include <string.h>
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+
+// This file only makes sense with atomicops_internals_x86_gcc.h -- it
+// depends on structs that are defined in that file.  If atomicops.h
+// doesn't sub-include that file, then we aren't needed, and shouldn't
+// try to do anything.
+#ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+
+// Inline cpuid instruction.  In PIC compilations, %ebx contains the address
+// of the global offset table.  To avoid breaking such executables, this code
+// must preserve that register's value across cpuid instructions.
+#if defined(__i386__)
+#define cpuid(a, b, c, d, inp) \
+  asm ("mov %%ebx, %%edi\n"    \
+       "cpuid\n"               \
+       "xchg %%edi, %%ebx\n"   \
+       : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#elif defined (__x86_64__)
+#define cpuid(a, b, c, d, inp) \
+  asm ("mov %%rbx, %%rdi\n"    \
+       "cpuid\n"               \
+       "xchg %%rdi, %%rbx\n"   \
+       : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#endif
+
+#if defined(cpuid)        // initialize the struct only on x86
+
+// Set the flags so that code will run correctly and conservatively, so even
+// if we haven't been initialized yet, we're probably single threaded, and our
+// default values should hopefully be pretty safe.
+struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = {
+  false,          // bug can't exist before process spawns multiple threads
+  false,          // no SSE2
+};
+
+// Initialize the AtomicOps_Internalx86CPUFeatures struct.
+static void AtomicOps_Internalx86CPUFeaturesInit() {
+  uint32 eax;
+  uint32 ebx;
+  uint32 ecx;
+  uint32 edx;
+
+  // Get vendor string (issue CPUID with eax = 0)
+  cpuid(eax, ebx, ecx, edx, 0);
+  char vendor[13];
+  memcpy(vendor, &ebx, 4);
+  memcpy(vendor + 4, &edx, 4);
+  memcpy(vendor + 8, &ecx, 4);
+  vendor[12] = 0;
+
+  // get feature flags in ecx/edx, and family/model in eax
+  cpuid(eax, ebx, ecx, edx, 1);
+
+  int family = (eax >> 8) & 0xf;        // family and model fields
+  int model = (eax >> 4) & 0xf;
+  if (family == 0xf) {                  // use extended family and model fields
+    family += (eax >> 20) & 0xff;
+    model += ((eax >> 16) & 0xf) << 4;
+  }
+
+  // Opteron Rev E has a bug in which on very rare occasions a locked
+  // instruction doesn't act as a read-acquire barrier if followed by a
+  // non-locked read-modify-write instruction.  Rev F has this bug in
+  // pre-release versions, but not in versions released to customers,
+  // so we test only for Rev E, which is family 15, model 32..63 inclusive.
+  if (strcmp(vendor, "AuthenticAMD") == 0 &&       // AMD
+      family == 15 &&
+      32 <= model && model <= 63) {
+    AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
+  } else {
+    AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
+  }
+
+  // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
+  AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);
+}
+
+namespace {
+
+class AtomicOpsx86Initializer {
+ public:
+  AtomicOpsx86Initializer() {
+    AtomicOps_Internalx86CPUFeaturesInit();
+  }
+};
+
+// A global to get use initialized on startup via static initialization :/
+AtomicOpsx86Initializer g_initer;
+
+}  // namespace
+
+#endif  // if x86
+
+#endif  // ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/base/atomicops_internals_x86_gcc.h b/base/atomicops_internals_x86_gcc.h
new file mode 100644
index 0000000..ac02b17
--- /dev/null
+++ b/base/atomicops_internals_x86_gcc.h
@@ -0,0 +1,269 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+
+#include "base/base_export.h"
+
+// This struct is not part of the public API of this module; clients may not
+// use it.  (However, it's exported via BASE_EXPORT because clients implicitly
+// do use it at link time by inlining these functions.)
+// Features of this x86.  Values may not be correct before main() is run,
+// but are set conservatively.
+struct AtomicOps_x86CPUFeatureStruct {
+  bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
+                            // after acquire compare-and-swap.
+  bool has_sse2;            // Processor has SSE2.
+};
+BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
+    AtomicOps_Internalx86CPUFeatures;
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace base {
+namespace subtle {
+
+// 32-bit low-level operations on any platform.
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev;
+  __asm__ __volatile__("lock; cmpxchgl %1,%2"
+                       : "=a" (prev)
+                       : "q" (new_value), "m" (*ptr), "0" (old_value)
+                       : "memory");
+  return prev;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  __asm__ __volatile__("xchgl %1,%0"  // The lock prefix is implicit for xchg.
+                       : "=r" (new_value)
+                       : "m" (*ptr), "0" (new_value)
+                       : "memory");
+  return new_value;  // Now it's the previous value.
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 temp = increment;
+  __asm__ __volatile__("lock; xaddl %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now holds the old value of *ptr
+  return temp + increment;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  Atomic32 temp = increment;
+  __asm__ __volatile__("lock; xaddl %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now holds the old value of *ptr
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return temp + increment;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return x;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+#if defined(__x86_64__)
+
+// 64-bit implementations of memory barrier can be simpler, because it
+// "mfence" is guaranteed to exist.
+inline void MemoryBarrier() {
+  __asm__ __volatile__("mfence" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+#else
+
+inline void MemoryBarrier() {
+  if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
+    __asm__ __volatile__("mfence" : : : "memory");
+  } else { // mfence is faster but not present on PIII
+    Atomic32 x = 0;
+    NoBarrier_AtomicExchange(&x, 0);  // acts as a barrier on PIII
+  }
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
+    *ptr = value;
+    __asm__ __volatile__("mfence" : : : "memory");
+  } else {
+    NoBarrier_AtomicExchange(ptr, value);
+                          // acts as a barrier on PIII
+  }
+}
+#endif
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ATOMICOPS_COMPILER_BARRIER();
+  *ptr = value; // An x86 store acts as a release barrier.
+  // See comments in Atomic64 version of Release_Store(), below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
+  // See comments in Atomic64 version of Release_Store(), below.
+  ATOMICOPS_COMPILER_BARRIER();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#if defined(__x86_64__)
+
+// 64-bit low-level operations on 64-bit platform.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 prev;
+  __asm__ __volatile__("lock; cmpxchgq %1,%2"
+                       : "=a" (prev)
+                       : "q" (new_value), "m" (*ptr), "0" (old_value)
+                       : "memory");
+  return prev;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  __asm__ __volatile__("xchgq %1,%0"  // The lock prefix is implicit for xchg.
+                       : "=r" (new_value)
+                       : "m" (*ptr), "0" (new_value)
+                       : "memory");
+  return new_value;  // Now it's the previous value.
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  Atomic64 temp = increment;
+  __asm__ __volatile__("lock; xaddq %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now contains the previous value of *ptr
+  return temp + increment;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  Atomic64 temp = increment;
+  __asm__ __volatile__("lock; xaddq %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now contains the previous value of *ptr
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return temp + increment;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ATOMICOPS_COMPILER_BARRIER();
+
+  *ptr = value; // An x86 store acts as a release barrier
+                // for current AMD/Intel chips as of Jan 2008.
+                // See also Acquire_Load(), below.
+
+  // When new chips come out, check:
+  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+  //  System Programming Guide, Chatper 7: Multiple-processor management,
+  //  Section 7.2, Memory Ordering.
+  // Last seen at:
+  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
+  //
+  // x86 stores/loads fail to act as barriers for a few instructions (clflush
+  // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
+  // not generated by the compiler, and are rare.  Users of these instructions
+  // need to know about cache behaviour in any case since all of these involve
+  // either flushing cache lines or non-temporal cache hints.
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
+                         // for current AMD/Intel chips as of Jan 2008.
+                         // See also Release_Store(), above.
+  ATOMICOPS_COMPILER_BARRIER();
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return x;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+#endif  // defined(__x86_64__)
+
+} // namespace base::subtle
+} // namespace base
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif  // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/base/atomicops_internals_x86_msvc.h b/base/atomicops_internals_x86_msvc.h
new file mode 100644
index 0000000..eacbb5e
--- /dev/null
+++ b/base/atomicops_internals_x86_msvc.h
@@ -0,0 +1,180 @@
+// 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>
+
+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);
+}
+
+#if !(defined(_MSC_VER) && _MSC_VER >= 1400)
+#error "We require at least vs2005 for MemoryBarrier"
+#endif
+inline void MemoryBarrier() {
+  // We use MemoryBarrier from WinNT.h
+  ::MemoryBarrier();
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  NoBarrier_AtomicExchange(ptr, value);
+              // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+  // See comments in Atomic64 version of Release_Store() below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#if defined(_WIN64)
+
+// 64-bit low-level operations on 64-bit platform.
+
+COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  PVOID result = InterlockedCompareExchangePointer(
+    reinterpret_cast<volatile PVOID*>(ptr),
+    reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
+  return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  PVOID result = InterlockedExchangePointer(
+    reinterpret_cast<volatile PVOID*>(ptr),
+    reinterpret_cast<PVOID>(new_value));
+  return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  return InterlockedExchangeAdd64(
+      reinterpret_cast<volatile LONGLONG*>(ptr),
+      static_cast<LONGLONG>(increment)) + increment;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  NoBarrier_AtomicExchange(ptr, value);
+              // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+
+  // When new chips come out, check:
+  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+  //  System Programming Guide, Chatper 7: Multiple-processor management,
+  //  Section 7.2, Memory Ordering.
+  // Last seen at:
+  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr;
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+
+#endif  // defined(_WIN64)
+
+}  // namespace base::subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
diff --git a/base/atomicops_unittest.cc b/base/atomicops_unittest.cc
new file mode 100644
index 0000000..d73a098
--- /dev/null
+++ b/base/atomicops_unittest.cc
@@ -0,0 +1,241 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/atomicops.h"
+
+#include <string.h>
+
+#include "base/port.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+template <class AtomicType>
+static void TestAtomicIncrement() {
+  // For now, we just test single threaded execution
+
+  // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go
+  // outside the expected address bounds.  This is in particular to
+  // test that some future change to the asm code doesn't cause the
+  // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit
+  // machines.
+  struct {
+    AtomicType prev_word;
+    AtomicType count;
+    AtomicType next_word;
+  } s;
+
+  AtomicType prev_word_value, next_word_value;
+  memset(&prev_word_value, 0xFF, sizeof(AtomicType));
+  memset(&next_word_value, 0xEE, sizeof(AtomicType));
+
+  s.prev_word = prev_word_value;
+  s.count = 0;
+  s.next_word = next_word_value;
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1);
+  EXPECT_EQ(s.count, 1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3);
+  EXPECT_EQ(s.count, 3);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6);
+  EXPECT_EQ(s.count, 6);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3);
+  EXPECT_EQ(s.count, 3);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1);
+  EXPECT_EQ(s.count, 1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0);
+  EXPECT_EQ(s.count, 0);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1);
+  EXPECT_EQ(s.count, -1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5);
+  EXPECT_EQ(s.count, -5);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0);
+  EXPECT_EQ(s.count, 0);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+}
+
+
+#define NUM_BITS(T) (sizeof(T) * 8)
+
+
+template <class AtomicType>
+static void TestCompareAndSwap() {
+  AtomicType value = 0;
+  AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1);
+  EXPECT_EQ(1, value);
+  EXPECT_EQ(0, prev);
+
+  // Use test value that has non-zero bits in both halves, more for testing
+  // 64-bit implementation on 32-bit platforms.
+  const AtomicType k_test_val = (GG_ULONGLONG(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 = (GG_ULONGLONG(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 = (GG_ULONGLONG(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 = GG_ULONGLONG(1) << (NUM_BITS(AtomicType) / 2);
+  value = test_val - 1;
+  new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
+  EXPECT_EQ(test_val, value);
+  EXPECT_EQ(value, new_value);
+
+  base::subtle::NoBarrier_AtomicIncrement(&value, -1);
+  EXPECT_EQ(test_val - 1, value);
+}
+
+// Return an AtomicType with the value 0xa5a5a5..
+template <class AtomicType>
+static AtomicType TestFillValue() {
+  AtomicType val = 0;
+  memset(&val, 0xa5, sizeof(AtomicType));
+  return val;
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestStore() {
+  const AtomicType kVal1 = TestFillValue<AtomicType>();
+  const AtomicType kVal2 = static_cast<AtomicType>(-1);
+
+  AtomicType value;
+
+  base::subtle::NoBarrier_Store(&value, kVal1);
+  EXPECT_EQ(kVal1, value);
+  base::subtle::NoBarrier_Store(&value, kVal2);
+  EXPECT_EQ(kVal2, value);
+
+  base::subtle::Acquire_Store(&value, kVal1);
+  EXPECT_EQ(kVal1, value);
+  base::subtle::Acquire_Store(&value, kVal2);
+  EXPECT_EQ(kVal2, value);
+
+  base::subtle::Release_Store(&value, kVal1);
+  EXPECT_EQ(kVal1, value);
+  base::subtle::Release_Store(&value, kVal2);
+  EXPECT_EQ(kVal2, value);
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestLoad() {
+  const AtomicType kVal1 = TestFillValue<AtomicType>();
+  const AtomicType kVal2 = static_cast<AtomicType>(-1);
+
+  AtomicType value;
+
+  value = kVal1;
+  EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value));
+  value = kVal2;
+  EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value));
+
+  value = kVal1;
+  EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value));
+  value = kVal2;
+  EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value));
+
+  value = kVal1;
+  EXPECT_EQ(kVal1, base::subtle::Release_Load(&value));
+  value = kVal2;
+  EXPECT_EQ(kVal2, base::subtle::Release_Load(&value));
+}
+
+TEST(AtomicOpsTest, Inc) {
+  TestAtomicIncrement<base::subtle::Atomic32>();
+  TestAtomicIncrement<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, CompareAndSwap) {
+  TestCompareAndSwap<base::subtle::Atomic32>();
+  TestCompareAndSwap<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Exchange) {
+  TestAtomicExchange<base::subtle::Atomic32>();
+  TestAtomicExchange<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, IncrementBounds) {
+  TestAtomicIncrementBounds<base::subtle::Atomic32>();
+  TestAtomicIncrementBounds<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Store) {
+  TestStore<base::subtle::Atomic32>();
+  TestStore<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Load) {
+  TestLoad<base::subtle::Atomic32>();
+  TestLoad<base::subtle::AtomicWord>();
+}
diff --git a/base/auto_reset.h b/base/auto_reset.h
new file mode 100644
index 0000000..86b60cb
--- /dev/null
+++ b/base/auto_reset.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_AUTO_RESET_H_
+#define BASE_AUTO_RESET_H_
+
+#include "base/basictypes.h"
+
+// AutoReset<> is useful for setting a variable to a new value only within a
+// particular scope. An 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 AutoReset<> instance should have a
+// shorter lifetime than its scoped_variable, to prevent invalid memory writes
+// when the AutoReset<> object is destroyed.
+
+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);
+};
+
+#endif  // BASE_AUTO_RESET_H_
diff --git a/base/base.gyp b/base/base.gyp
new file mode 100644
index 0000000..c1dea4b
--- /dev/null
+++ b/base/base.gyp
@@ -0,0 +1,1104 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    '../build/win_precompile.gypi',
+    'base.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'base',
+      'type': '<(component)',
+      'toolsets': ['host', 'target'],
+      'variables': {
+        'base_target': 1,
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+      },
+      'dependencies': [
+        'base_static',
+        'allocator/allocator.gyp:allocator_extension_thunks',
+        '../testing/gtest.gyp:gtest_prod',
+        '../third_party/modp_b64/modp_b64.gyp:modp_b64',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+      ],
+      # TODO(gregoryd): direct_dependent_settings should be shared with the
+      #  64-bit target, but it doesn't work due to a bug in gyp
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '..',
+        ],
+      },
+      'conditions': [
+        ['use_glib==1', {
+          'conditions': [
+            ['chromeos==1', {
+              'sources/': [ ['include', '_chromeos\\.cc$'] ]
+            }],
+            ['linux_use_tcmalloc==0', {
+              'defines': [
+                'NO_TCMALLOC',
+              ],
+              'direct_dependent_settings': {
+                'defines': [
+                  'NO_TCMALLOC',
+                ],
+              },
+            }],
+            ['toolkit_uses_gtk==1', {
+              'dependencies': [
+                '../build/linux/system.gyp:gtk',
+              ],
+              'export_dependent_settings': [
+                '../build/linux/system.gyp:gtk',
+              ],
+            }],
+          ],
+          'dependencies': [
+            'symbolize',
+            '../build/linux/system.gyp:glib',
+            '../build/linux/system.gyp:x11',
+            'xdg_mime',
+          ],
+          'defines': [
+            'USE_SYMBOLIZE',
+          ],
+          'cflags': [
+            '-Wno-write-strings',
+          ],
+          'export_dependent_settings': [
+            '../build/linux/system.gyp:glib',
+            '../build/linux/system.gyp:x11',
+          ],
+        }, {  # use_glib!=1
+            'sources/': [
+              ['exclude', '/xdg_user_dirs/'],
+              ['exclude', '_nss\\.cc$'],
+            ],
+        }],
+        ['OS == "android" and _toolset == "host"', {
+          # 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 build on linux depends on system.gyp::gtk as
+            # default linux build has TOOLKIT_GTK defined.
+            ['host_os == "linux"', {
+              'sources/': [
+                ['include', '^atomicops_internals_x86_gcc\\.cc$'],
+              ],
+              'dependencies': [
+                '../build/linux/system.gyp:gtk',
+              ],
+              'export_dependent_settings': [
+                '../build/linux/system.gyp:gtk',
+              ],
+            }],
+            ['host_os == "mac"', {
+              'sources/': [
+                ['exclude', '^native_library_linux\\.cc$'],
+                ['exclude', '^process_util_linux\\.cc$'],
+                ['exclude', '^sys_info_linux\\.cc$'],
+                ['exclude', '^sys_string_conversions_linux\\.cc$'],
+                ['exclude', '^worker_pool_linux\\.cc$'],
+              ],
+            }],
+          ],
+        }],
+        ['OS == "android" and _toolset == "target"', {
+          'conditions': [
+            ['target_arch == "ia32"', {
+              'sources/': [
+                ['include', '^atomicops_internals_x86_gcc\\.cc$'],
+              ],
+            }],
+          ],
+          'dependencies': [
+            'base_jni_headers',
+            'symbolize',
+            '../third_party/ashmem/ashmem.gyp:ashmem',
+            '../third_party/icu/icu.gyp:icuuc',
+          ],
+          'include_dirs': [
+            '<(SHARED_INTERMEDIATE_DIR)/base',
+          ],
+          'link_settings': {
+            'libraries': [
+              '-llog',
+            ],
+          },
+          'defines': [
+            'USE_SYMBOLIZE',
+          ],
+          'sources!': [
+            'debug/stack_trace_posix.cc',
+          ],
+        }],
+        ['OS == "android" and _toolset == "target" and android_build_type == 0', {
+          'dependencies': [
+            'base_java',
+          ],
+        }],
+        ['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',
+            ],
+          },
+        }],
+        ['OS == "mac"', {
+          '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',
+            ],
+          },
+          'dependencies': [
+            '../third_party/mach_override/mach_override.gyp:mach_override',
+          ],
+        }],
+        ['OS == "ios"', {
+          '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"', {
+            'dependencies': ['../third_party/libevent/libevent.gyp:libevent'],
+        },],
+        ['component=="shared_library"', {
+          'conditions': [
+            ['OS=="win"', {
+              'sources!': [
+                'debug/debug_on_start_win.cc',
+              ],
+            }],
+          ],
+        }],
+      ],
+      'sources': [
+        'third_party/nspr/prcpucfg.h',
+        'third_party/nspr/prcpucfg_win.h',
+        'third_party/nspr/prtypes.h',
+        'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
+        'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
+        'auto_reset.h',
+        'event_recorder.h',
+        'event_recorder_stubs.cc',
+        'event_recorder_win.cc',
+        'linux_util.cc',
+        'linux_util.h',
+        'md5.cc',
+        'md5.h',
+        'message_pump_android.cc',
+        'message_pump_android.h',
+        'message_pump_glib.cc',
+        'message_pump_glib.h',
+        'message_pump_gtk.cc',
+        'message_pump_gtk.h',
+        'message_pump_observer.h',
+        'message_pump_aurax11.cc',
+        'message_pump_aurax11.h',
+        'message_pump_libevent.cc',
+        'message_pump_libevent.h',
+        'message_pump_mac.h',
+        '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_win.cc',
+        'sync_socket_posix.cc',
+      ],
+    },
+    {
+      'target_name': 'base_i18n',
+      'type': '<(component)',
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+      },
+      'dependencies': [
+        'base',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '../third_party/icu/icu.gyp:icui18n',
+        '../third_party/icu/icu.gyp:icuuc',
+      ],
+      'conditions': [
+        ['toolkit_uses_gtk==1', {
+          'dependencies': [
+            # i18n/rtl.cc uses gtk
+            '../build/linux/system.gyp:gtk',
+          ],
+        }],
+      ],
+      'export_dependent_settings': [
+        'base',
+      ],
+      'defines': [
+        'BASE_I18N_IMPLEMENTATION',
+      ],
+      'sources': [
+        'i18n/base_i18n_export.h',
+        'i18n/bidi_line_iterator.cc',
+        'i18n/bidi_line_iterator.h',
+        'i18n/break_iterator.cc',
+        'i18n/break_iterator.h',
+        'i18n/char_iterator.cc',
+        'i18n/char_iterator.h',
+        'i18n/case_conversion.cc',
+        'i18n/case_conversion.h',
+        'i18n/file_util_icu.cc',
+        'i18n/file_util_icu.h',
+        'i18n/icu_encoding_detection.cc',
+        'i18n/icu_encoding_detection.h',
+        'i18n/icu_string_conversions.cc',
+        'i18n/icu_string_conversions.h',
+        'i18n/icu_util.cc',
+        'i18n/icu_util.h',
+        'i18n/number_formatting.cc',
+        'i18n/number_formatting.h',
+        'i18n/rtl.cc',
+        'i18n/rtl.h',
+        'i18n/string_search.cc',
+        'i18n/string_search.h',
+        'i18n/time_formatting.cc',
+        'i18n/time_formatting.h',
+      ],
+    },
+    {
+      'target_name': 'base_prefs',
+      'type': '<(component)',
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+      },
+      'dependencies': [
+        'base',
+      ],
+      'export_dependent_settings': [
+        'base',
+      ],
+      'defines': [
+        'BASE_PREFS_IMPLEMENTATION',
+      ],
+      'sources': [
+        'prefs/default_pref_store.cc',
+        'prefs/default_pref_store.h',
+        'prefs/json_pref_store.cc',
+        'prefs/json_pref_store.h',
+        'prefs/overlay_user_pref_store.cc',
+        'prefs/overlay_user_pref_store.h',
+        'prefs/persistent_pref_store.h',
+        'prefs/pref_notifier.h',
+        'prefs/pref_store.cc',
+        'prefs/pref_store.h',
+        'prefs/pref_value_map.cc',
+        'prefs/pref_value_map.h',
+        'prefs/public/pref_change_registrar.cc',
+        'prefs/public/pref_change_registrar.h',
+        'prefs/public/pref_observer.h',
+        'prefs/public/pref_service_base.h',
+        'prefs/value_map_pref_store.cc',
+        'prefs/value_map_pref_store.h',
+      ],
+    },
+    {
+      # This is the subset of files from base that should not be used with a
+      # dynamic library. Note that this library cannot depend on base because
+      # base depends on base_static.
+      'target_name': 'base_static',
+      'type': 'static_library',
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+      },
+      'toolsets': ['host', 'target'],
+      'sources': [
+        'base_switches.cc',
+        'base_switches.h',
+        'win/pe_image.cc',
+        'win/pe_image.h',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
+      # 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',
+      ],
+      # TODO(rvargas): Bug 78117. Remove this.
+      'msvs_disabled_warnings': [
+        4244,
+      ],
+    },
+    # 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': [
+        # Tests.
+        'android/jni_android_unittest.cc',
+        'android/jni_array_unittest.cc',
+        'android/path_utils_unittest.cc',
+        'android/scoped_java_ref_unittest.cc',
+        'at_exit_unittest.cc',
+        'atomicops_unittest.cc',
+        'base64_unittest.cc',
+        'bind_helpers_unittest.cc',
+        'bind_unittest.cc',
+        'bind_unittest.nc',
+        'bits_unittest.cc',
+        'build_time_unittest.cc',
+        'callback_unittest.cc',
+        'callback_unittest.nc',
+        'cancelable_callback_unittest.cc',
+        'command_line_unittest.cc',
+        'containers/linked_list_unittest.cc',
+        'containers/small_map_unittest.cc',
+        'containers/stack_container_unittest.cc',
+        'cpu_unittest.cc',
+        'debug/leak_tracker_unittest.cc',
+        'debug/stack_trace_unittest.cc',
+        'debug/trace_event_unittest.cc',
+        'debug/trace_event_unittest.h',
+        'debug/trace_event_win_unittest.cc',
+        'environment_unittest.cc',
+        'file_path_unittest.cc',
+        'file_util_proxy_unittest.cc',
+        'file_util_unittest.cc',
+        'file_version_info_unittest.cc',
+        'files/dir_reader_posix_unittest.cc',
+        'files/important_file_writer_unittest.cc',
+        'gmock_unittest.cc',
+        'guid_unittest.cc',
+        'hi_res_timer_manager_unittest.cc',
+        'id_map_unittest.cc',
+        'i18n/break_iterator_unittest.cc',
+        'i18n/char_iterator_unittest.cc',
+        'i18n/case_conversion_unittest.cc',
+        'i18n/file_util_icu_unittest.cc',
+        'i18n/icu_string_conversions_unittest.cc',
+        'i18n/number_formatting_unittest.cc',
+        'i18n/rtl_unittest.cc',
+        'i18n/string_search_unittest.cc',
+        'i18n/time_formatting_unittest.cc',
+        'ios/device_util_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/foundation_util_unittest.mm',
+        'mac/mac_util_unittest.mm',
+        'mac/objc_property_releaser_unittest.mm',
+        'mac/scoped_sending_event_unittest.mm',
+        'md5_unittest.cc',
+        'memory/aligned_memory_unittest.cc',
+        'memory/linked_ptr_unittest.cc',
+        'memory/mru_cache_unittest.cc',
+        'memory/ref_counted_memory_unittest.cc',
+        'memory/ref_counted_unittest.cc',
+        'memory/scoped_nsobject_unittest.mm',
+        'memory/scoped_ptr_unittest.cc',
+        'memory/scoped_ptr_unittest.nc',
+        'memory/scoped_vector_unittest.cc',
+        'memory/singleton_unittest.cc',
+        'memory/weak_ptr_unittest.cc',
+        'memory/weak_ptr_unittest.nc',
+        'message_loop_proxy_impl_unittest.cc',
+        'message_loop_proxy_unittest.cc',
+        'message_loop_unittest.cc',
+        'message_pump_glib_unittest.cc',
+        'message_pump_libevent_unittest.cc',
+        'metrics/sample_map_unittest.cc',
+        'metrics/sample_vector_unittest.cc',
+        'metrics/bucket_ranges_unittest.cc',
+        'metrics/field_trial_unittest.cc',
+        'metrics/histogram_unittest.cc',
+        'metrics/sparse_histogram_unittest.cc',
+        'metrics/stats_table_unittest.cc',
+        'metrics/statistics_recorder_unittest.cc',
+        'observer_list_unittest.cc',
+        'os_compat_android_unittest.cc',
+        'path_service_unittest.cc',
+        'pickle_unittest.cc',
+        'platform_file_unittest.cc',
+        'posix/file_descriptor_shuffle_unittest.cc',
+        'pr_time_unittest.cc',
+        'process_util_unittest.cc',
+        'process_util_unittest_ios.cc',
+        'process_util_unittest_mac.h',
+        'process_util_unittest_mac.mm',
+        'profiler/tracked_time_unittest.cc',
+        'rand_util_unittest.cc',
+        'scoped_native_library_unittest.cc',
+        'scoped_observer.h',
+        'scoped_temp_dir_unittest.cc',
+        'sha1_unittest.cc',
+        'shared_memory_unittest.cc',
+        'string16_unittest.cc',
+        'string_number_conversions_unittest.cc',
+        'string_piece_unittest.cc',
+        'string_split_unittest.cc',
+        'string_tokenizer_unittest.cc',
+        'string_util_unittest.cc',
+        'stringize_macros_unittest.cc',
+        'stringprintf_unittest.cc',
+        'synchronization/cancellation_flag_unittest.cc',
+        'synchronization/condition_variable_unittest.cc',
+        'synchronization/lock_unittest.cc',
+        'synchronization/waitable_event_unittest.cc',
+        'synchronization/waitable_event_watcher_unittest.cc',
+        'sys_info_unittest.cc',
+        'sys_string_conversions_mac_unittest.mm',
+        'sys_string_conversions_unittest.cc',
+        'system_monitor/system_monitor_unittest.cc',
+        'task_runner_util_unittest.cc',
+        'template_util_unittest.cc',
+        'test/sequenced_worker_pool_owner.cc',
+        'test/sequenced_worker_pool_owner.h',
+        'test/trace_event_analyzer_unittest.cc',
+        'threading/non_thread_safe_unittest.cc',
+        'threading/platform_thread_unittest.cc',
+        'threading/sequenced_worker_pool_unittest.cc',
+        'threading/simple_thread_unittest.cc',
+        'threading/thread_checker_unittest.cc',
+        'threading/thread_collision_warner_unittest.cc',
+        'threading/thread_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_unittest.cc',
+        'time_win_unittest.cc',
+        'timer_unittest.cc',
+        'tools_sanity_unittest.cc',
+        'tracked_objects_unittest.cc',
+        'tuple_unittest.cc',
+        'utf_offset_string_conversions_unittest.cc',
+        'utf_string_conversions_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/object_watcher_unittest.cc',
+        'win/pe_image_unittest.cc',
+        'win/registry_unittest.cc',
+        'win/sampling_profiler_unittest.cc',
+        'win/scoped_bstr_unittest.cc',
+        'win/scoped_comptr_unittest.cc',
+        'win/scoped_process_information_unittest.cc',
+        'win/shortcut_unittest.cc',
+        'win/startup_information_unittest.cc',
+        'win/scoped_variant_unittest.cc',
+        'win/win_util_unittest.cc',
+        'win/wrapped_window_proc_unittest.cc',
+      ],
+      'dependencies': [
+        'base',
+        'base_i18n',
+        'base_static',
+        'run_all_unittests',
+        'test_support_base',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        '../third_party/icu/icu.gyp:icui18n',
+        '../third_party/icu/icu.gyp:icuuc',
+      ],
+      'includes': ['../build/nocompile.gypi'],
+      'variables': {
+         # TODO(ajwong): Is there a way to autodetect this?
+        'module_dir': 'base'
+      },
+      'conditions': [
+        ['OS == "android"', {
+          'dependencies': [
+            'android/jni_generator/jni_generator.gyp:jni_generator_tests',
+          ],
+          'conditions': [
+            ['gtest_target_type == "shared_library"', {
+              'dependencies': [
+                '../testing/android/native_test.gyp:native_test_native_code',
+              ],
+            }],
+          ],
+        }],
+        ['OS == "ios"', {
+          'sources/': [
+            # Only test the iOS-meaningful portion of process_utils.
+            ['exclude', '^process_util_unittest'],
+            ['include', '^process_util_unittest_ios\\.cc$'],
+            # Requires spawning processes.
+            ['exclude', '^metrics/stats_table_unittest\\.cc$'],
+            # TODO(ios): Remove these as base/ is unforked.
+            # For now, exclude everything that doesn't build as-is, just to
+            # get a minimal target building.
+            # Unittests that don't pass.
+            ['exclude', '^message_loop_unittest\\.cc$'],
+          ],
+          'conditions': [
+            ['coverage != 0', {
+              'sources!': [
+                # These sources can't be built with coverage due to a toolchain
+                # bug: http://openradar.appspot.com/radar?id=1499403
+                'json/json_reader_unittest.cc',
+                'string_piece_unittest.cc',
+
+                # These tests crash when run with coverage turned on due to an
+                # issue with llvm_gcda_increment_indirect_counter:
+                # http://crbug.com/156058
+                'debug/trace_event_unittest.cc',
+                'debug/trace_event_unittest.h',
+                'logging_unittest.cc',
+                'string_util_unittest.cc',
+                'test/trace_event_analyzer_unittest.cc',
+                'utf_offset_string_conversions_unittest.cc',
+              ],
+            }],
+          ],
+          'actions': [
+            {
+              'action_name': 'copy_test_data',
+              'variables': {
+                'test_data_files': [
+                  'data/json/bom_feff.json',
+                  'data/file_util_unittest',
+                ],
+                'test_data_prefix': 'base',
+              },
+              'includes': [ '../build/copy_test_data_ios.gypi' ],
+            },
+          ],
+        }],
+        ['use_glib==1', {
+          'sources!': [
+            'file_version_info_unittest.cc',
+          ],
+          'conditions': [
+            [ 'linux_use_tcmalloc==1', {
+                'dependencies': [
+                  'allocator/allocator.gyp:allocator',
+                ],
+              },
+            ],
+            [ 'toolkit_uses_gtk==1', {
+              'sources': [
+                'nix/xdg_util_unittest.cc',
+              ],
+              'dependencies': [
+                '../build/linux/system.gyp:gtk',
+              ]
+            }],
+          ],
+          'dependencies': [
+            '../build/linux/system.gyp:glib',
+            '../build/linux/system.gyp:ssl',
+            '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
+          ],
+        }, {  # use_glib!=1
+          'sources!': [
+            'message_pump_glib_unittest.cc',
+          ]
+        }],
+        # This is needed to trigger the dll copy step on windows.
+        # TODO(mark): This should not be necessary.
+        ['OS == "win"', {
+          'dependencies': [
+            '../third_party/icu/icu.gyp:icudata',
+          ],
+          'sources!': [
+            'file_descriptor_shuffle_unittest.cc',
+            'files/dir_reader_posix_unittest.cc',
+            'threading/worker_pool_posix_unittest.cc',
+            'message_pump_libevent_unittest.cc',
+          ],
+        }, {  # OS != "win"
+          'dependencies': [
+            '../third_party/libevent/libevent.gyp:libevent'
+          ],
+          'sources/': [
+            ['exclude', '^win/'],
+          ],
+          'sources!': [
+            'debug/trace_event_win_unittest.cc',
+            'time_win_unittest.cc',
+            'win/win_util_unittest.cc',
+          ],
+        }],
+      ],  # conditions
+      'target_conditions': [
+        ['OS == "ios"', {
+          'sources/': [
+            # Pull in specific Mac files for iOS (which have been filtered out
+            # by file name rules).
+            ['include', '^mac/objc_property_releaser_unittest\\.mm$'],
+            ['include', '^mac/bind_objc_block_unittest\\.mm$'],
+            ['include', '^sys_string_conversions_mac_unittest\\.mm$'],
+          ],
+        }],
+      ],  # target_conditions
+    },
+    {
+      'target_name': 'test_support_base',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+        'base_static',
+        'base_i18n',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'export_dependent_settings': [
+        'base',
+      ],
+      'conditions': [
+        ['toolkit_uses_gtk==1', {
+          'dependencies': [
+            # test_suite initializes GTK.
+            '../build/linux/system.gyp:gtk',
+          ],
+        }],
+        ['os_posix==0', {
+          'sources!': [
+            'test/scoped_locale.cc',
+            'test/scoped_locale.h',
+          ],
+        }],
+        ['os_bsd==1', {
+          'sources!': [
+            'test/test_file_util_linux.cc',
+          ],
+        }],
+        ['OS=="win"', {
+          'direct_dependent_settings': {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'DelayLoadDLLs': [
+                  'propsys.dll',
+                ],
+              },
+            },
+          },
+        }],
+      ],
+      'sources': [
+        'perftimer.cc',
+        'test/main_hook.cc',
+        'test/main_hook.h',
+        'test/main_hook_ios.mm',
+        '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_time_provider.cc',
+        'test/mock_time_provider.h',
+        'test/multiprocess_test.cc',
+        'test/multiprocess_test.h',
+        'test/multiprocess_test_android.cc',
+        'test/perf_test_suite.cc',
+        'test/perf_test_suite.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/task_runner_test_template.cc',
+        'test/task_runner_test_template.h',
+        'test/test_file_util.h',
+        '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_listener_ios.h',
+        'test/test_listener_ios.mm',
+        'test/test_reg_util_win.cc',
+        'test/test_reg_util_win.h',
+        'test/test_shortcut_win.cc',
+        'test/test_shortcut_win.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/thread_test_helper.cc',
+        'test/thread_test_helper.h',
+        'test/trace_event_analyzer.cc',
+        'test/trace_event_analyzer.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$'],
+          ],
+        }],
+      ],  # target_conditions
+    },
+    {
+      'target_name': 'test_support_perf',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'perftimer.cc',
+        'test/run_all_perftests.cc',
+      ],
+      'direct_dependent_settings': {
+        'defines': [
+          'PERF_TEST',
+        ],
+      },
+      'conditions': [
+        ['toolkit_uses_gtk==1', {
+          'dependencies': [
+            # Needed to handle the #include chain:
+            #   base/test/perf_test_suite.h
+            #   base/test/test_suite.h
+            #   gtk/gtk.h
+            '../build/linux/system.gyp:gtk',
+          ],
+        }],
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS!="ios"', {
+      'targets': [
+        {
+          'target_name': 'check_example',
+          'type': 'executable',
+          'sources': [
+            'check_example.cc',
+          ],
+          'dependencies': [
+            'base',
+          ],
+        },
+      ],
+    }],
+    ['OS == "win"', {
+      'targets': [
+        {
+          'target_name': 'base_nacl_win64',
+          'type': '<(component)',
+          'variables': {
+            'base_target': 1,
+          },
+          'dependencies': [
+            'base_static_win64',
+            'allocator/allocator.gyp:allocator_extension_thunks_win64',
+            'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
+          ],
+          # 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)',
+          ],
+          'sources!': [
+            # base64.cc depends on modp_b64.
+            'base64.cc',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+          'conditions': [
+            ['component == "shared_library"', {
+              'sources!': [
+                'debug/debug_on_start_win.cc',
+              ],
+            }],
+          ],
+        },
+        {
+          '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',
+            },
+          },
+        },
+      ],
+    }],
+    ['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',
+          ],
+          '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': [
+            '..',
+          ],
+        },
+        {
+          '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',
+          ],
+        },
+      ],
+    }],
+    ['OS == "android"', {
+      'targets': [
+        {
+          'target_name': 'base_jni_headers',
+          'type': 'none',
+          'sources': [
+            'android/java/src/org/chromium/base/BuildInfo.java',
+            'android/java/src/org/chromium/base/LocaleUtils.java',
+            'android/java/src/org/chromium/base/PathService.java',
+            'android/java/src/org/chromium/base/PathUtils.java',
+            'android/java/src/org/chromium/base/SystemMessageHandler.java',
+            'android/java/src/org/chromium/base/SystemMonitor.java',
+          ],
+          'variables': {
+            'jni_gen_dir': 'base',
+          },
+          'includes': [ '../build/jni_generator.gypi' ],
+        },
+        {
+          'target_name': 'base_java',
+          'type': 'none',
+          'variables': {
+            'package_name': 'base',
+            'java_in_dir': '../base/android/java',
+          },
+          'includes': [ '../build/java.gypi' ],
+        },
+        {
+          'target_name': 'base_java_test_support',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+          ],
+          'variables': {
+            'package_name': 'base_javatests',
+            'java_in_dir': '../base/test/android/javatests',
+          },
+          'includes': [ '../build/java.gypi' ],
+        },
+      ],
+    }],
+    ['OS == "win"', {
+      'targets': [
+        {
+          'target_name': 'debug_message',
+          'type': 'executable',
+          'sources': [
+            'debug_message.cc',
+          ],
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+            },
+          },
+        },
+      ],
+    }],
+    # Special target to wrap a gtest_target_type == shared_library
+    # base_unittests into an android apk for execution.
+    # TODO(jrg): lib.target comes from _InstallableTargetInstallPath()
+    # in the gyp make generator.  What is the correct way to extract
+    # this path from gyp and into 'raw' for input to antfiles?
+    # Hard-coding in the gypfile seems a poor choice.
+    ['OS == "android" and gtest_target_type == "shared_library"', {
+      'targets': [
+        {
+          'target_name': 'base_unittests_apk',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+            'base_unittests',
+          ],
+          'variables': {
+            'test_suite_name': 'base_unittests',
+            'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)base_unittests<(SHARED_LIB_SUFFIX)',
+          },
+          'includes': [ '../build/apk_test.gypi' ],
+        },
+      ],
+    }],
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'base_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'base_unittests',
+          ],
+          'includes': [
+            '../build/isolate.gypi',
+            'base_unittests.isolate',
+          ],
+          'sources': [
+            'base_unittests.isolate',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/base.gypi b/base/base.gypi
new file mode 100644
index 0000000..977cc02
--- /dev/null
+++ b/base/base.gypi
@@ -0,0 +1,723 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'variables': {
+      'base_target': 0,
+    },
+    'target_conditions': [
+      # This part is shared between the targets defined below.
+      ['base_target==1', {
+        'sources': [
+          '../build/build_config.h',
+          'third_party/dmg_fp/dmg_fp.h',
+          'third_party/dmg_fp/g_fmt.cc',
+          'third_party/dmg_fp/dtoa_wrapper.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/nspr/prcpucfg_linux.h',
+          'third_party/xdg_mime/xdgmime.h',
+          'allocator/allocator_extension.cc',
+          'allocator/allocator_extension.h',
+          'allocator/type_profiler_control.cc',
+          'allocator/type_profiler_control.h',
+          'android/base_jni_registrar.cc',
+          'android/base_jni_registrar.h',
+          'android/build_info.cc',
+          'android/build_info.h',
+          'android/scoped_java_ref.cc',
+          'android/scoped_java_ref.h',
+          'android/jni_android.cc',
+          'android/jni_android.h',
+          'android/jni_array.cc',
+          'android/jni_array.h',
+          'android/jni_helper.cc',
+          'android/jni_helper.h',
+          'android/jni_registrar.cc',
+          'android/jni_registrar.h',
+          'android/jni_string.cc',
+          'android/jni_string.h',
+          'android/locale_utils.cc',
+          'android/locale_utils.h',
+          'android/path_service_android.cc',
+          'android/path_service_android.h',
+          'android/path_utils.cc',
+          'android/path_utils.h',
+          'at_exit.cc',
+          'at_exit.h',
+          'atomic_ref_count.h',
+          'atomic_sequence_num.h',
+          'atomicops.h',
+          'atomicops_internals_gcc.h',
+          'atomicops_internals_mac.h',
+          'atomicops_internals_tsan.h',
+          'atomicops_internals_x86_gcc.cc',
+          'atomicops_internals_x86_gcc.h',
+          'atomicops_internals_x86_msvc.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',
+          'base64.cc',
+          'base64.h',
+          'basictypes.h',
+          'bind.h',
+          'bind_helpers.cc',
+          'bind_helpers.h',
+          'bind_internal.h',
+          'bind_internal_win.h',
+          'bits.h',
+          'build_time.cc',
+          'build_time.h',
+          'callback.h',
+          'callback_helpers.h',
+          'callback_internal.cc',
+          'callback_internal.h',
+          'cancelable_callback.h',
+          'chromeos/chromeos_version.cc',
+          'chromeos/chromeos_version.h',
+          'command_line.cc',
+          'command_line.h',
+          'compiler_specific.h',
+          'containers/linked_list.h',
+          'containers/small_map.h',
+          'containers/stack_container.h',
+          'cpu.cc',
+          'cpu.h',
+          'critical_closure.h',
+          'critical_closure_ios.mm',
+          'debug/alias.cc',
+          'debug/alias.h',
+          'debug/debug_on_start_win.cc',
+          'debug/debug_on_start_win.h',
+          'debug/debugger.cc',
+          'debug/debugger.h',
+          'debug/debugger_posix.cc',
+          'debug/debugger_win.cc',
+          'debug/leak_annotations.h',
+          'debug/leak_tracker.h',
+          'debug/profiler.cc',
+          'debug/profiler.h',
+          'debug/stack_trace.cc',
+          'debug/stack_trace.h',
+          'debug/stack_trace_android.cc',
+          'debug/stack_trace_ios.mm',
+          'debug/stack_trace_posix.cc',
+          'debug/stack_trace_win.cc',
+          'debug/trace_event.cc',
+          'debug/trace_event.h',
+          'debug/trace_event_android.cc',
+          'debug/trace_event_impl.cc',
+          'debug/trace_event_impl.h',
+          'debug/trace_event_win.cc',
+          'eintr_wrapper.h',
+          'environment.cc',
+          'environment.h',
+          'file_descriptor_posix.h',
+          'file_path.cc',
+          'file_path.h',
+          'file_util.cc',
+          'file_util.h',
+          'file_util_android.cc',
+          'file_util_linux.cc',
+          'file_util_mac.mm',
+          'file_util_posix.cc',
+          'file_util_win.cc',
+          'file_util_proxy.cc',
+          'file_util_proxy.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_path_watcher.cc',
+          'files/file_path_watcher.h',
+          'files/file_path_watcher_kqueue.cc',
+          'files/file_path_watcher_linux.cc',
+          'files/file_path_watcher_stub.cc',
+          'files/file_path_watcher_win.cc',
+          'files/important_file_writer.h',
+          'files/important_file_writer.cc',
+          'float_util.h',
+          'format_macros.h',
+          'gtest_prod_util.h',
+          'guid.cc',
+          'guid.h',
+          'guid_posix.cc',
+          'guid_win.cc',
+          'hash.cc',
+          'hash.h',
+          'hash_tables.h',
+          'hi_res_timer_manager_posix.cc',
+          'hi_res_timer_manager_win.cc',
+          'hi_res_timer_manager.h',
+          'id_map.h',
+          'ios/device_util.h',
+          'ios/device_util.mm',
+          'ios/ios_util.h',
+          'ios/ios_util.mm',
+          'ios/scoped_critical_action.h',
+          'ios/scoped_critical_action.mm',
+          '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.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/bind_objc_block.mm',
+          'mac/bundle_locations.h',
+          'mac/bundle_locations.mm',
+          'mac/cocoa_protocols.h',
+          'mac/crash_logging.h',
+          'mac/crash_logging.mm',
+          'mac/foundation_util.h',
+          'mac/foundation_util.mm',
+          'mac/launchd.cc',
+          'mac/launchd.h',
+          'mac/mac_logging.h',
+          'mac/mac_logging.cc',
+          'mac/mac_util.h',
+          'mac/mac_util.mm',
+          '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_cftyperef.h',
+          'mac/scoped_ioobject.h',
+          'mac/scoped_launch_data.h',
+          'mac/scoped_mach_port.cc',
+          'mac/scoped_mach_port.h',
+          'mac/scoped_nsautorelease_pool.h',
+          'mac/scoped_nsautorelease_pool.mm',
+          'mac/scoped_nsexception_enabler.h',
+          'mac/scoped_nsexception_enabler.mm',
+          'mac/scoped_sending_event.h',
+          'mac/scoped_sending_event.mm',
+          'mach_ipc_mac.h',
+          'mach_ipc_mac.mm',
+          'memory/aligned_memory.cc',
+          'memory/aligned_memory.h',
+          'memory/linked_ptr.h',
+          'memory/manual_constructor.h',
+          'memory/mru_cache.h',
+          'memory/raw_scoped_refptr_mismatch_checker.h',
+          'memory/ref_counted.cc',
+          'memory/ref_counted.h',
+          'memory/ref_counted_memory.cc',
+          'memory/ref_counted_memory.h',
+          'memory/scoped_handle.h',
+          'memory/scoped_nsobject.h',
+          'memory/scoped_open_process.h',
+          'memory/scoped_policy.h',
+          'memory/scoped_ptr.h',
+          'memory/scoped_vector.h',
+          'memory/singleton.cc',
+          'memory/singleton.h',
+          'memory/weak_ptr.cc',
+          'memory/weak_ptr.h',
+          'message_loop.cc',
+          'message_loop.h',
+          'message_loop_proxy.cc',
+          'message_loop_proxy.h',
+          'message_loop_proxy_impl.cc',
+          'message_loop_proxy_impl.h',
+          'message_pump.cc',
+          'message_pump.h',
+          'message_pump_android.cc',
+          'message_pump_android.h',
+          'message_pump_default.cc',
+          'message_pump_default.h',
+          'message_pump_win.cc',
+          'message_pump_win.h',
+          'metrics/sample_map.cc',
+          'metrics/sample_map.h',
+          'metrics/sample_vector.cc',
+          'metrics/sample_vector.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_flattener.h',
+          'metrics/histogram_samples.cc',
+          'metrics/histogram_samples.h',
+          'metrics/histogram_snapshot_manager.cc',
+          'metrics/histogram_snapshot_manager.h',
+          'metrics/sparse_histogram.cc',
+          'metrics/sparse_histogram.h',
+          'metrics/statistics_recorder.cc',
+          'metrics/statistics_recorder.h',
+          'metrics/stats_counters.cc',
+          'metrics/stats_counters.h',
+          'metrics/stats_table.cc',
+          'metrics/stats_table.h',
+          'move.h',
+          'native_library.h',
+          'native_library_mac.mm',
+          'native_library_posix.cc',
+          'native_library_win.cc',
+          'observer_list.h',
+          'observer_list_threadsafe.h',
+          'os_compat_android.cc',
+          'os_compat_android.h',
+          'os_compat_nacl.cc',
+          'os_compat_nacl.h',
+          'path_service.cc',
+          'path_service.h',
+          'pending_task.cc',
+          'pending_task.h',
+          'pickle.cc',
+          'pickle.h',
+          'platform_file.cc',
+          'platform_file.h',
+          'platform_file_posix.cc',
+          'platform_file_win.cc',
+          'port.h',
+          'posix/global_descriptors.cc',
+          'posix/global_descriptors.h',
+          'posix/unix_domain_socket.cc',
+          'posix/unix_domain_socket.h',
+          'process.h',
+          'process_info.h',
+          'process_info_mac.cc',
+          'process_info_win.cc',
+          'process_linux.cc',
+          'process_posix.cc',
+          'process_util.cc',
+          'process_util.h',
+          'process_util_freebsd.cc',
+          'process_util_ios.mm',
+          'process_util_linux.cc',
+          'process_util_mac.mm',
+          'process_util_openbsd.cc',
+          'process_util_posix.cc',
+          'process_util_win.cc',
+          'process_win.cc',
+          'profiler/scoped_profile.cc',
+          'profiler/scoped_profile.h',
+          'profiler/alternate_timer.cc',
+          'profiler/alternate_timer.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',
+          'safe_strerror_posix.cc',
+          'safe_strerror_posix.h',
+          'scoped_native_library.cc',
+          'scoped_native_library.h',
+          'scoped_temp_dir.cc',
+          'scoped_temp_dir.h',
+          'sequenced_task_runner.cc',
+          'sequenced_task_runner.h',
+          'sequenced_task_runner_helpers.h',
+          'sha1.h',
+          'sha1_portable.cc',
+          'sha1_win.cc',
+          'shared_memory.h',
+          'shared_memory_android.cc',
+          'shared_memory_nacl.cc',
+          'shared_memory_posix.cc',
+          'shared_memory_win.cc',
+          'single_thread_task_runner.h',
+          'stl_util.h',
+          'string_number_conversions.cc',
+          'string_number_conversions.h',
+          'string_piece.cc',
+          'string_piece.h',
+          'string_split.cc',
+          'string_split.h',
+          'string_tokenizer.h',
+          'string_util.cc',
+          'string_util.h',
+          'string_util_posix.h',
+          'string_util_win.h',
+          'string16.cc',
+          'string16.h',
+          'stringize_macros.h',
+          'stringprintf.cc',
+          'stringprintf.h',
+          'supports_user_data.cc',
+          'supports_user_data.h',
+          'synchronization/cancellation_flag.cc',
+          'synchronization/cancellation_flag.h',
+          'synchronization/condition_variable.h',
+          'synchronization/condition_variable_posix.cc',
+          'synchronization/condition_variable_win.cc',
+          'synchronization/lock.cc',
+          'synchronization/lock.h',
+          'synchronization/lock_impl.h',
+          'synchronization/lock_impl_posix.cc',
+          'synchronization/lock_impl_win.cc',
+          'synchronization/spin_wait.h',
+          'synchronization/waitable_event.h',
+          'synchronization/waitable_event_posix.cc',
+          'synchronization/waitable_event_watcher.h',
+          'synchronization/waitable_event_watcher_posix.cc',
+          'synchronization/waitable_event_watcher_win.cc',
+          'synchronization/waitable_event_win.cc',
+          'system_monitor/system_monitor.cc',
+          'system_monitor/system_monitor.h',
+          'system_monitor/system_monitor_android.cc',
+          'system_monitor/system_monitor_android.h',
+          'system_monitor/system_monitor_ios.mm',
+          'system_monitor/system_monitor_mac.mm',
+          'system_monitor/system_monitor_posix.cc',
+          'system_monitor/system_monitor_win.cc',
+          'sys_byteorder.h',
+          'sys_info.cc',
+          'sys_info.h',
+          'sys_info_android.cc',
+          'sys_info_chromeos.cc',
+          'sys_info_freebsd.cc',
+          'sys_info_ios.mm',
+          'sys_info_linux.cc',
+          'sys_info_mac.cc',
+          'sys_info_openbsd.cc',
+          'sys_info_posix.cc',
+          'sys_info_win.cc',
+          'sys_string_conversions.h',
+          'sys_string_conversions_mac.mm',
+          'sys_string_conversions_posix.cc',
+          'sys_string_conversions_win.cc',
+          'task_runner.cc',
+          'task_runner.h',
+          'task_runner_util.h',
+          'template_util.h',
+          'thread_task_runner_handle.cc',
+          'thread_task_runner_handle.h',
+          'threading/non_thread_safe.h',
+          'threading/non_thread_safe_impl.cc',
+          'threading/non_thread_safe_impl.h',
+          'threading/platform_thread.h',
+          'threading/platform_thread_mac.mm',
+          'threading/platform_thread_posix.cc',
+          'threading/platform_thread_win.cc',
+          'threading/post_task_and_reply_impl.cc',
+          'threading/post_task_and_reply_impl.h',
+          'threading/sequenced_worker_pool.cc',
+          'threading/sequenced_worker_pool.h',
+          'threading/simple_thread.cc',
+          'threading/simple_thread.h',
+          'threading/thread.cc',
+          'threading/thread.h',
+          'threading/thread_checker.h',
+          'threading/thread_checker_impl.cc',
+          'threading/thread_checker_impl.h',
+          'threading/thread_collision_warner.cc',
+          'threading/thread_collision_warner.h',
+          'threading/thread_local.h',
+          'threading/thread_local_posix.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.h',
+          'threading/thread_restrictions.cc',
+          'threading/watchdog.cc',
+          'threading/watchdog.h',
+          'threading/worker_pool.h',
+          'threading/worker_pool.cc',
+          'threading/worker_pool_posix.cc',
+          'threading/worker_pool_posix.h',
+          'threading/worker_pool_win.cc',
+          'time.cc',
+          'time.h',
+          'time_mac.cc',
+          'time_posix.cc',
+          'time_win.cc',
+          'timer.cc',
+          'timer.h',
+          'tracked_objects.cc',
+          'tracked_objects.h',
+          'tracking_info.cc',
+          'tracking_info.h',
+          'tuple.h',
+          'utf_offset_string_conversions.cc',
+          'utf_offset_string_conversions.h',
+          'utf_string_conversion_utils.cc',
+          'utf_string_conversion_utils.h',
+          'utf_string_conversions.cc',
+          'utf_string_conversions.h',
+          'values.cc',
+          'values.h',
+          'value_conversions.cc',
+          'value_conversions.h',
+          'version.cc',
+          'version.h',
+          'vlog.cc',
+          'vlog.h',
+          'nix/mime_util_xdg.cc',
+          'nix/mime_util_xdg.h',
+          'nix/xdg_util.cc',
+          'nix/xdg_util.h',
+          'win/enum_variant.h',
+          'win/enum_variant.cc',
+          '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.h',
+          'win/iunknown_impl.cc',
+          'win/metro.cc',
+          'win/metro.h',
+          'win/object_watcher.cc',
+          'win/object_watcher.h',
+          'win/registry.cc',
+          'win/registry.h',
+          'win/resource_util.cc',
+          'win/resource_util.h',
+          'win/sampling_profiler.cc',
+          'win/sampling_profiler.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_select_object.h',
+          'win/shortcut.cc',
+          'win/shortcut.h',
+          'win/startup_information.cc',
+          'win/startup_information.h',
+          'win/scoped_variant.cc',
+          'win/scoped_variant.h',
+          'win/text_services_message_filter.cc',
+          'win/text_services_message_filter.h',
+          'win/windows_version.cc',
+          'win/windows_version.h',
+          'win/win_util.cc',
+          'win/win_util.h',
+          'win/wrapped_window_proc.cc',
+          'win/wrapped_window_proc.h',
+        ],
+        'defines': [
+          'BASE_IMPLEMENTATION',
+        ],
+        'include_dirs': [
+          '..',
+        ],
+        'msvs_disabled_warnings': [
+          4018,
+        ],
+        'target_conditions': [
+          ['<(use_glib)==0 or >(nacl_untrusted_build)==1', {
+              'sources/': [
+                ['exclude', '^nix/'],
+              ],
+              'sources!': [
+                'atomicops_internals_x86_gcc.cc',
+                'message_pump_glib.cc',
+                'message_pump_aurax11.cc',
+              ],
+          }],
+          ['<(toolkit_uses_gtk)==0 or >(nacl_untrusted_build)==1', {
+            'sources!': ['message_pump_gtk.cc'],
+          }],
+          ['(OS != "linux" and <(os_bsd) != 1 and OS != "android") or >(nacl_untrusted_build)==1', {
+              'sources!': [
+                # Not automatically excluded by the *linux.cc rules.
+                'linux_util.cc',
+              ],
+            },
+          ],
+          ['>(nacl_untrusted_build)==1', {
+            'sources!': [
+               'allocator/type_profiler_control.cc',
+               'allocator/type_profiler_control.h',
+               'base_paths.cc',
+               'command_line.cc',
+               'cpu.cc',
+               'debug/stack_trace_posix.cc',
+               'file_util.cc',
+               'file_util_posix.cc',
+               'file_util_proxy.cc',
+               'files/file_path_watcher_kqueue.cc',
+               'native_library_posix.cc',
+               'path_service.cc',
+               'platform_file_posix.cc',
+               'posix/unix_domain_socket.cc',
+               'process_posix.cc',
+               'process_util.cc',
+               'process_util_posix.cc',
+               'rand_util_posix.cc',
+               'scoped_native_library.cc',
+               'scoped_temp_dir.cc',
+               'shared_memory_posix.cc',
+               'sys_info_posix.cc',
+               'threading/sequenced_worker_pool.cc',
+               'third_party/dynamic_annotations/dynamic_annotations.c',
+            ],
+            # Metrics won't work in the NaCl sandbox.
+            'sources/': [ ['exclude', '^metrics/'] ],
+          }],
+          ['OS == "android" and >(nacl_untrusted_build)==0', {
+            'sources!': [
+              'base_paths_posix.cc',
+              'files/file_path_watcher_kqueue.cc',
+              'files/file_path_watcher_stub.cc',
+              'system_monitor/system_monitor_posix.cc',
+            ],
+            'sources/': [
+              ['include', '^files/file_path_watcher_linux\\.cc$'],
+              ['include', '^process_util_linux\\.cc$'],
+              ['include', '^sys_info_linux\\.cc$'],
+              ['include', '^sys_string_conversions_posix\\.cc$'],
+              ['include', '^worker_pool_linux\\.cc$'],
+            ],
+          }],
+          ['OS == "ios"', {
+            'sources/': [
+              # Pull in specific Mac files for iOS (which have been filtered out
+              # by file name rules).
+              ['include', '^atomicops_internals_mac\\.'],
+              ['include', '^base_paths_mac\\.'],
+              ['include', '^file_util_mac\\.'],
+              ['include', '^file_version_info_mac\\.'],
+              ['include', '^mac/bind_objc_block\\.'],
+              ['include', '^mac/bundle_locations\\.'],
+              ['include', '^mac/foundation_util\\.'],
+              ['include', '^mac/mac_logging\\.'],
+              ['include', '^mac/objc_property_releaser\\.'],
+              ['include', '^mac/scoped_mach_port\\.'],
+              ['include', '^mac/scoped_nsautorelease_pool\\.'],
+              ['include', '^message_pump_mac\\.'],
+              ['include', '^threading/platform_thread_mac\\.'],
+              ['include', '^sys_string_conversions_mac\\.'],
+              ['include', '^time_mac\\.'],
+              ['include', '^worker_pool_mac\\.'],
+              # Exclude all process_util except the minimal implementation
+              # needed on iOS (mostly for unit tests).
+              ['exclude', '^process_util'],
+              ['include', '^process_util_ios\\.mm$'],
+            ],
+          }],
+          ['OS != "mac" or >(nacl_untrusted_build)==1', {
+              'sources!': [
+                'mac/scoped_aedesc.h'
+              ],
+          }],
+          # 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" or >(nacl_untrusted_build)==1', {
+              'sources/': [ ['exclude', '^win/'] ],
+            },
+          ],
+          ['OS != "android" or >(nacl_untrusted_build)==1', {
+              'sources/': [ ['exclude', '^android/'] ],
+            },
+          ],
+          ['OS == "win" and >(nacl_untrusted_build)==0', {
+            'include_dirs': [
+              '<(DEPTH)/third_party/wtl/include',
+            ],
+            'sources!': [
+              'event_recorder_stubs.cc',
+              'files/file_path_watcher_kqueue.cc',
+              'files/file_path_watcher_stub.cc',
+              'message_pump_libevent.cc',
+              'posix/file_descriptor_shuffle.cc',
+              # Not using sha1_win.cc because it may have caused a
+              # regression to page cycler moz.
+              'sha1_win.cc',
+              'string16.cc',
+            ],
+          },],
+          ['OS == "linux" and >(nacl_untrusted_build)==0', {
+            'sources!': [
+              'files/file_path_watcher_kqueue.cc',
+              'files/file_path_watcher_stub.cc',
+            ],
+          }],
+          ['(OS == "mac" or OS == "ios") and >(nacl_untrusted_build)==0', {
+            'sources/': [
+              ['exclude', '^files/file_path_watcher_stub\\.cc$'],
+              ['exclude', '^base_paths_posix\\.cc$'],
+              ['exclude', '^native_library_posix\\.cc$'],
+              ['exclude', '^sys_string_conversions_posix\\.cc$'],
+            ],
+          }],
+          ['<(os_bsd)==1 and >(nacl_untrusted_build)==0', {
+            'sources/': [
+              ['exclude', '^files/file_path_watcher_linux\\.cc$'],
+              ['exclude', '^files/file_path_watcher_stub\\.cc$'],
+              ['exclude', '^file_util_linux\\.cc$'],
+              ['exclude', '^process_linux\\.cc$'],
+              ['exclude', '^process_util_linux\\.cc$'],
+              ['exclude', '^sys_info_linux\\.cc$'],
+            ],
+          }],
+          ['<(chromeos)!=1 or >(nacl_untrusted_build)==1', {
+            'sources/': [
+              ['exclude', '^chromeos/'],
+            ],
+          }],
+          # 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$'] ],
+          }],
+        ],
+      }],
+    ],
+  },
+}
diff --git a/base/base.target.mk b/base/base.target.mk
new file mode 100644
index 0000000..8d7c35e
--- /dev/null
+++ b/base/base.target.mk
@@ -0,0 +1,316 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := base_base_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,GYP,testing_gtest_prod_gyp)/gtest_prod.stamp \
+	$(call intermediates-dir-for,GYP,base_base_jni_headers_gyp)/base_jni_headers.stamp \
+	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	base/event_recorder_stubs.cc \
+	base/linux_util.cc \
+	base/md5.cc \
+	base/message_pump_android.cc \
+	base/message_pump_libevent.cc \
+	base/metrics/field_trial.cc \
+	base/posix/file_descriptor_shuffle.cc \
+	base/sync_socket_posix.cc \
+	base/third_party/dmg_fp/g_fmt.cc \
+	base/third_party/dmg_fp/dtoa_wrapper.cc \
+	base/third_party/icu/icu_utf.cc \
+	base/third_party/nspr/prtime.cc \
+	base/allocator/allocator_extension.cc \
+	base/allocator/type_profiler_control.cc \
+	base/android/base_jni_registrar.cc \
+	base/android/build_info.cc \
+	base/android/scoped_java_ref.cc \
+	base/android/jni_android.cc \
+	base/android/jni_array.cc \
+	base/android/jni_helper.cc \
+	base/android/jni_registrar.cc \
+	base/android/jni_string.cc \
+	base/android/locale_utils.cc \
+	base/android/path_service_android.cc \
+	base/android/path_utils.cc \
+	base/at_exit.cc \
+	base/base_paths.cc \
+	base/base_paths_android.cc \
+	base/base64.cc \
+	base/bind_helpers.cc \
+	base/build_time.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/profiler.cc \
+	base/debug/stack_trace.cc \
+	base/debug/stack_trace_android.cc \
+	base/debug/trace_event.cc \
+	base/debug/trace_event_android.cc \
+	base/debug/trace_event_impl.cc \
+	base/environment.cc \
+	base/file_path.cc \
+	base/file_util.cc \
+	base/file_util_android.cc \
+	base/file_util_posix.cc \
+	base/file_util_proxy.cc \
+	base/files/file_path_watcher.cc \
+	base/files/file_path_watcher_linux.cc \
+	base/files/important_file_writer.cc \
+	base/guid.cc \
+	base/guid_posix.cc \
+	base/hash.cc \
+	base/hi_res_timer_manager_posix.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_writer.cc \
+	base/json/string_escape.cc \
+	base/lazy_instance.cc \
+	base/location.cc \
+	base/logging.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.cc \
+	base/message_loop_proxy.cc \
+	base/message_loop_proxy_impl.cc \
+	base/message_pump.cc \
+	base/message_pump_default.cc \
+	base/metrics/sample_map.cc \
+	base/metrics/sample_vector.cc \
+	base/metrics/bucket_ranges.cc \
+	base/metrics/histogram.cc \
+	base/metrics/histogram_base.cc \
+	base/metrics/histogram_samples.cc \
+	base/metrics/histogram_snapshot_manager.cc \
+	base/metrics/sparse_histogram.cc \
+	base/metrics/statistics_recorder.cc \
+	base/metrics/stats_counters.cc \
+	base/metrics/stats_table.cc \
+	base/native_library_posix.cc \
+	base/os_compat_android.cc \
+	base/path_service.cc \
+	base/pending_task.cc \
+	base/pickle.cc \
+	base/platform_file.cc \
+	base/platform_file_posix.cc \
+	base/posix/global_descriptors.cc \
+	base/posix/unix_domain_socket.cc \
+	base/process_posix.cc \
+	base/process_util.cc \
+	base/process_util_linux.cc \
+	base/process_util_posix.cc \
+	base/profiler/scoped_profile.cc \
+	base/profiler/alternate_timer.cc \
+	base/profiler/tracked_time.cc \
+	base/rand_util.cc \
+	base/rand_util_posix.cc \
+	base/run_loop.cc \
+	base/safe_strerror_posix.cc \
+	base/scoped_native_library.cc \
+	base/scoped_temp_dir.cc \
+	base/sequenced_task_runner.cc \
+	base/sha1_portable.cc \
+	base/shared_memory_android.cc \
+	base/shared_memory_posix.cc \
+	base/string_number_conversions.cc \
+	base/string_piece.cc \
+	base/string_split.cc \
+	base/string_util.cc \
+	base/string16.cc \
+	base/stringprintf.cc \
+	base/supports_user_data.cc \
+	base/synchronization/cancellation_flag.cc \
+	base/synchronization/condition_variable_posix.cc \
+	base/synchronization/lock.cc \
+	base/synchronization/lock_impl_posix.cc \
+	base/synchronization/waitable_event_posix.cc \
+	base/synchronization/waitable_event_watcher_posix.cc \
+	base/system_monitor/system_monitor.cc \
+	base/system_monitor/system_monitor_android.cc \
+	base/sys_info.cc \
+	base/sys_info_android.cc \
+	base/sys_info_linux.cc \
+	base/sys_info_posix.cc \
+	base/sys_string_conversions_posix.cc \
+	base/task_runner.cc \
+	base/thread_task_runner_handle.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_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_local_posix.cc \
+	base/threading/thread_local_storage_posix.cc \
+	base/threading/thread_restrictions.cc \
+	base/threading/watchdog.cc \
+	base/threading/worker_pool.cc \
+	base/threading/worker_pool_posix.cc \
+	base/time.cc \
+	base/time_posix.cc \
+	base/timer.cc \
+	base/tracked_objects.cc \
+	base/tracking_info.cc \
+	base/utf_offset_string_conversions.cc \
+	base/utf_string_conversion_utils.cc \
+	base/utf_string_conversions.cc \
+	base/values.cc \
+	base/value_conversions.cc \
+	base/version.cc \
+	base/vlog.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS := \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-mthumb \
+	-march=armv7-a \
+	-mtune=cortex-a8 \
+	-mfloat-abi=softfp \
+	-mfpu=vfpv3-d16 \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-mthumb-interwork \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-Wno-error=extra \
+	-Wno-error=ignored-qualifiers \
+	-Wno-error=type-limits \
+	-Wno-error=non-virtual-dtor \
+	-Wno-error=sign-promo \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_CFLAGS_C :=
+
+MY_DEFS := \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_PEPPER_THREADING' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DUSE_SKIA=1' \
+	'-DUSE_SYMBOLIZE' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-DUSE_SYSTEM_ICU' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DBASE_IMPLEMENTATION' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_SYMBOLS_ID=""' \
+	'-DANDROID_UPSTREAM_BRINGUP=1' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES := \
+	$(gyp_shared_intermediate_dir)/base \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/common \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/i18n \
+	$(LOCAL_PATH) \
+	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
+	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat
+
+### Rules for final target.
+
+LOCAL_LDFLAGS := \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections
+
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: base_base_gyp
+
+# Alias gyp target name.
+.PHONY: base
+base: base_base_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/base/base64.cc b/base/base64.cc
new file mode 100644
index 0000000..1907978
--- /dev/null
+++ b/base/base64.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base64.h"
+
+#include "third_party/modp_b64/modp_b64.h"
+
+namespace base {
+
+bool Base64Encode(const StringPiece& input, std::string* output) {
+  std::string temp;
+  temp.resize(modp_b64_encode_len(input.size()));  // makes room for null byte
+
+  // null terminates result since result is base64 text!
+  int input_size = static_cast<int>(input.size());
+
+  // modp_b64_encode_len() returns at least 1, so temp[0] is safe to use.
+  int output_size = modp_b64_encode(&(temp[0]), input.data(), input_size);
+  if (output_size < 0)
+    return false;
+
+  temp.resize(output_size);  // strips off null byte
+  output->swap(temp);
+  return true;
+}
+
+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!
+  int input_size = static_cast<int>(input.size());
+  int output_size = modp_b64_decode(&(temp[0]), input.data(), input_size);
+  if (output_size < 0)
+    return false;
+
+  temp.resize(output_size);
+  output->swap(temp);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/base64.h b/base/base64.h
new file mode 100644
index 0000000..983d5e2
--- /dev/null
+++ b/base/base64.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE64_H__
+#define BASE_BASE64_H__
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/string_piece.h"
+
+namespace base {
+
+// Encodes the input string in base64.  Returns true if successful and false
+// otherwise.  The output string is only modified if successful.
+BASE_EXPORT bool 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.
+BASE_EXPORT bool Base64Decode(const StringPiece& input, std::string* output);
+
+}  // namespace base
+
+#endif  // BASE_BASE64_H__
diff --git a/base/base64_unittest.cc b/base/base64_unittest.cc
new file mode 100644
index 0000000..9a5dd81
--- /dev/null
+++ b/base/base64_unittest.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/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;
+
+  ok = Base64Encode(kText, &encoded);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(kBase64Text, encoded);
+
+  ok = Base64Decode(encoded, &decoded);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(kText, decoded);
+}
+
+}  // namespace base
diff --git a/base/base_export.h b/base/base_export.h
new file mode 100644
index 0000000..723b38a
--- /dev/null
+++ b/base/base_export.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_EXPORT_H_
+#define BASE_BASE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __declspec(dllexport)
+#define BASE_EXPORT_PRIVATE __declspec(dllexport)
+#else
+#define BASE_EXPORT __declspec(dllimport)
+#define BASE_EXPORT_PRIVATE __declspec(dllimport)
+#endif  // defined(BASE_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __attribute__((visibility("default")))
+#define BASE_EXPORT_PRIVATE __attribute__((visibility("default")))
+#else
+#define BASE_EXPORT
+#define BASE_EXPORT_PRIVATE
+#endif  // defined(BASE_IMPLEMENTATION)
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define BASE_EXPORT
+#define BASE_EXPORT_PRIVATE
+#endif
+
+#endif  // BASE_BASE_EXPORT_H_
diff --git a/base/base_i18n.target.mk b/base/base_i18n.target.mk
new file mode 100644
index 0000000..09e2d5a
--- /dev/null
+++ b/base/base_i18n.target.mk
@@ -0,0 +1,165 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := base_base_i18n_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES := \
+	$(call intermediates-dir-for,GYP,third_party_icu_icui18n_gyp)/icui18n.stamp \
+	$(call intermediates-dir-for,GYP,third_party_icu_icuuc_gyp)/icuuc.stamp
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	base/i18n/bidi_line_iterator.cc \
+	base/i18n/break_iterator.cc \
+	base/i18n/char_iterator.cc \
+	base/i18n/case_conversion.cc \
+	base/i18n/file_util_icu.cc \
+	base/i18n/icu_encoding_detection.cc \
+	base/i18n/icu_string_conversions.cc \
+	base/i18n/icu_util.cc \
+	base/i18n/number_formatting.cc \
+	base/i18n/rtl.cc \
+	base/i18n/string_search.cc \
+	base/i18n/time_formatting.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS := \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-mthumb \
+	-march=armv7-a \
+	-mtune=cortex-a8 \
+	-mfloat-abi=softfp \
+	-mfpu=vfpv3-d16 \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-mthumb-interwork \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-Wno-error=extra \
+	-Wno-error=ignored-qualifiers \
+	-Wno-error=type-limits \
+	-Wno-error=non-virtual-dtor \
+	-Wno-error=sign-promo \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_CFLAGS_C :=
+
+MY_DEFS := \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_PEPPER_THREADING' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DUSE_SKIA=1' \
+	'-DBASE_I18N_IMPLEMENTATION' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-DUSE_SYSTEM_ICU' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_SYMBOLS_ID=""' \
+	'-DANDROID_UPSTREAM_BRINGUP=1' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH) \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/common \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/icu4c/i18n \
+	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
+	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat
+
+### Rules for final target.
+
+LOCAL_LDFLAGS := \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections
+
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: base_base_i18n_gyp
+
+# Alias gyp target name.
+.PHONY: base_i18n
+base_i18n: base_base_i18n_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/base/base_jni_headers.target.mk b/base/base_jni_headers.target.mk
new file mode 100644
index 0000000..f14ba22
--- /dev/null
+++ b/base/base_jni_headers.target.mk
@@ -0,0 +1,200 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := GYP
+LOCAL_MODULE := base_base_jni_headers_gyp
+LOCAL_MODULE_STEM := base_jni_headers
+LOCAL_MODULE_SUFFIX := .stamp
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+
+### Generated for rule "_usr_local_google_code_clank_master_ab_external_chromium_org_base_base_gyp_base_jni_headers_target_generate_jni_headers":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/LocaleUtils.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SystemMonitor.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+$(gyp_shared_intermediate_dir)/base/jni/BuildInfo_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/BuildInfo_jni.h: gyp_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/BuildInfo_jni.h: gyp_shared_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_shared_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/BuildInfo_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/BuildInfo.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/BuildInfo.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni"
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/BuildInfo_jni.h
+
+$(gyp_shared_intermediate_dir)/base/jni/LocaleUtils_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/LocaleUtils_jni.h: gyp_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/LocaleUtils_jni.h: gyp_shared_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_shared_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/LocaleUtils_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/LocaleUtils.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/LocaleUtils.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni"
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/LocaleUtils_jni.h
+
+$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_shared_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_shared_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/PathService.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/PathService.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni"
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h
+
+$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h: gyp_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h: gyp_shared_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_shared_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/PathUtils.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/PathUtils.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni"
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h
+
+$(gyp_shared_intermediate_dir)/base/jni/SystemMessageHandler_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/SystemMessageHandler_jni.h: gyp_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/SystemMessageHandler_jni.h: gyp_shared_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_shared_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/SystemMessageHandler_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/SystemMessageHandler.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/SystemMessageHandler.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni"
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/SystemMessageHandler_jni.h
+
+$(gyp_shared_intermediate_dir)/base/jni/SystemMonitor_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/SystemMonitor_jni.h: gyp_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/SystemMonitor_jni.h: gyp_shared_intermediate_dir := $(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_shared_intermediate_dir)
+$(gyp_shared_intermediate_dir)/base/jni/SystemMonitor_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/SystemMonitor.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/SystemMonitor.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni"
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/SystemMonitor_jni.h
+
+### Finished generating for all rules
+
+GYP_GENERATED_OUTPUTS := \
+	$(gyp_shared_intermediate_dir)/base/jni/BuildInfo_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/LocaleUtils_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/SystemMessageHandler_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/SystemMonitor_jni.h
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES := \
+	$(gyp_shared_intermediate_dir)/base/jni/BuildInfo_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/LocaleUtils_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/SystemMessageHandler_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/SystemMonitor_jni.h \
+	base_base_jni_headers_gyp_rule_trigger
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES :=
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS := \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-mthumb \
+	-march=armv7-a \
+	-mtune=cortex-a8 \
+	-mfloat-abi=softfp \
+	-mfpu=vfpv3-d16 \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-mthumb-interwork \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-Wno-error=extra \
+	-Wno-error=ignored-qualifiers \
+	-Wno-error=type-limits \
+	-Wno-error=non-virtual-dtor \
+	-Wno-error=sign-promo \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_CFLAGS_C :=
+
+MY_DEFS := \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_PEPPER_THREADING' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DUSE_SKIA=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_SYMBOLS_ID=""' \
+	'-DANDROID_UPSTREAM_BRINGUP=1' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES := \
+	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
+	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat
+
+### Rules for final target.
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: base_base_jni_headers_gyp
+
+# Alias gyp target name.
+.PHONY: base_jni_headers
+base_jni_headers: base_base_jni_headers_gyp
+
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/gyp_stamp
+LOCAL_UNINSTALLABLE_MODULE := true
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
+	$(hide) echo "Gyp timestamp: $@"
+	$(hide) mkdir -p $(dir $@)
+	$(hide) touch $@
diff --git a/base/base_paths.cc b/base/base_paths.cc
new file mode 100644
index 0000000..80105b6
--- /dev/null
+++ b/base/base_paths.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base_paths.h"
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+
+namespace base {
+
+bool PathProvider(int key, FilePath* result) {
+  // NOTE: DIR_CURRENT is a special case in PathService::Get
+
+  FilePath cur;
+  switch (key) {
+    case base::DIR_EXE:
+      PathService::Get(base::FILE_EXE, &cur);
+      cur = cur.DirName();
+      break;
+    case base::DIR_MODULE:
+      PathService::Get(base::FILE_MODULE, &cur);
+      cur = cur.DirName();
+      break;
+    case base::DIR_TEMP:
+      if (!file_util::GetTempDir(&cur))
+        return false;
+      break;
+    default:
+      return false;
+  }
+
+  *result = cur;
+  return true;
+}
+
+}  // namespace base
diff --git a/base/base_paths.h b/base/base_paths.h
new file mode 100644
index 0000000..3251a84
--- /dev/null
+++ b/base/base_paths.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_H_
+#define BASE_BASE_PATHS_H_
+
+// This file declares path keys for the base module.  These can be used with
+// the PathService to access various special directories and files.
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/base_paths_win.h"
+#elif defined(OS_MACOSX)
+#include "base/base_paths_mac.h"
+#elif defined(OS_ANDROID)
+#include "base/base_paths_android.h"
+#endif
+
+#if defined(OS_POSIX)
+#include "base/base_paths_posix.h"
+#endif
+
+namespace base {
+
+enum BasePathKey {
+  PATH_START = 0,
+
+  DIR_CURRENT,  // current directory
+  DIR_EXE,      // directory containing FILE_EXE
+  DIR_MODULE,   // directory containing FILE_MODULE
+  DIR_TEMP,     // temporary directory
+  FILE_EXE,     // Path and filename of the current executable.
+  FILE_MODULE,  // Path and filename of the module containing the code for the
+                // PathService (which could differ from FILE_EXE if the
+                // PathService were compiled into a shared object, for example).
+  DIR_SOURCE_ROOT,  // Returns the root of the source tree.  This key is useful
+                    // for tests that need to locate various resources.  It
+                    // should not be used outside of test code.
+  DIR_USER_DESKTOP,  // The current user's Desktop.
+
+  PATH_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_H_
diff --git a/base/base_paths_android.cc b/base/base_paths_android.cc
new file mode 100644
index 0000000..9905200
--- /dev/null
+++ b/base/base_paths_android.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines base::PathProviderAndroid which replaces base::PathProviderPosix for
+// Android in base/path_service.cc.
+
+#include <unistd.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/path_utils.h"
+#include "base/base_paths.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/process_util.h"
+
+namespace base {
+
+bool PathProviderAndroid(int key, FilePath* result) {
+  switch (key) {
+    case base::FILE_EXE: {
+      char bin_dir[PATH_MAX + 1];
+      int bin_dir_size = readlink(kProcSelfExe, bin_dir, PATH_MAX);
+      if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) {
+        NOTREACHED() << "Unable to resolve " << kProcSelfExe << ".";
+        return false;
+      }
+      bin_dir[bin_dir_size] = 0;
+      *result = FilePath(bin_dir);
+      return true;
+    }
+    case base::FILE_MODULE:
+      // dladdr didn't work in Android as only the file name was returned.
+      NOTIMPLEMENTED();
+      return false;
+    case base::DIR_MODULE:
+      return base::android::GetNativeLibraryDirectory(result);
+    case base::DIR_SOURCE_ROOT:
+      // This const is only used for tests.
+      return base::android::GetExternalStorageDirectory(result);
+    case base::DIR_USER_DESKTOP:
+      // Android doesn't support GetUserDesktop.
+      NOTIMPLEMENTED();
+      return false;
+    case base::DIR_CACHE:
+      return base::android::GetCacheDirectory(result);
+    case base::DIR_ANDROID_APP_DATA:
+      return base::android::GetDataDirectory(result);
+    case base::DIR_HOME:
+      *result = file_util::GetHomeDir();
+      return true;
+    case base::DIR_ANDROID_EXTERNAL_STORAGE:
+      return base::android::GetExternalStorageDirectory(result);
+    default:
+      // Note: the path system expects this function to override the default
+      // behavior. So no need to log an error if we don't support a given
+      // path. The system will just use the default.
+      return false;
+  }
+}
+
+}  // namespace base
diff --git a/base/base_paths_android.h b/base/base_paths_android.h
new file mode 100644
index 0000000..7a9ac4a
--- /dev/null
+++ b/base/base_paths_android.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_ANDROID_H_
+#define BASE_BASE_PATHS_ANDROID_H_
+
+// This file declares Android-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_ANDROID_START = 300,
+
+  DIR_ANDROID_APP_DATA,  // Directory where to put Android app's data.
+  DIR_ANDROID_EXTERNAL_STORAGE,  // Android external storage directory.
+
+  PATH_ANDROID_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_ANDROID_H_
diff --git a/base/base_paths_mac.h b/base/base_paths_mac.h
new file mode 100644
index 0000000..ac75402
--- /dev/null
+++ b/base/base_paths_mac.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_MAC_H_
+#define BASE_BASE_PATHS_MAC_H_
+
+// This file declares Mac-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_MAC_START = 200,
+
+  DIR_APP_DATA,  // ~/Library/Application Support
+
+  PATH_MAC_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_MAC_H_
diff --git a/base/base_paths_mac.mm b/base/base_paths_mac.mm
new file mode 100644
index 0000000..630f742
--- /dev/null
+++ b/base/base_paths_mac.mm
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines base::PathProviderMac which replaces base::PathProviderPosix for Mac
+// in base/path_service.cc.
+
+#include <dlfcn.h>
+#import <Foundation/Foundation.h>
+#include <mach-o/dyld.h>
+
+#include "base/base_paths.h"
+#include "base/compiler_specific.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "build/build_config.h"
+
+namespace {
+
+void GetNSExecutablePath(FilePath* path) {
+  DCHECK(path);
+  // Executable path can have relative references ("..") depending on
+  // how the app was launched.
+  uint32_t executable_length = 0;
+  _NSGetExecutablePath(NULL, &executable_length);
+  DCHECK_GT(executable_length, 1u);
+  std::string executable_path;
+  int rv = _NSGetExecutablePath(WriteInto(&executable_path, executable_length),
+                                &executable_length);
+  DCHECK_EQ(rv, 0);
+  *path = FilePath(executable_path);
+}
+
+// Returns true if the module for |address| is found. |path| will contain
+// the path to the module. Note that |path| may not be absolute.
+bool GetModulePathForAddress(FilePath* path,
+                             const void* address) WARN_UNUSED_RESULT;
+
+bool GetModulePathForAddress(FilePath* path, const void* address) {
+  Dl_info info;
+  if (dladdr(address, &info) == 0)
+    return false;
+  *path = FilePath(info.dli_fname);
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+
+bool PathProviderMac(int key, FilePath* result) {
+  switch (key) {
+    case base::FILE_EXE:
+      GetNSExecutablePath(result);
+      return true;
+    case base::FILE_MODULE:
+      return GetModulePathForAddress(result,
+          reinterpret_cast<const void*>(&base::PathProviderMac));
+    case base::DIR_APP_DATA: {
+      bool success = base::mac::GetUserDirectory(NSApplicationSupportDirectory,
+                                                 result);
+#if defined(OS_IOS)
+      // On IOS, this directory does not exist unless it is created explicitly.
+      if (success && !file_util::PathExists(*result))
+        success = file_util::CreateDirectory(*result);
+#endif  // defined(OS_IOS)
+      return success;
+    }
+    case base::DIR_SOURCE_ROOT:
+      // Go through PathService to catch overrides.
+      if (!PathService::Get(base::FILE_EXE, result))
+        return false;
+
+      // Start with the executable's directory.
+      *result = result->DirName();
+
+#if !defined(OS_IOS)
+      if (base::mac::AmIBundled()) {
+        // The bundled app executables (Chromium, TestShell, etc) live five
+        // levels down, eg:
+        // src/xcodebuild/{Debug|Release}/Chromium.app/Contents/MacOS/Chromium
+        *result = result->DirName().DirName().DirName().DirName().DirName();
+      } else {
+        // Unit tests execute two levels deep from the source root, eg:
+        // src/xcodebuild/{Debug|Release}/base_unittests
+        *result = result->DirName().DirName();
+      }
+#endif
+      return true;
+    case base::DIR_USER_DESKTOP:
+#if defined(OS_IOS)
+      // iOS does not have desktop directories.
+      NOTIMPLEMENTED();
+      return false;
+#else
+      return base::mac::GetUserDirectory(NSDesktopDirectory, result);
+#endif
+    case base::DIR_CACHE:
+      return base::mac::GetUserDirectory(NSCachesDirectory, result);
+    case base::DIR_HOME:
+      *result = base::mac::NSStringToFilePath(NSHomeDirectory());
+      return true;
+    default:
+      return false;
+  }
+}
+
+}  // namespace base
diff --git a/base/base_paths_posix.cc b/base/base_paths_posix.cc
new file mode 100644
index 0000000..834dee3
--- /dev/null
+++ b/base/base_paths_posix.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.
+
+// Defines base::PathProviderPosix, default path provider on POSIX OSes that
+// don't have their own base_paths_OS.cc implementation (i.e. all but Mac and
+// Android).
+
+#include <ostream>
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/environment.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/nix/xdg_util.h"
+#include "build/build_config.h"
+
+#if defined(OS_FREEBSD)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#elif defined(OS_SOLARIS)
+#include <stdlib.h>
+#endif
+
+namespace base {
+
+bool PathProviderPosix(int key, FilePath* result) {
+  FilePath path;
+  switch (key) {
+    case base::FILE_EXE:
+    case base::FILE_MODULE: {  // TODO(evanm): is this correct?
+#if defined(OS_LINUX)
+      FilePath bin_dir;
+      if (!file_util::ReadSymbolicLink(FilePath(kProcSelfExe), &bin_dir)) {
+        NOTREACHED() << "Unable to resolve " << kProcSelfExe << ".";
+        return false;
+      }
+      *result = bin_dir;
+      return true;
+#elif defined(OS_FREEBSD)
+      int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+      char bin_dir[PATH_MAX + 1];
+      size_t length = sizeof(bin_dir);
+      // Upon return, |length| is the number of bytes written to |bin_dir|
+      // including the string terminator.
+      int error = sysctl(name, 4, bin_dir, &length, NULL, 0);
+      if (error < 0 || length <= 1) {
+        NOTREACHED() << "Unable to resolve path.";
+        return false;
+      }
+      *result = FilePath(FilePath::StringType(bin_dir, length - 1));
+      return true;
+#elif defined(OS_SOLARIS)
+      char bin_dir[PATH_MAX + 1];
+      if (realpath(getexecname(), bin_dir) == NULL) {
+        NOTREACHED() << "Unable to resolve " << getexecname() << ".";
+        return false;
+      }
+      *result = FilePath(bin_dir);
+      return true;
+#elif defined(OS_OPENBSD)
+      // There is currently no way to get the executable path on OpenBSD
+      char* cpath;
+      if ((cpath = getenv("CHROME_EXE_PATH")) != NULL)
+        *result = FilePath(cpath);
+      else
+        *result = FilePath("/usr/local/chrome/chrome");
+      return true;
+#endif
+    }
+    case base::DIR_SOURCE_ROOT: {
+      // Allow passing this in the environment, for more flexibility in build
+      // tree configurations (sub-project builds, gyp --output_dir, etc.)
+      scoped_ptr<base::Environment> env(base::Environment::Create());
+      std::string cr_source_root;
+      if (env->GetVar("CR_SOURCE_ROOT", &cr_source_root)) {
+        path = FilePath(cr_source_root);
+        if (file_util::PathExists(path)) {
+          *result = path;
+          return true;
+        } else {
+          DLOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not "
+                        << "point to a directory.";
+        }
+      }
+      // On POSIX, unit tests execute two levels deep from the source root.
+      // For example:  out/{Debug|Release}/net_unittest
+      if (PathService::Get(base::DIR_EXE, &path)) {
+        *result = path.DirName().DirName();
+        return true;
+      }
+
+      DLOG(ERROR) << "Couldn't find your source root.  "
+                  << "Try running from your chromium/src directory.";
+      return false;
+    }
+    case base::DIR_USER_DESKTOP:
+      *result = base::nix::GetXDGUserDirectory("DESKTOP", "Desktop");
+      return true;
+    case base::DIR_CACHE: {
+      scoped_ptr<base::Environment> env(base::Environment::Create());
+      FilePath cache_dir(base::nix::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
+                                                    ".cache"));
+      *result = cache_dir;
+      return true;
+    }
+    case base::DIR_HOME:
+      *result = file_util::GetHomeDir();
+      return true;
+  }
+  return false;
+}
+
+}  // namespace base
diff --git a/base/base_paths_posix.h b/base/base_paths_posix.h
new file mode 100644
index 0000000..811c8cb
--- /dev/null
+++ b/base/base_paths_posix.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_PATHS_POSIX_H_
+#define BASE_BASE_PATHS_POSIX_H_
+
+// This file declares windows-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_POSIX_START = 400,
+
+  DIR_CACHE,    // Directory where to put cache data.  Note this is
+                // *not* where the browser cache lives, but the
+                // browser cache can be a subdirectory.
+                // This is $XDG_CACHE_HOME on Linux and
+                // ~/Library/Caches on Mac.
+  DIR_HOME,     // $HOME on POSIX-like systems.
+
+  PATH_POSIX_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_POSIX_H_
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc
new file mode 100644
index 0000000..a06d908
--- /dev/null
+++ b/base/base_paths_win.cc
@@ -0,0 +1,209 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#include <windows.h>
+#include <shlobj.h>
+
+#include "base/base_paths.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/windows_version.h"
+
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+namespace {
+
+bool GetQuickLaunchPath(bool default_user, FilePath* result) {
+  if (default_user) {
+    wchar_t system_buffer[MAX_PATH];
+    system_buffer[0] = 0;
+    // As per MSDN, passing -1 for |hToken| indicates the Default user:
+    // http://msdn.microsoft.com/library/windows/desktop/bb762181.aspx
+    if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA,
+                               reinterpret_cast<HANDLE>(-1), SHGFP_TYPE_CURRENT,
+                               system_buffer))) {
+      return false;
+    }
+    *result = FilePath(system_buffer);
+  } else if (!PathService::Get(base::DIR_APP_DATA, result)) {
+    // For the current user, grab the APPDATA directory directly from the
+    // PathService cache.
+    return false;
+  }
+  // According to various sources, appending
+  // "Microsoft\Internet Explorer\Quick Launch" to %appdata% is the only
+  // reliable way to get the quick launch folder across all versions of Windows.
+  // http://stackoverflow.com/questions/76080/how-do-you-reliably-get-the-quick-
+  // http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0901.mspx
+  *result = result->AppendASCII("Microsoft");
+  *result = result->AppendASCII("Internet Explorer");
+  *result = result->AppendASCII("Quick Launch");
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+
+bool PathProviderWin(int key, FilePath* result) {
+
+  // We need to go compute the value. It would be nice to support paths with
+  // names longer than MAX_PATH, but the system functions don't seem to be
+  // designed for it either, with the exception of GetTempPath (but other
+  // things will surely break if the temp path is too long, so we don't bother
+  // handling it.
+  wchar_t system_buffer[MAX_PATH];
+  system_buffer[0] = 0;
+
+  FilePath cur;
+  switch (key) {
+    case base::FILE_EXE:
+      GetModuleFileName(NULL, system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    case base::FILE_MODULE: {
+      // the resource containing module is assumed to be the one that
+      // this code lives in, whether that's a dll or exe
+      HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
+      GetModuleFileName(this_module, system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    }
+    case base::DIR_WINDOWS:
+      GetWindowsDirectory(system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_SYSTEM:
+      GetSystemDirectory(system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_PROGRAM_FILESX86:
+      if (base::win::OSInfo::GetInstance()->architecture() !=
+          base::win::OSInfo::X86_ARCHITECTURE) {
+        if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL,
+                                   SHGFP_TYPE_CURRENT, system_buffer)))
+          return false;
+        cur = FilePath(system_buffer);
+        break;
+      }
+      // Fall through to base::DIR_PROGRAM_FILES if we're on an X86 machine.
+    case base::DIR_PROGRAM_FILES:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_IE_INTERNET_CACHE:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_COMMON_START_MENU:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_START_MENU:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_APP_DATA:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
+                                 system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_COMMON_APP_DATA:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_PROFILE:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT,
+                                 system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_LOCAL_APP_DATA_LOW:
+      if (win::GetVersion() < win::VERSION_VISTA)
+        return false;
+
+      // TODO(nsylvain): We should use SHGetKnownFolderPath instead. Bug 1281128
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
+                                 system_buffer)))
+        return false;
+      cur = FilePath(system_buffer).DirName().AppendASCII("LocalLow");
+      break;
+    case base::DIR_LOCAL_APP_DATA:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_SOURCE_ROOT: {
+      FilePath executableDir;
+      // On Windows, unit tests execute two levels deep from the source root.
+      // For example:  chrome/{Debug|Release}/ui_tests.exe
+      PathService::Get(base::DIR_EXE, &executableDir);
+      cur = executableDir.DirName().DirName();
+      break;
+    }
+    case base::DIR_APP_SHORTCUTS: {
+      if (win::GetVersion() < win::VERSION_WIN8)
+        return false;
+
+      base::win::ScopedCoMem<wchar_t> path_buf;
+      if (FAILED(SHGetKnownFolderPath(FOLDERID_ApplicationShortcuts, 0, NULL,
+                                      &path_buf)))
+        return false;
+
+      cur = FilePath(string16(path_buf));
+      break;
+    }
+    case base::DIR_USER_DESKTOP:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer))) {
+        return false;
+      }
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_COMMON_DESKTOP:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer))) {
+        return false;
+      }
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_USER_QUICK_LAUNCH:
+      if (!GetQuickLaunchPath(false, &cur))
+        return false;
+      break;
+    case base::DIR_DEFAULT_USER_QUICK_LAUNCH:
+      if (!GetQuickLaunchPath(true, &cur))
+        return false;
+      break;
+    case base::DIR_TASKBAR_PINS:
+      if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur))
+        return false;
+      cur = cur.AppendASCII("User Pinned");
+      cur = cur.AppendASCII("TaskBar");
+      break;
+    default:
+      return false;
+  }
+
+  *result = cur;
+  return true;
+}
+
+}  // namespace base
diff --git a/base/base_paths_win.h b/base/base_paths_win.h
new file mode 100644
index 0000000..11bc111
--- /dev/null
+++ b/base/base_paths_win.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_BASE_PATHS_WIN_H__
+#define BASE_BASE_PATHS_WIN_H__
+
+// This file declares windows-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_WIN_START = 100,
+
+  DIR_WINDOWS,  // Windows directory, usually "c:\windows"
+  DIR_SYSTEM,   // Usually c:\windows\system32"
+  DIR_PROGRAM_FILES,      // Usually c:\program files
+  DIR_PROGRAM_FILESX86,   // Usually c:\program files or c:\program files (x86)
+
+  DIR_IE_INTERNET_CACHE,  // Temporary Internet Files directory.
+  DIR_COMMON_START_MENU,  // Usually "C:\Documents and Settings\All Users\
+                          // Start Menu\Programs"
+  DIR_START_MENU,         // Usually "C:\Documents and Settings\<user>\
+                          // Start Menu\Programs"
+  DIR_APP_DATA,           // Application Data directory under the user profile.
+  DIR_PROFILE,            // Usually "C:\Documents and settings\<user>.
+  DIR_LOCAL_APP_DATA_LOW, // Local AppData directory for low integrity level.
+  DIR_LOCAL_APP_DATA,     // "Local Settings\Application Data" directory under
+                          // the user profile.
+  DIR_COMMON_APP_DATA,    // W2K, XP, W2K3: "C:\Documents and Settings\
+                          // All Users\Application Data".
+                          // Vista, W2K8 and above: "C:\ProgramData".
+  DIR_APP_SHORTCUTS,      // Where tiles on the start screen are stored, only
+                          // for Windows 8. Maps to "Local\AppData\Microsoft\
+                          // Windows\Application Shortcuts\".
+  DIR_COMMON_DESKTOP,     // Directory for the common desktop (visible
+                          // on all user's Desktop).
+  DIR_USER_QUICK_LAUNCH,  // Directory for the quick launch shortcuts.
+  DIR_DEFAULT_USER_QUICK_LAUNCH,  // Directory for the quick launch shortcuts
+                                  // of the Default user.
+  DIR_TASKBAR_PINS,       // Directory for the shortcuts pinned to taskbar via
+                          // base::win::TaskbarPinShortcutLink().
+
+  PATH_WIN_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_WIN_H__
diff --git a/base/base_static.target.mk b/base/base_static.target.mk
new file mode 100644
index 0000000..431227a
--- /dev/null
+++ b/base/base_static.target.mk
@@ -0,0 +1,147 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := base_base_static_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	base/base_switches.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS := \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-mthumb \
+	-march=armv7-a \
+	-mtune=cortex-a8 \
+	-mfloat-abi=softfp \
+	-mfpu=vfpv3-d16 \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-mthumb-interwork \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-Wno-error=extra \
+	-Wno-error=ignored-qualifiers \
+	-Wno-error=type-limits \
+	-Wno-error=non-virtual-dtor \
+	-Wno-error=sign-promo \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_CFLAGS_C :=
+
+MY_DEFS := \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_PEPPER_THREADING' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DUSE_SKIA=1' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_SYMBOLS_ID=""' \
+	'-DANDROID_UPSTREAM_BRINGUP=1' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH) \
+	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
+	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat
+
+### Rules for final target.
+
+LOCAL_LDFLAGS := \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections
+
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: base_base_static_gyp
+
+# Alias gyp target name.
+.PHONY: base_static
+base_static: base_base_static_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/base/base_switches.cc b/base/base_switches.cc
new file mode 100644
index 0000000..7c7b061
--- /dev/null
+++ b/base/base_switches.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base_switches.h"
+
+namespace switches {
+
+// If the program includes base/debug/debug_on_start_win.h, the process will
+// (on Windows only) start the JIT system-registered debugger on itself and
+// will wait for 60 seconds for the debugger to attach to itself. Then a break
+// point will be hit.
+const char kDebugOnStart[]                  = "debug-on-start";
+
+// Disables the crash reporting.
+const char kDisableBreakpad[]               = "disable-breakpad";
+
+// Enable DCHECKs in release mode.
+const char kEnableDCHECK[]                  = "enable-dcheck";
+
+// Generates full memory crash dump.
+const char kFullMemoryCrashReport[]         = "full-memory-crash-report";
+
+// Suppresses all error dialogs when present.
+const char kNoErrorDialogs[]                = "noerrdialogs";
+
+// When running certain tests that spawn child processes, this switch indicates
+// to the test framework that the current process is a child process.
+const char kTestChildProcess[]              = "test-child-process";
+
+// Gives the default maximal active V-logging level; 0 is the default.
+// Normally positive values are used for V-logging levels.
+const char kV[]                             = "v";
+
+// Gives the per-module maximal V-logging levels to override the value
+// given by --v.  E.g. "my_module=2,foo*=3" would change the logging
+// level for all code in source files "my_module.*" and "foo*.*"
+// ("-inl" suffixes are also disregarded for this matching).
+//
+// Any pattern containing a forward or backward slash will be tested
+// against the whole pathname and not just the module.  E.g.,
+// "*/foo/bar/*=2" would change the logging level for all code in
+// source files under a "foo/bar" directory.
+const char kVModule[]                       = "vmodule";
+
+// Will wait for 60 seconds for a debugger to come to attach to the process.
+const char kWaitForDebugger[]               = "wait-for-debugger";
+
+}  // namespace switches
diff --git a/base/base_switches.h b/base/base_switches.h
new file mode 100644
index 0000000..558a5cf
--- /dev/null
+++ b/base/base_switches.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines all the "base" command-line switches.
+
+#ifndef BASE_BASE_SWITCHES_H_
+#define BASE_BASE_SWITCHES_H_
+
+namespace switches {
+
+extern const char kDebugOnStart[];
+extern const char kDisableBreakpad[];
+extern const char kEnableDCHECK[];
+extern const char kFullMemoryCrashReport[];
+extern const char kNoErrorDialogs[];
+extern const char kTestChildProcess[];
+extern const char kV[];
+extern const char kVModule[];
+extern const char kWaitForDebugger[];
+
+}  // namespace switches
+
+#endif  // BASE_BASE_SWITCHES_H_
diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate
new file mode 100644
index 0000000..f13e66b
--- /dev/null
+++ b/base/base_unittests.isolate
@@ -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.
+{
+  'variables': {
+    'isolate_dependency_tracked': [
+      '../testing/test_env.py',
+      '../tools/swarm_client/run_isolated.py',
+      '../tools/swarm_client/run_test_cases.py',
+      '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+      'data/json/bom_feff.json',
+    ],
+    'isolate_dependency_untracked': [
+      'data/file_util_unittest/',
+    ],
+  },
+  'conditions': [
+    ['OS=="linux"', {
+      'variables': {
+        'command': [
+          '../testing/xvfb.py',
+          '<(PRODUCT_DIR)',
+          '../tools/swarm_client/run_test_cases.py',
+          '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+        ],
+        'isolate_dependency_tracked': [
+          '../testing/xvfb.py',
+          '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
+        ],
+      },
+    }, {
+      'variables': {
+        'command': [
+          '../testing/test_env.py',
+          '../tools/swarm_client/run_test_cases.py',
+          '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+        ],
+      },
+    }],
+    ['OS=="win"', {
+      'variables': {
+        'isolate_dependency_tracked': [
+          '<(PRODUCT_DIR)/icudt.dll',
+          'data/file_version_info_unittest/FileVersionInfoTest1.dll',
+          'data/file_version_info_unittest/FileVersionInfoTest2.dll',
+        ],
+      },
+    }],
+  ],
+}
diff --git a/base/base_untrusted.gyp b/base/base_untrusted.gyp
new file mode 100644
index 0000000..8b64c7d
--- /dev/null
+++ b/base/base_untrusted.gyp
@@ -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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    '../build/common_untrusted.gypi',
+    'base.gypi',
+  ],
+  'conditions': [
+    ['disable_nacl==0 and disable_nacl_untrusted==0', {
+      'targets': [
+        {
+          'target_name': 'base_untrusted',
+          'type': 'none',
+          'variables': {
+            'base_target': 1,
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libbase_untrusted.a',
+            'build_glibc': 1,
+            'build_newlib': 1,
+            'sources': [
+              'string16.cc',
+              'sync_socket_nacl.cc',
+              'third_party/nspr/prtime.cc',
+              'time_posix.cc',
+            ],
+          },
+          'dependencies': [
+            '<(DEPTH)/native_client/tools.gyp:prep_toolchain',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/basictypes.h b/base/basictypes.h
new file mode 100644
index 0000000..9681756
--- /dev/null
+++ b/base/basictypes.h
@@ -0,0 +1,361 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASICTYPES_H_
+#define BASE_BASICTYPES_H_
+
+#include <limits.h>         // So we can set the bounds of our types
+#include <stddef.h>         // For size_t
+#include <string.h>         // for memcpy
+
+#include "base/port.h"    // Types that only need exist on certain systems
+
+#ifndef COMPILER_MSVC
+// stdint.h is part of C99 but MSVC doesn't have it.
+#include <stdint.h>         // For intptr_t.
+#endif
+
+typedef signed char         schar;
+typedef signed char         int8;
+typedef short               int16;
+// TODO: Remove these type guards.  These are to avoid conflicts with
+// obsolete/protypes.h in the Gecko SDK.
+#ifndef _INT32
+#define _INT32
+typedef int                 int32;
+#endif
+
+// The NSPR system headers define 64-bit as |long| when possible, except on
+// Mac OS X.  In order to not have typedef mismatches, we do the same on LP64.
+//
+// On Mac OS X, |long long| is used for 64-bit types for compatibility with
+// <inttypes.h> format macros even in the LP64 model.
+#if defined(__LP64__) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
+typedef long                int64;
+#else
+typedef long long           int64;
+#endif
+
+// NOTE: unsigned types are DANGEROUS in loops and other arithmetical
+// places.  Use the signed types unless your variable represents a bit
+// pattern (eg a hash value) or you really need the extra bit.  Do NOT
+// use 'unsigned' to express "this value should always be positive";
+// use assertions for this.
+
+typedef unsigned char      uint8;
+typedef unsigned short     uint16;
+// TODO: Remove these type guards.  These are to avoid conflicts with
+// obsolete/protypes.h in the Gecko SDK.
+#ifndef _UINT32
+#define _UINT32
+typedef unsigned int       uint32;
+#endif
+
+// See the comment above about NSPR and 64-bit.
+#if defined(__LP64__) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
+typedef unsigned long uint64;
+#else
+typedef unsigned long long uint64;
+#endif
+
+// A type to represent a Unicode code-point value. As of Unicode 4.0,
+// such values require up to 21 bits.
+// (For type-checking on pointers, make this explicitly signed,
+// and it should always be the signed version of whatever int32 is.)
+typedef signed int         char32;
+
+const uint8  kuint8max  = (( uint8) 0xFF);
+const uint16 kuint16max = ((uint16) 0xFFFF);
+const uint32 kuint32max = ((uint32) 0xFFFFFFFF);
+const uint64 kuint64max = ((uint64) GG_LONGLONG(0xFFFFFFFFFFFFFFFF));
+const  int8  kint8min   = ((  int8) 0x80);
+const  int8  kint8max   = ((  int8) 0x7F);
+const  int16 kint16min  = (( int16) 0x8000);
+const  int16 kint16max  = (( int16) 0x7FFF);
+const  int32 kint32min  = (( int32) 0x80000000);
+const  int32 kint32max  = (( int32) 0x7FFFFFFF);
+const  int64 kint64min  = (( int64) GG_LONGLONG(0x8000000000000000));
+const  int64 kint64max  = (( int64) GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);               \
+  void operator=(const TypeName&)
+
+// An older, deprecated, politically incorrect name for the above.
+// NOTE: The usage of this macro was baned from our code base, but some
+// third_party libraries are yet using it.
+// TODO(tfarina): Figure out how to fix the usage of this macro in the
+// third_party libraries and get rid of it.
+#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                    \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// The arraysize(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example.  If you use arraysize on
+// a pointer by mistake, you will get a compile-time error.
+//
+// One caveat is that arraysize() doesn't accept any array of an
+// anonymous type or a type defined inside a function.  In these rare
+// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below.  This is
+// due to a limitation in C++'s template system.  The limitation might
+// eventually be removed, but it hasn't happened yet.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
+
+// That gcc wants both of these prototypes seems mysterious. VC, for
+// its part, can't decide which to use (another mystery). Matching of
+// template overloads: the final frontier.
+#ifndef _MSC_VER
+template <typename T, size_t N>
+char (&ArraySizeHelper(const T (&array)[N]))[N];
+#endif
+
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
+// but can be used on anonymous types or types defined inside
+// functions.  It's less safe than arraysize as it accepts some
+// (although not all) pointers.  Therefore, you should use arraysize
+// whenever possible.
+//
+// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type
+// size_t.
+//
+// ARRAYSIZE_UNSAFE catches a few type errors.  If you see a compiler error
+//
+//   "warning: division by zero in ..."
+//
+// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.
+// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.
+//
+// The following comments are on the implementation details, and can
+// be ignored by the users.
+//
+// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in
+// the array) and sizeof(*(arr)) (the # of bytes in one array
+// element).  If the former is divisible by the latter, perhaps arr is
+// indeed an array, in which case the division result is the # of
+// elements in the array.  Otherwise, arr cannot possibly be an array,
+// and we generate a compiler error to prevent the code from
+// compiling.
+//
+// Since the size of bool is implementation-defined, we need to cast
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
+// result has type size_t.
+//
+// This macro is not perfect as it wrongfully accepts certain
+// pointers, namely where the pointer size is divisible by the pointee
+// size.  Since all our code has to go through a 32-bit compiler,
+// where a pointer is 4 bytes, this means all pointers to a type whose
+// size is 3 or greater than 4 will be (righteously) rejected.
+
+#define ARRAYSIZE_UNSAFE(a) \
+  ((sizeof(a) / sizeof(*(a))) / \
+   static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+
+// Use implicit_cast as a safe version of static_cast or const_cast
+// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
+// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
+// a const pointer to Foo).
+// When you use implicit_cast, the compiler checks that the cast is safe.
+// Such explicit implicit_casts are necessary in surprisingly many
+// situations where C++ demands an exact type match instead of an
+// argument type convertable to a target type.
+//
+// The From type can be inferred, so the preferred syntax for using
+// implicit_cast is the same as for static_cast etc.:
+//
+//   implicit_cast<ToType>(expr)
+//
+// implicit_cast would have been part of the C++ standard library,
+// but the proposal was submitted too late.  It will probably make
+// its way into the language in the future.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+  return f;
+}
+
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+//   COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES,
+//                  content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+//   COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+template <bool>
+struct CompileAssert {
+};
+
+#undef COMPILE_ASSERT
+#define COMPILE_ASSERT(expr, msg) \
+  typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+// Implementation details of COMPILE_ASSERT:
+//
+// - COMPILE_ASSERT works by defining an array type that has -1
+//   elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+//     #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+//   does not work, as gcc supports variable-length arrays whose sizes
+//   are determined at run-time (this is gcc's extension and not part
+//   of the C++ standard).  As a result, gcc fails to reject the
+//   following code with the simple definition:
+//
+//     int foo;
+//     COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
+//                               // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+//   expr is a compile-time constant.  (Template arguments must be
+//   determined at compile-time.)
+//
+// - The outer parentheses in CompileAssert<(bool(expr))> are necessary
+//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written
+//
+//     CompileAssert<bool(expr)>
+//
+//   instead, these compilers will refuse to compile
+//
+//     COMPILE_ASSERT(5 > 0, some_message);
+//
+//   (They seem to think the ">" in "5 > 0" marks the end of the
+//   template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+//     ((expr) ? 1 : -1).
+//
+//   This is to avoid running into a bug in MS VC 7.1, which
+//   causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+
+// bit_cast<Dest,Source> is a template function that implements the
+// equivalent of "*reinterpret_cast<Dest*>(&source)".  We need this in
+// very low-level functions like the protobuf library and fast math
+// support.
+//
+//   float f = 3.14159265358979;
+//   int i = bit_cast<int32>(f);
+//   // i = 0x40490fdb
+//
+// The classical address-casting method is:
+//
+//   // WRONG
+//   float f = 3.14159265358979;            // WRONG
+//   int i = * reinterpret_cast<int*>(&f);  // WRONG
+//
+// The address-casting method actually produces undefined behavior
+// according to ISO C++ specification section 3.10 -15 -.  Roughly, this
+// section says: if an object in memory has one type, and a program
+// accesses it with a different type, then the result is undefined
+// behavior for most values of "different type".
+//
+// This is true for any cast syntax, either *(int*)&f or
+// *reinterpret_cast<int*>(&f).  And it is particularly true for
+// conversions betweeen integral lvalues and floating-point lvalues.
+//
+// The purpose of 3.10 -15- is to allow optimizing compilers to assume
+// that expressions with different types refer to different memory.  gcc
+// 4.0.1 has an optimizer that takes advantage of this.  So a
+// non-conforming program quietly produces wildly incorrect output.
+//
+// The problem is not the use of reinterpret_cast.  The problem is type
+// punning: holding an object in memory of one type and reading its bits
+// back using a different type.
+//
+// The C++ standard is more subtle and complex than this, but that
+// is the basic idea.
+//
+// Anyways ...
+//
+// bit_cast<> calls memcpy() which is blessed by the standard,
+// especially by the example in section 3.9 .  Also, of course,
+// bit_cast<> wraps up the nasty logic in one place.
+//
+// Fortunately memcpy() is very fast.  In optimized mode, with a
+// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
+// code with the minimal amount of data movement.  On a 32-bit system,
+// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
+// compiles to two loads and two stores.
+//
+// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.
+//
+// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
+// is likely to surprise you.
+
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+  // Compile time assertion: sizeof(Dest) == sizeof(Source)
+  // A compile error here means your Dest and Source have different sizes.
+  typedef char VerifySizesAreEqual [sizeof(Dest) == sizeof(Source) ? 1 : -1];
+
+  Dest dest;
+  memcpy(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+// Used to explicitly mark the return value of a function as unused. If you are
+// really sure you don't want to do anything with the return value of a function
+// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
+//
+//   scoped_ptr<MyType> my_var = ...;
+//   if (TakeOwnership(my_var.get()) == SUCCESS)
+//     ignore_result(my_var.release());
+//
+template<typename T>
+inline void ignore_result(const T&) {
+}
+
+// The following enum should be used only as a constructor argument to indicate
+// that the variable has static storage class, and that the constructor should
+// do nothing to its state.  It indicates to the reader that it is legal to
+// declare a static instance of the class, provided the constructor is given
+// the base::LINKER_INITIALIZED argument.  Normally, it is unsafe to declare a
+// static variable that has a constructor or a destructor because invocation
+// order is undefined.  However, IF the type can be initialized by filling with
+// zeroes (which the loader does for static variables), AND the destructor also
+// does nothing to the storage, AND there are no virtual methods, then a
+// constructor declared as
+//       explicit MyClass(base::LinkerInitialized x) {}
+// and invoked as
+//       static MyClass my_variable_name(base::LINKER_INITIALIZED);
+namespace base {
+enum LinkerInitialized { LINKER_INITIALIZED };
+
+// Use these to declare and define a static local variable (static T;) so that
+// it is leaked so that its destructors are not called at exit. If you need
+// thread-safe initialization, use base/lazy_instance.h instead.
+#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \
+  static type& name = *new type arguments
+
+}  // base
+
+#endif  // BASE_BASICTYPES_H_
diff --git a/base/bind.h b/base/bind.h
new file mode 100644
index 0000000..5cf124d
--- /dev/null
+++ b/base/bind.h
@@ -0,0 +1,517 @@
+// This file was GENERATED by command:
+//     pump.py bind.h.pump
+// DO NOT EDIT BY HAND!!!
+
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIND_H_
+#define BASE_BIND_H_
+
+#include "base/bind_internal.h"
+#include "base/callback_internal.h"
+
+// -----------------------------------------------------------------------------
+// Usage documentation
+// -----------------------------------------------------------------------------
+//
+// See base/callback.h for documentation.
+//
+//
+// -----------------------------------------------------------------------------
+// Implementation notes
+// -----------------------------------------------------------------------------
+//
+// If you're reading the implementation, before proceeding further, you should
+// read the top comment of base/bind_internal.h for a definition of common
+// terms and concepts.
+//
+// RETURN TYPES
+//
+// Though Bind()'s result is meant to be stored in a Callback<> type, it
+// cannot actually return the exact type without requiring a large amount
+// of extra template specializations. The problem is that in order to
+// discern the correct specialization of Callback<>, Bind would need to
+// unwrap the function signature to determine the signature's arity, and
+// whether or not it is a method.
+//
+// Each unique combination of (arity, function_type, num_prebound) where
+// function_type is one of {function, method, const_method} would require
+// one specialization.  We eventually have to do a similar number of
+// specializations anyways in the implementation (see the Invoker<>,
+// classes).  However, it is avoidable in Bind if we return the result
+// via an indirection like we do below.
+//
+// TODO(ajwong): We might be able to avoid this now, but need to test.
+//
+// It is possible to move most of the COMPILE_ASSERT asserts into BindState<>,
+// but it feels a little nicer to have the asserts here so people do not
+// need to crack open bind_internal.h.  On the other hand, it makes Bind()
+// harder to read.
+
+namespace base {
+
+template <typename Functor>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        void()>
+            ::UnboundRunType>
+Bind(Functor functor) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef internal::FunctionTraits<typename RunnableType::RunType>
+      BoundFunctorTraits;
+
+  typedef internal::BindState<RunnableType, RunType, void()> BindState;
+
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor)));
+}
+
+template <typename Functor, typename P1>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        void(typename internal::CallbackParamTraits<P1>::StorageType)>
+            ::UnboundRunType>
+Bind(Functor functor, const P1& p1) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef internal::FunctionTraits<typename RunnableType::RunType>
+      BoundFunctorTraits;
+
+  // Do not allow binding a non-const reference parameter. Non-const reference
+  // parameters are disallowed by the Google style guide.  Also, binding a
+  // non-const reference parameter can make for subtle bugs because the
+  // invoked function will receive a reference to the stored copy of the
+  // argument and not the original.
+  COMPILE_ASSERT(
+      !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ),
+      do_not_bind_functions_with_nonconst_ref);
+
+  // For methods, we need to be careful for parameter 1.  We do not require
+  // a scoped_refptr because BindState<> itself takes care of AddRef() for
+  // methods. We also disallow binding of an array as the method's target
+  // object.
+  COMPILE_ASSERT(
+      internal::HasIsMethodTag<RunnableType>::value ||
+          !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
+      p1_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
+                     !is_array<P1>::value,
+                 first_bound_argument_to_method_cannot_be_array);
+  typedef internal::BindState<RunnableType, RunType,
+      void(typename internal::CallbackParamTraits<P1>::StorageType)> BindState;
+
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor), p1));
+}
+
+template <typename Functor, typename P1, typename P2>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        void(typename internal::CallbackParamTraits<P1>::StorageType,
+            typename internal::CallbackParamTraits<P2>::StorageType)>
+            ::UnboundRunType>
+Bind(Functor functor, const P1& p1, const P2& p2) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef internal::FunctionTraits<typename RunnableType::RunType>
+      BoundFunctorTraits;
+
+  // Do not allow binding a non-const reference parameter. Non-const reference
+  // parameters are disallowed by the Google style guide.  Also, binding a
+  // non-const reference parameter can make for subtle bugs because the
+  // invoked function will receive a reference to the stored copy of the
+  // argument and not the original.
+  COMPILE_ASSERT(
+      !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ),
+      do_not_bind_functions_with_nonconst_ref);
+
+  // For methods, we need to be careful for parameter 1.  We do not require
+  // a scoped_refptr because BindState<> itself takes care of AddRef() for
+  // methods. We also disallow binding of an array as the method's target
+  // object.
+  COMPILE_ASSERT(
+      internal::HasIsMethodTag<RunnableType>::value ||
+          !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
+      p1_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
+                     !is_array<P1>::value,
+                 first_bound_argument_to_method_cannot_be_array);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
+                 p2_is_refcounted_type_and_needs_scoped_refptr);
+  typedef internal::BindState<RunnableType, RunType,
+      void(typename internal::CallbackParamTraits<P1>::StorageType,
+      typename internal::CallbackParamTraits<P2>::StorageType)> BindState;
+
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor), p1, p2));
+}
+
+template <typename Functor, typename P1, typename P2, typename P3>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        void(typename internal::CallbackParamTraits<P1>::StorageType,
+            typename internal::CallbackParamTraits<P2>::StorageType,
+            typename internal::CallbackParamTraits<P3>::StorageType)>
+            ::UnboundRunType>
+Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef internal::FunctionTraits<typename RunnableType::RunType>
+      BoundFunctorTraits;
+
+  // Do not allow binding a non-const reference parameter. Non-const reference
+  // parameters are disallowed by the Google style guide.  Also, binding a
+  // non-const reference parameter can make for subtle bugs because the
+  // invoked function will receive a reference to the stored copy of the
+  // argument and not the original.
+  COMPILE_ASSERT(
+      !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ),
+      do_not_bind_functions_with_nonconst_ref);
+
+  // For methods, we need to be careful for parameter 1.  We do not require
+  // a scoped_refptr because BindState<> itself takes care of AddRef() for
+  // methods. We also disallow binding of an array as the method's target
+  // object.
+  COMPILE_ASSERT(
+      internal::HasIsMethodTag<RunnableType>::value ||
+          !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
+      p1_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
+                     !is_array<P1>::value,
+                 first_bound_argument_to_method_cannot_be_array);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
+                 p2_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
+                 p3_is_refcounted_type_and_needs_scoped_refptr);
+  typedef internal::BindState<RunnableType, RunType,
+      void(typename internal::CallbackParamTraits<P1>::StorageType,
+      typename internal::CallbackParamTraits<P2>::StorageType,
+      typename internal::CallbackParamTraits<P3>::StorageType)> BindState;
+
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor), p1, p2, p3));
+}
+
+template <typename Functor, typename P1, typename P2, typename P3, typename P4>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        void(typename internal::CallbackParamTraits<P1>::StorageType,
+            typename internal::CallbackParamTraits<P2>::StorageType,
+            typename internal::CallbackParamTraits<P3>::StorageType,
+            typename internal::CallbackParamTraits<P4>::StorageType)>
+            ::UnboundRunType>
+Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef internal::FunctionTraits<typename RunnableType::RunType>
+      BoundFunctorTraits;
+
+  // Do not allow binding a non-const reference parameter. Non-const reference
+  // parameters are disallowed by the Google style guide.  Also, binding a
+  // non-const reference parameter can make for subtle bugs because the
+  // invoked function will receive a reference to the stored copy of the
+  // argument and not the original.
+  COMPILE_ASSERT(
+      !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ),
+      do_not_bind_functions_with_nonconst_ref);
+
+  // For methods, we need to be careful for parameter 1.  We do not require
+  // a scoped_refptr because BindState<> itself takes care of AddRef() for
+  // methods. We also disallow binding of an array as the method's target
+  // object.
+  COMPILE_ASSERT(
+      internal::HasIsMethodTag<RunnableType>::value ||
+          !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
+      p1_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
+                     !is_array<P1>::value,
+                 first_bound_argument_to_method_cannot_be_array);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
+                 p2_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
+                 p3_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
+                 p4_is_refcounted_type_and_needs_scoped_refptr);
+  typedef internal::BindState<RunnableType, RunType,
+      void(typename internal::CallbackParamTraits<P1>::StorageType,
+      typename internal::CallbackParamTraits<P2>::StorageType,
+      typename internal::CallbackParamTraits<P3>::StorageType,
+      typename internal::CallbackParamTraits<P4>::StorageType)> BindState;
+
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4));
+}
+
+template <typename Functor, typename P1, typename P2, typename P3, typename P4,
+    typename P5>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        void(typename internal::CallbackParamTraits<P1>::StorageType,
+            typename internal::CallbackParamTraits<P2>::StorageType,
+            typename internal::CallbackParamTraits<P3>::StorageType,
+            typename internal::CallbackParamTraits<P4>::StorageType,
+            typename internal::CallbackParamTraits<P5>::StorageType)>
+            ::UnboundRunType>
+Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
+    const P5& p5) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef internal::FunctionTraits<typename RunnableType::RunType>
+      BoundFunctorTraits;
+
+  // Do not allow binding a non-const reference parameter. Non-const reference
+  // parameters are disallowed by the Google style guide.  Also, binding a
+  // non-const reference parameter can make for subtle bugs because the
+  // invoked function will receive a reference to the stored copy of the
+  // argument and not the original.
+  COMPILE_ASSERT(
+      !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ),
+      do_not_bind_functions_with_nonconst_ref);
+
+  // For methods, we need to be careful for parameter 1.  We do not require
+  // a scoped_refptr because BindState<> itself takes care of AddRef() for
+  // methods. We also disallow binding of an array as the method's target
+  // object.
+  COMPILE_ASSERT(
+      internal::HasIsMethodTag<RunnableType>::value ||
+          !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
+      p1_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
+                     !is_array<P1>::value,
+                 first_bound_argument_to_method_cannot_be_array);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
+                 p2_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
+                 p3_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
+                 p4_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
+                 p5_is_refcounted_type_and_needs_scoped_refptr);
+  typedef internal::BindState<RunnableType, RunType,
+      void(typename internal::CallbackParamTraits<P1>::StorageType,
+      typename internal::CallbackParamTraits<P2>::StorageType,
+      typename internal::CallbackParamTraits<P3>::StorageType,
+      typename internal::CallbackParamTraits<P4>::StorageType,
+      typename internal::CallbackParamTraits<P5>::StorageType)> BindState;
+
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5));
+}
+
+template <typename Functor, typename P1, typename P2, typename P3, typename P4,
+    typename P5, typename P6>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        void(typename internal::CallbackParamTraits<P1>::StorageType,
+            typename internal::CallbackParamTraits<P2>::StorageType,
+            typename internal::CallbackParamTraits<P3>::StorageType,
+            typename internal::CallbackParamTraits<P4>::StorageType,
+            typename internal::CallbackParamTraits<P5>::StorageType,
+            typename internal::CallbackParamTraits<P6>::StorageType)>
+            ::UnboundRunType>
+Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
+    const P5& p5, const P6& p6) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef internal::FunctionTraits<typename RunnableType::RunType>
+      BoundFunctorTraits;
+
+  // Do not allow binding a non-const reference parameter. Non-const reference
+  // parameters are disallowed by the Google style guide.  Also, binding a
+  // non-const reference parameter can make for subtle bugs because the
+  // invoked function will receive a reference to the stored copy of the
+  // argument and not the original.
+  COMPILE_ASSERT(
+      !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ),
+      do_not_bind_functions_with_nonconst_ref);
+
+  // For methods, we need to be careful for parameter 1.  We do not require
+  // a scoped_refptr because BindState<> itself takes care of AddRef() for
+  // methods. We also disallow binding of an array as the method's target
+  // object.
+  COMPILE_ASSERT(
+      internal::HasIsMethodTag<RunnableType>::value ||
+          !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
+      p1_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
+                     !is_array<P1>::value,
+                 first_bound_argument_to_method_cannot_be_array);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
+                 p2_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
+                 p3_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
+                 p4_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
+                 p5_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
+                 p6_is_refcounted_type_and_needs_scoped_refptr);
+  typedef internal::BindState<RunnableType, RunType,
+      void(typename internal::CallbackParamTraits<P1>::StorageType,
+      typename internal::CallbackParamTraits<P2>::StorageType,
+      typename internal::CallbackParamTraits<P3>::StorageType,
+      typename internal::CallbackParamTraits<P4>::StorageType,
+      typename internal::CallbackParamTraits<P5>::StorageType,
+      typename internal::CallbackParamTraits<P6>::StorageType)> BindState;
+
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6));
+}
+
+template <typename Functor, typename P1, typename P2, typename P3, typename P4,
+    typename P5, typename P6, typename P7>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        void(typename internal::CallbackParamTraits<P1>::StorageType,
+            typename internal::CallbackParamTraits<P2>::StorageType,
+            typename internal::CallbackParamTraits<P3>::StorageType,
+            typename internal::CallbackParamTraits<P4>::StorageType,
+            typename internal::CallbackParamTraits<P5>::StorageType,
+            typename internal::CallbackParamTraits<P6>::StorageType,
+            typename internal::CallbackParamTraits<P7>::StorageType)>
+            ::UnboundRunType>
+Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
+    const P5& p5, const P6& p6, const P7& p7) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef internal::FunctionTraits<typename RunnableType::RunType>
+      BoundFunctorTraits;
+
+  // Do not allow binding a non-const reference parameter. Non-const reference
+  // parameters are disallowed by the Google style guide.  Also, binding a
+  // non-const reference parameter can make for subtle bugs because the
+  // invoked function will receive a reference to the stored copy of the
+  // argument and not the original.
+  COMPILE_ASSERT(
+      !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ||
+          is_non_const_reference<typename BoundFunctorTraits::A7Type>::value ),
+      do_not_bind_functions_with_nonconst_ref);
+
+  // For methods, we need to be careful for parameter 1.  We do not require
+  // a scoped_refptr because BindState<> itself takes care of AddRef() for
+  // methods. We also disallow binding of an array as the method's target
+  // object.
+  COMPILE_ASSERT(
+      internal::HasIsMethodTag<RunnableType>::value ||
+          !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
+      p1_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
+                     !is_array<P1>::value,
+                 first_bound_argument_to_method_cannot_be_array);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
+                 p2_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
+                 p3_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
+                 p4_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
+                 p5_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
+                 p6_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P7>::value,
+                 p7_is_refcounted_type_and_needs_scoped_refptr);
+  typedef internal::BindState<RunnableType, RunType,
+      void(typename internal::CallbackParamTraits<P1>::StorageType,
+      typename internal::CallbackParamTraits<P2>::StorageType,
+      typename internal::CallbackParamTraits<P3>::StorageType,
+      typename internal::CallbackParamTraits<P4>::StorageType,
+      typename internal::CallbackParamTraits<P5>::StorageType,
+      typename internal::CallbackParamTraits<P6>::StorageType,
+      typename internal::CallbackParamTraits<P7>::StorageType)> BindState;
+
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6,
+          p7));
+}
+
+}  // namespace base
+
+#endif  // BASE_BIND_H_
diff --git a/base/bind.h.pump b/base/bind.h.pump
new file mode 100644
index 0000000..b321649
--- /dev/null
+++ b/base/bind.h.pump
@@ -0,0 +1,153 @@
+$$ This is a pump file for generating file templates.  Pump is a python
+$$ script that is part of the Google Test suite of utilities.  Description
+$$ can be found here:
+$$
+$$ http://code.google.com/p/googletest/wiki/PumpManual
+$$
+
+$$
+$$ MAX_ARITY controls the number of arguments that Bind() supports.
+$$ The amount of code, and more importantly, the number of template types
+$$ generated by pump grows at O(MAX_ARITY^2).
+$$
+$$ We tried going to 11 and found it imposed an extra 10 penalty on windows
+$$ cycle times compared to our original baseline of 6.
+$$
+$$ Currently 7 is chosen as a compromise between supporting a convenient
+$$ number of arguments and keeping compile times low.  At 7, we have 115
+$$ templates being generated by pump.
+$$
+$$ Be careful when adjusting this number.  If people find a need to bind
+$$ a larger number of arguments, consider refactoring the function to use
+$$ a param struct instead of raising the MAX_ARITY.
+$$
+$$ See http://crbug.com/98542 for more context.
+$$
+$var MAX_ARITY = 7
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIND_H_
+#define BASE_BIND_H_
+
+#include "base/bind_internal.h"
+#include "base/callback_internal.h"
+
+// -----------------------------------------------------------------------------
+// Usage documentation
+// -----------------------------------------------------------------------------
+//
+// See base/callback.h for documentation.
+//
+//
+// -----------------------------------------------------------------------------
+// Implementation notes
+// -----------------------------------------------------------------------------
+//
+// If you're reading the implementation, before proceeding further, you should
+// read the top comment of base/bind_internal.h for a definition of common
+// terms and concepts.
+//
+// RETURN TYPES
+//
+// Though Bind()'s result is meant to be stored in a Callback<> type, it
+// cannot actually return the exact type without requiring a large amount
+// of extra template specializations. The problem is that in order to
+// discern the correct specialization of Callback<>, Bind would need to
+// unwrap the function signature to determine the signature's arity, and
+// whether or not it is a method.
+//
+// Each unique combination of (arity, function_type, num_prebound) where
+// function_type is one of {function, method, const_method} would require
+// one specialization.  We eventually have to do a similar number of
+// specializations anyways in the implementation (see the Invoker<>,
+// classes).  However, it is avoidable in Bind if we return the result
+// via an indirection like we do below.
+//
+// TODO(ajwong): We might be able to avoid this now, but need to test.
+//
+// It is possible to move most of the COMPILE_ASSERT asserts into BindState<>,
+// but it feels a little nicer to have the asserts here so people do not
+// need to crack open bind_internal.h.  On the other hand, it makes Bind()
+// harder to read.
+
+namespace base {
+
+$range ARITY 0..MAX_ARITY
+$for ARITY [[
+$range ARG 1..ARITY
+
+template <typename Functor[[]]
+$if ARITY > 0 [[, ]] $for ARG , [[typename P$(ARG)]]>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        void($for ARG , [[typename internal::CallbackParamTraits<P$(ARG)>::StorageType]])>
+            ::UnboundRunType>
+Bind(Functor functor
+$if ARITY > 0 [[, ]] $for ARG , [[const P$(ARG)& p$(ARG)]]) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef internal::FunctionTraits<typename RunnableType::RunType>
+      BoundFunctorTraits;
+
+$if ARITY > 0 [[
+
+  // Do not allow binding a non-const reference parameter. Non-const reference
+  // parameters are disallowed by the Google style guide.  Also, binding a
+  // non-const reference parameter can make for subtle bugs because the
+  // invoked function will receive a reference to the stored copy of the
+  // argument and not the original.
+  COMPILE_ASSERT(
+      !($for ARG || [[
+is_non_const_reference<typename BoundFunctorTraits::A$(ARG)Type>::value ]]),
+      do_not_bind_functions_with_nonconst_ref);
+
+]]
+
+
+$for ARG [[
+
+
+$if ARG == 1 [[
+  // For methods, we need to be careful for parameter 1.  We do not require
+  // a scoped_refptr because BindState<> itself takes care of AddRef() for
+  // methods. We also disallow binding of an array as the method's target
+  // object.
+  COMPILE_ASSERT(
+      internal::HasIsMethodTag<RunnableType>::value ||
+          !internal::NeedsScopedRefptrButGetsRawPtr<P$(ARG)>::value,
+      p$(ARG)_is_refcounted_type_and_needs_scoped_refptr);
+  COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
+                     !is_array<P$(ARG)>::value,
+                 first_bound_argument_to_method_cannot_be_array);
+]] $else [[
+  COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P$(ARG)>::value,
+                 p$(ARG)_is_refcounted_type_and_needs_scoped_refptr);
+]]  $$ $if ARG
+
+]]  $$ $for ARG
+
+  typedef internal::BindState<RunnableType, RunType, [[]]
+void($for ARG , [[typename internal::CallbackParamTraits<P$(ARG)>::StorageType]])> [[]]
+BindState;
+
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor)[[]]
+$if ARITY > 0 [[, ]] $for ARG , [[p$(ARG)]]));
+}
+
+]]  $$ for ARITY
+
+}  // namespace base
+
+#endif  // BASE_BIND_H_
diff --git a/base/bind_helpers.cc b/base/bind_helpers.cc
new file mode 100644
index 0000000..f2fc3bb
--- /dev/null
+++ b/base/bind_helpers.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 "base/bind_helpers.h"
+
+#include "base/callback.h"
+
+namespace base {
+
+void DoNothing() {
+}
+
+ScopedClosureRunner::ScopedClosureRunner(const Closure& closure)
+    : closure_(closure) {
+}
+
+ScopedClosureRunner::~ScopedClosureRunner() {
+  if (!closure_.is_null())
+    closure_.Run();
+}
+
+Closure ScopedClosureRunner::Release() {
+  Closure result = closure_;
+  closure_.Reset();
+  return result;
+}
+
+}  // namespace base
diff --git a/base/bind_helpers.h b/base/bind_helpers.h
new file mode 100644
index 0000000..0ac9069
--- /dev/null
+++ b/base/bind_helpers.h
@@ -0,0 +1,562 @@
+// Copyright (c) 2011 The Chromium 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(), bass::Passed(),
+// base::ConstRef(), and base::IgnoreResult().
+//
+// Unretained() allows Bind() to bind a non-refcounted class, and to disable
+// refcounting on arguments that are refcounted objects.
+//
+// Owned() transfers ownership of an object to the Callback resulting from
+// bind; the object will be deleted when the Callback is deleted.
+//
+// Passed() is for transferring movable-but-not-copyable types (eg. scoped_ptr)
+// through a Callback. Logically, this signifies a destructive transfer of
+// the state of the argument into the target function.  Invoking
+// Callback::Run() twice on a Callback that was created with a Passed()
+// argument will CHECK() because the first invocation would have already
+// transferred ownership to the target function.
+//
+// ConstRef() allows binding a constant reference to an argument rather
+// than a copy.
+//
+// IgnoreResult() is used to adapt a function or Callback with a return type to
+// one with a void return. This is most useful if you have a function with,
+// say, a pesky ignorable bool return that you want to use with PostTask or
+// something else that expect a Callback with a void return.
+//
+// EXAMPLE OF Unretained():
+//
+//   class Foo {
+//    public:
+//     void func() { cout << "Foo:f" << endl; }
+//   };
+//
+//   // In some function somewhere.
+//   Foo foo;
+//   Closure foo_callback =
+//       Bind(&Foo::func, Unretained(&foo));
+//   foo_callback.Run();  // Prints "Foo:f".
+//
+// Without the Unretained() wrapper on |&foo|, the above call would fail
+// to compile because Foo does not support the AddRef() and Release() methods.
+//
+//
+// EXAMPLE OF Owned():
+//
+//   void foo(int* arg) { cout << *arg << endl }
+//
+//   int* pn = new int(1);
+//   Closure foo_callback = Bind(&foo, Owned(pn));
+//
+//   foo_callback.Run();  // Prints "1"
+//   foo_callback.Run();  // Prints "1"
+//   *n = 2;
+//   foo_callback.Run();  // Prints "2"
+//
+//   foo_callback.Reset();  // |pn| is deleted.  Also will happen when
+//                          // |foo_callback| goes out of scope.
+//
+// Without Owned(), someone would have to know to delete |pn| when the last
+// reference to the Callback is deleted.
+//
+//
+// EXAMPLE OF ConstRef():
+//
+//   void foo(int arg) { cout << arg << endl }
+//
+//   int n = 1;
+//   Closure no_ref = Bind(&foo, n);
+//   Closure has_ref = Bind(&foo, ConstRef(n));
+//
+//   no_ref.Run();  // Prints "1"
+//   has_ref.Run();  // Prints "1"
+//
+//   n = 2;
+//   no_ref.Run();  // Prints "1"
+//   has_ref.Run();  // Prints "2"
+//
+// Note that because ConstRef() takes a reference on |n|, |n| must outlive all
+// its bound callbacks.
+//
+//
+// EXAMPLE OF IgnoreResult():
+//
+//   int DoSomething(int arg) { cout << arg << endl; }
+//
+//   // Assign to a Callback with a void return type.
+//   Callback<void(int)> cb = Bind(IgnoreResult(&DoSomething));
+//   cb->Run(1);  // Prints "1".
+//
+//   // Prints "1" on |ml|.
+//   ml->PostTask(FROM_HERE, Bind(IgnoreResult(&DoSomething), 1);
+//
+//
+// EXAMPLE OF Passed():
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) { }
+//   scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); }
+//
+//   scoped_ptr<Foo> f(new Foo());
+//
+//   // |cb| is given ownership of Foo(). |f| is now NULL.
+//   // You can use f.Pass() in place of &f, but it's more verbose.
+//   Closure cb = Bind(&TakesOwnership, Passed(&f));
+//
+//   // Run was never called so |cb| still owns Foo() and deletes
+//   // it on Reset().
+//   cb.Reset();
+//
+//   // |cb| is given a new Foo created by CreateFoo().
+//   cb = Bind(&TakesOwnership, Passed(CreateFoo()));
+//
+//   // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
+//   // no longer owns Foo() and, if reset, would not delete Foo().
+//   cb.Run();  // Foo() is now transferred to |arg| and deleted.
+//   cb.Run();  // This CHECK()s since Foo() already been used once.
+//
+// Passed() is particularly useful with PostTask() when you are transferring
+// ownership of an argument into a task, but don't necessarily know if the
+// task will always be executed. This can happen if the task is cancellable
+// or if it is posted to a MessageLoopProxy.
+//
+//
+// 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.
+//   ScopedClosureRunner - Scoper object that runs the wrapped closure when it
+//                         goes out of scope. It's conceptually similar to
+//                         scoped_ptr<> but calls Run() instead of deleting
+//                         the pointer.
+
+#ifndef BASE_BIND_HELPERS_H_
+#define BASE_BIND_HELPERS_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/template_util.h"
+
+namespace base {
+namespace internal {
+
+// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T
+// for the existence of AddRef() and Release() functions of the correct
+// signature.
+//
+// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
+// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
+// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison
+// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
+//
+// The last link in particular show the method used below.
+//
+// For SFINAE to work with inherited methods, we need to pull some extra tricks
+// with multiple inheritance.  In the more standard formulation, the overloads
+// of Check would be:
+//
+//   template <typename C>
+//   Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*);
+//
+//   template <typename C>
+//   No NotTheCheckWeWant(...);
+//
+//   static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes);
+//
+// The problem here is that template resolution will not match
+// C::TargetFunc if TargetFunc does not exist directly in C.  That is, if
+// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match,
+// |value| will be false.  This formulation only checks for whether or
+// not TargetFunc exist directly in the class being introspected.
+//
+// To get around this, we play a dirty trick with multiple inheritance.
+// First, We create a class BaseMixin that declares each function that we
+// want to probe for.  Then we create a class Base that inherits from both T
+// (the class we wish to probe) and BaseMixin.  Note that the function
+// signature in BaseMixin does not need to match the signature of the function
+// we are probing for; thus it's easiest to just use void(void).
+//
+// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
+// ambiguous resolution between BaseMixin and T.  This lets us write the
+// following:
+//
+//   template <typename C>
+//   No GoodCheck(Helper<&C::TargetFunc>*);
+//
+//   template <typename C>
+//   Yes GoodCheck(...);
+//
+//   static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes);
+//
+// Notice here that the variadic version of GoodCheck() returns Yes here
+// instead of No like the previous one. Also notice that we calculate |value|
+// by specializing GoodCheck() on Base instead of T.
+//
+// We've reversed the roles of the variadic, and Helper overloads.
+// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid
+// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve
+// to the variadic version if T has TargetFunc.  If T::TargetFunc does not
+// exist, then &C::TargetFunc is not ambiguous, and the overload resolution
+// will prefer GoodCheck(Helper<&C::TargetFunc>*).
+//
+// This method of SFINAE will correctly probe for inherited names, but it cannot
+// typecheck those names.  It's still a good enough sanity check though.
+//
+// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008.
+//
+// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted
+// this works well.
+//
+// TODO(ajwong): Make this check for Release() as well.
+// See http://crbug.com/82038.
+template <typename T>
+class SupportsAddRefAndRelease {
+  typedef char Yes[1];
+  typedef char No[2];
+
+  struct BaseMixin {
+    void AddRef();
+  };
+
+// MSVC warns when you try to use Base if T has a private destructor, the
+// common pattern for refcounted types. It does this even though no attempt to
+// instantiate Base is made.  We disable the warning for this definition.
+#if defined(OS_WIN)
+#pragma warning(disable:4624)
+#endif
+  struct Base : public T, public BaseMixin {
+  };
+#if defined(OS_WIN)
+#pragma warning(default:4624)
+#endif
+
+  template <void(BaseMixin::*)(void)> struct Helper {};
+
+  template <typename C>
+  static No& Check(Helper<&C::AddRef>*);
+
+  template <typename >
+  static Yes& Check(...);
+
+ public:
+  static const bool value = sizeof(Check<Base>(0)) == sizeof(Yes);
+};
+
+// Helpers to assert that arguments of a recounted type are bound with a
+// scoped_refptr.
+template <bool IsClasstype, typename T>
+struct UnsafeBindtoRefCountedArgHelper : false_type {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArgHelper<true, T>
+    : integral_constant<bool, SupportsAddRefAndRelease<T>::value> {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArg : false_type {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArg<T*>
+    : UnsafeBindtoRefCountedArgHelper<is_class<T>::value, T> {
+};
+
+template <typename T>
+class HasIsMethodTag {
+  typedef char Yes[1];
+  typedef char No[2];
+
+  template <typename U>
+  static Yes& Check(typename U::IsMethod*);
+
+  template <typename U>
+  static No& Check(...);
+
+ public:
+  static const bool value = sizeof(Check<T>(0)) == sizeof(Yes);
+};
+
+template <typename T>
+class UnretainedWrapper {
+ public:
+  explicit UnretainedWrapper(T* o) : ptr_(o) {}
+  T* get() const { return ptr_; }
+ private:
+  T* ptr_;
+};
+
+template <typename T>
+class ConstRefWrapper {
+ public:
+  explicit ConstRefWrapper(const T& o) : ptr_(&o) {}
+  const T& get() const { return *ptr_; }
+ private:
+  const T* ptr_;
+};
+
+template <typename T>
+struct IgnoreResultHelper {
+  explicit IgnoreResultHelper(T functor) : functor_(functor) {}
+
+  T functor_;
+};
+
+template <typename T>
+struct IgnoreResultHelper<Callback<T> > {
+  explicit IgnoreResultHelper(const Callback<T>& functor) : functor_(functor) {}
+
+  const Callback<T>& functor_;
+};
+
+// An alternate implementation is to avoid the destructive copy, and instead
+// specialize ParamTraits<> for OwnedWrapper<> to change the StorageType to
+// a class that is essentially a scoped_ptr<>.
+//
+// The current implementation has the benefit though of leaving ParamTraits<>
+// fully in callback_internal.h as well as avoiding type conversions during
+// storage.
+template <typename T>
+class OwnedWrapper {
+ public:
+  explicit OwnedWrapper(T* o) : ptr_(o) {}
+  ~OwnedWrapper() { delete ptr_; }
+  T* get() const { return ptr_; }
+  OwnedWrapper(const OwnedWrapper& other) {
+    ptr_ = other.ptr_;
+    other.ptr_ = NULL;
+  }
+
+ private:
+  mutable T* ptr_;
+};
+
+// PassedWrapper is a copyable adapter for a scoper that ignores const.
+//
+// It is needed to get around the fact that Bind() takes a const reference to
+// all its arguments.  Because Bind() takes a const reference to avoid
+// unnecessary copies, it is incompatible with movable-but-not-copyable
+// types; doing a destructive "move" of the type into Bind() would violate
+// the const correctness.
+//
+// This conundrum cannot be solved without either C++11 rvalue references or
+// a O(2^n) blowup of Bind() templates to handle each combination of regular
+// types and movable-but-not-copyable types.  Thus we introduce a wrapper type
+// that is copyable to transmit the correct type information down into
+// BindState<>. Ignoring const in this type makes sense because it is only
+// created when we are explicitly trying to do a destructive move.
+//
+// Two notes:
+//  1) PassedWrapper supports any type that has a "Pass()" function.
+//     This is intentional. The whitelisting of which specific types we
+//     support is maintained by CallbackParamTraits<>.
+//  2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
+//     scoper to a Callback and allow the Callback to execute once.
+template <typename T>
+class PassedWrapper {
+ public:
+  explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
+  PassedWrapper(const PassedWrapper& other)
+      : is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
+  }
+  T Pass() const {
+    CHECK(is_valid_);
+    is_valid_ = false;
+    return scoper_.Pass();
+  }
+
+ private:
+  mutable bool is_valid_;
+  mutable T scoper_;
+};
+
+// Unwrap the stored parameters for the wrappers above.
+template <typename T>
+struct UnwrapTraits {
+  typedef const T& ForwardType;
+  static ForwardType Unwrap(const T& o) { return o; }
+};
+
+template <typename T>
+struct UnwrapTraits<UnretainedWrapper<T> > {
+  typedef T* ForwardType;
+  static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
+    return unretained.get();
+  }
+};
+
+template <typename T>
+struct UnwrapTraits<ConstRefWrapper<T> > {
+  typedef const T& ForwardType;
+  static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
+    return const_ref.get();
+  }
+};
+
+template <typename T>
+struct UnwrapTraits<scoped_refptr<T> > {
+  typedef T* ForwardType;
+  static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
+};
+
+template <typename T>
+struct UnwrapTraits<WeakPtr<T> > {
+  typedef const WeakPtr<T>& ForwardType;
+  static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
+};
+
+template <typename T>
+struct UnwrapTraits<OwnedWrapper<T> > {
+  typedef T* ForwardType;
+  static ForwardType Unwrap(const OwnedWrapper<T>& o) {
+    return o.get();
+  }
+};
+
+template <typename T>
+struct UnwrapTraits<PassedWrapper<T> > {
+  typedef T ForwardType;
+  static T Unwrap(PassedWrapper<T>& o) {
+    return o.Pass();
+  }
+};
+
+// Utility for handling different refcounting semantics in the Bind()
+// function.
+template <bool is_method, typename T>
+struct MaybeRefcount;
+
+template <typename T>
+struct MaybeRefcount<false, T> {
+  static void AddRef(const T&) {}
+  static void Release(const T&) {}
+};
+
+template <typename T, size_t n>
+struct MaybeRefcount<false, T[n]> {
+  static void AddRef(const T*) {}
+  static void Release(const T*) {}
+};
+
+template <typename T>
+struct MaybeRefcount<true, T> {
+  static void AddRef(const T&) {}
+  static void Release(const T&) {}
+};
+
+template <typename T>
+struct MaybeRefcount<true, T*> {
+  static void AddRef(T* o) { o->AddRef(); }
+  static void Release(T* o) { o->Release(); }
+};
+
+// No need to additionally AddRef() and Release() since we are storing a
+// scoped_refptr<> inside the storage object already.
+template <typename T>
+struct MaybeRefcount<true, scoped_refptr<T> > {
+  static void AddRef(const scoped_refptr<T>& o) {}
+  static void Release(const scoped_refptr<T>& o) {}
+};
+
+template <typename T>
+struct MaybeRefcount<true, const T*> {
+  static void AddRef(const T* o) { o->AddRef(); }
+  static void Release(const T* o) { o->Release(); }
+};
+
+// 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.
+//
+// P1 should be the type of the object that will be received of the method.
+template <bool IsMethod, typename P1>
+struct IsWeakMethod : public false_type {};
+
+template <typename T>
+struct IsWeakMethod<true, WeakPtr<T> > : public true_type {};
+
+template <typename T>
+struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T> > > : public true_type {};
+
+}  // namespace internal
+
+template <typename T>
+static inline internal::UnretainedWrapper<T> Unretained(T* o) {
+  return internal::UnretainedWrapper<T>(o);
+}
+
+template <typename T>
+static inline internal::ConstRefWrapper<T> ConstRef(const T& o) {
+  return internal::ConstRefWrapper<T>(o);
+}
+
+template <typename T>
+static inline internal::OwnedWrapper<T> Owned(T* o) {
+  return internal::OwnedWrapper<T>(o);
+}
+
+// We offer 2 syntaxes for calling Passed().  The first takes a temporary and
+// is best suited for use with the return value of a function. The second
+// takes a pointer to the scoper and is just syntactic sugar to avoid having
+// to write Passed(scoper.Pass()).
+template <typename T>
+static inline internal::PassedWrapper<T> Passed(T scoper) {
+  return internal::PassedWrapper<T>(scoper.Pass());
+}
+template <typename T>
+static inline internal::PassedWrapper<T> Passed(T* scoper) {
+  return internal::PassedWrapper<T>(scoper->Pass());
+}
+
+template <typename T>
+static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
+  return internal::IgnoreResultHelper<T>(data);
+}
+
+template <typename T>
+static inline internal::IgnoreResultHelper<Callback<T> >
+IgnoreResult(const Callback<T>& data) {
+  return internal::IgnoreResultHelper<Callback<T> >(data);
+}
+
+BASE_EXPORT void DoNothing();
+
+template<typename T>
+void DeletePointer(T* obj) {
+  delete obj;
+}
+
+// ScopedClosureRunner is akin to scoped_ptr for Closures. It ensures that the
+// Closure is executed and deleted no matter how the current scope exits.
+class BASE_EXPORT ScopedClosureRunner {
+ public:
+  explicit ScopedClosureRunner(const Closure& closure);
+  ~ScopedClosureRunner();
+
+  Closure Release();
+
+ private:
+  Closure closure_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedClosureRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_BIND_HELPERS_H_
diff --git a/base/bind_helpers_unittest.cc b/base/bind_helpers_unittest.cc
new file mode 100644
index 0000000..3ef2d75
--- /dev/null
+++ b/base/bind_helpers_unittest.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/bind_helpers.h"
+
+#include "base/callback.h"
+#include "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void Increment(int* value) {
+  (*value)++;
+}
+
+TEST(BindHelpersTest, TestScopedClosureRunnerExitScope) {
+  int run_count = 0;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count));
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(BindHelpersTest, TestScopedClosureRunnerRelease) {
+  int run_count = 0;
+  base::Closure c;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count));
+    c = runner.Release();
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(0, run_count);
+  c.Run();
+  EXPECT_EQ(1, run_count);
+}
+
+}  // namespace
diff --git a/base/bind_internal.h b/base/bind_internal.h
new file mode 100644
index 0000000..4e155ab
--- /dev/null
+++ b/base/bind_internal.h
@@ -0,0 +1,2792 @@
+// This file was GENERATED by command:
+//     pump.py bind_internal.h.pump
+// DO NOT EDIT BY HAND!!!
+
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIND_INTERNAL_H_
+#define BASE_BIND_INTERNAL_H_
+
+#include "base/bind_helpers.h"
+#include "base/callback_internal.h"
+#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
+#include "base/memory/weak_ptr.h"
+#include "base/template_util.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/bind_internal_win.h"
+#endif
+
+namespace base {
+namespace internal {
+
+// See base/callback.h for user documentation.
+//
+//
+// CONCEPTS:
+//  Runnable -- A type (really a type class) that has a single Run() method
+//              and a RunType typedef that corresponds to the type of Run().
+//              A Runnable can declare that it should treated like a method
+//              call by including a typedef named IsMethod.  The value of
+//              this typedef is NOT inspected, only the existence.  When a
+//              Runnable declares itself a method, Bind() will enforce special
+//              refcounting + WeakPtr handling semantics for the first
+//              parameter which is expected to be an object.
+//  Functor -- A copyable type representing something that should be called.
+//             All function pointers, Callback<>, and Runnables are functors
+//             even if the invocation syntax differs.
+//  RunType -- A function type (as opposed to function _pointer_ type) for
+//             a Run() function.  Usually just a convenience typedef.
+//  (Bound)ArgsType -- A function type that is being (ab)used to store the
+//                     types of set of arguments.  The "return" type is always
+//                     void here.  We use this hack so that we do not need
+//                     a new type name for each arity of type. (eg.,
+//                     BindState1, BindState2).  This makes forward
+//                     declarations and friending much much easier.
+//
+// Types:
+//  RunnableAdapter<> -- Wraps the various "function" pointer types into an
+//                       object that adheres to the Runnable interface.
+//                       There are |3*ARITY| RunnableAdapter types.
+//  FunctionTraits<> -- Type traits that unwrap a function signature into a
+//                      a set of easier to use typedefs.  Used mainly for
+//                      compile time asserts.
+//                      There are |ARITY| FunctionTraits types.
+//  ForceVoidReturn<> -- Helper class for translating function signatures to
+//                       equivalent forms with a "void" return type.
+//                    There are |ARITY| ForceVoidReturn types.
+//  FunctorTraits<> -- Type traits used determine the correct RunType and
+//                     RunnableType for a Functor.  This is where function
+//                     signature adapters are applied.
+//                    There are |ARITY| ForceVoidReturn types.
+//  MakeRunnable<> -- Takes a Functor and returns an object in the Runnable
+//                    type class that represents the underlying Functor.
+//                    There are |O(1)| MakeRunnable types.
+//  InvokeHelper<> -- Take a Runnable + arguments and actully invokes it.
+// Handle the differing syntaxes needed for WeakPtr<> support,
+//                    and for ignoring return values.  This is separate from
+//                    Invoker to avoid creating multiple version of Invoker<>
+//                    which grows at O(n^2) with the arity.
+//                    There are |k*ARITY| InvokeHelper types.
+//  Invoker<> -- Unwraps the curried parameters and executes the Runnable.
+//               There are |(ARITY^2 + ARITY)/2| Invoketypes.
+//  BindState<> -- Stores the curried parameters, and is the main entry point
+//                 into the Bind() system, doing most of the type resolution.
+//                 There are ARITY BindState types.
+
+// RunnableAdapter<>
+//
+// The RunnableAdapter<> templates provide a uniform interface for invoking
+// a function pointer, method pointer, or const method pointer. The adapter
+// exposes a Run() method with an appropriate signature. Using this wrapper
+// allows for writing code that supports all three pointer types without
+// undue repetition.  Without it, a lot of code would need to be repeated 3
+// times.
+//
+// For method pointers and const method pointers the first argument to Run()
+// is considered to be the received of the method.  This is similar to STL's
+// mem_fun().
+//
+// This class also exposes a RunType typedef that is the function type of the
+// Run() function.
+//
+// If and only if the wrapper contains a method or const method pointer, an
+// IsMethod typedef is exposed.  The existence of this typedef (NOT the value)
+// marks that the wrapper should be considered a method wrapper.
+
+template <typename Functor>
+class RunnableAdapter;
+
+// Function: Arity 0.
+template <typename R>
+class RunnableAdapter<R(*)()> {
+ public:
+  typedef R (RunType)();
+
+  explicit RunnableAdapter(R(*function)())
+      : function_(function) {
+  }
+
+  R Run() {
+    return function_();
+  }
+
+ private:
+  R (*function_)();
+};
+
+// Method: Arity 0.
+template <typename R, typename T>
+class RunnableAdapter<R(T::*)()> {
+ public:
+  typedef R (RunType)(T*);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)())
+      : method_(method) {
+  }
+
+  R Run(T* object) {
+    return (object->*method_)();
+  }
+
+ private:
+  R (T::*method_)();
+};
+
+// Const Method: Arity 0.
+template <typename R, typename T>
+class RunnableAdapter<R(T::*)() const> {
+ public:
+  typedef R (RunType)(const T*);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)() const)
+      : method_(method) {
+  }
+
+  R Run(const T* object) {
+    return (object->*method_)();
+  }
+
+ private:
+  R (T::*method_)() const;
+};
+
+// Function: Arity 1.
+template <typename R, typename A1>
+class RunnableAdapter<R(*)(A1)> {
+ public:
+  typedef R (RunType)(A1);
+
+  explicit RunnableAdapter(R(*function)(A1))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1) {
+    return function_(CallbackForward(a1));
+  }
+
+ private:
+  R (*function_)(A1);
+};
+
+// Method: Arity 1.
+template <typename R, typename T, typename A1>
+class RunnableAdapter<R(T::*)(A1)> {
+ public:
+  typedef R (RunType)(T*, A1);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1))
+      : method_(method) {
+  }
+
+  R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1) {
+    return (object->*method_)(CallbackForward(a1));
+  }
+
+ private:
+  R (T::*method_)(A1);
+};
+
+// Const Method: Arity 1.
+template <typename R, typename T, typename A1>
+class RunnableAdapter<R(T::*)(A1) const> {
+ public:
+  typedef R (RunType)(const T*, A1);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1) const)
+      : method_(method) {
+  }
+
+  R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1) {
+    return (object->*method_)(CallbackForward(a1));
+  }
+
+ private:
+  R (T::*method_)(A1) const;
+};
+
+// Function: Arity 2.
+template <typename R, typename A1, typename A2>
+class RunnableAdapter<R(*)(A1, A2)> {
+ public:
+  typedef R (RunType)(A1, A2);
+
+  explicit RunnableAdapter(R(*function)(A1, A2))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2) {
+    return function_(CallbackForward(a1), CallbackForward(a2));
+  }
+
+ private:
+  R (*function_)(A1, A2);
+};
+
+// Method: Arity 2.
+template <typename R, typename T, typename A1, typename A2>
+class RunnableAdapter<R(T::*)(A1, A2)> {
+ public:
+  typedef R (RunType)(T*, A1, A2);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2))
+      : method_(method) {
+  }
+
+  R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2));
+  }
+
+ private:
+  R (T::*method_)(A1, A2);
+};
+
+// Const Method: Arity 2.
+template <typename R, typename T, typename A1, typename A2>
+class RunnableAdapter<R(T::*)(A1, A2) const> {
+ public:
+  typedef R (RunType)(const T*, A1, A2);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2) const)
+      : method_(method) {
+  }
+
+  R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2));
+  }
+
+ private:
+  R (T::*method_)(A1, A2) const;
+};
+
+// Function: Arity 3.
+template <typename R, typename A1, typename A2, typename A3>
+class RunnableAdapter<R(*)(A1, A2, A3)> {
+ public:
+  typedef R (RunType)(A1, A2, A3);
+
+  explicit RunnableAdapter(R(*function)(A1, A2, A3))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3) {
+    return function_(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3));
+  }
+
+ private:
+  R (*function_)(A1, A2, A3);
+};
+
+// Method: Arity 3.
+template <typename R, typename T, typename A1, typename A2, typename A3>
+class RunnableAdapter<R(T::*)(A1, A2, A3)> {
+ public:
+  typedef R (RunType)(T*, A1, A2, A3);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2, A3))
+      : method_(method) {
+  }
+
+  R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3));
+  }
+
+ private:
+  R (T::*method_)(A1, A2, A3);
+};
+
+// Const Method: Arity 3.
+template <typename R, typename T, typename A1, typename A2, typename A3>
+class RunnableAdapter<R(T::*)(A1, A2, A3) const> {
+ public:
+  typedef R (RunType)(const T*, A1, A2, A3);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2, A3) const)
+      : method_(method) {
+  }
+
+  R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3));
+  }
+
+ private:
+  R (T::*method_)(A1, A2, A3) const;
+};
+
+// Function: Arity 4.
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+class RunnableAdapter<R(*)(A1, A2, A3, A4)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4);
+
+  explicit RunnableAdapter(R(*function)(A1, A2, A3, A4))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4) {
+    return function_(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4));
+  }
+
+ private:
+  R (*function_)(A1, A2, A3, A4);
+};
+
+// Method: Arity 4.
+template <typename R, typename T, typename A1, typename A2, typename A3,
+    typename A4>
+class RunnableAdapter<R(T::*)(A1, A2, A3, A4)> {
+ public:
+  typedef R (RunType)(T*, A1, A2, A3, A4);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4))
+      : method_(method) {
+  }
+
+  R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4));
+  }
+
+ private:
+  R (T::*method_)(A1, A2, A3, A4);
+};
+
+// Const Method: Arity 4.
+template <typename R, typename T, typename A1, typename A2, typename A3,
+    typename A4>
+class RunnableAdapter<R(T::*)(A1, A2, A3, A4) const> {
+ public:
+  typedef R (RunType)(const T*, A1, A2, A3, A4);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4) const)
+      : method_(method) {
+  }
+
+  R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4));
+  }
+
+ private:
+  R (T::*method_)(A1, A2, A3, A4) const;
+};
+
+// Function: Arity 5.
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5>
+class RunnableAdapter<R(*)(A1, A2, A3, A4, A5)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5);
+
+  explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5) {
+    return function_(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5));
+  }
+
+ private:
+  R (*function_)(A1, A2, A3, A4, A5);
+};
+
+// Method: Arity 5.
+template <typename R, typename T, typename A1, typename A2, typename A3,
+    typename A4, typename A5>
+class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5)> {
+ public:
+  typedef R (RunType)(T*, A1, A2, A3, A4, A5);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5))
+      : method_(method) {
+  }
+
+  R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5));
+  }
+
+ private:
+  R (T::*method_)(A1, A2, A3, A4, A5);
+};
+
+// Const Method: Arity 5.
+template <typename R, typename T, typename A1, typename A2, typename A3,
+    typename A4, typename A5>
+class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5) const> {
+ public:
+  typedef R (RunType)(const T*, A1, A2, A3, A4, A5);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5) const)
+      : method_(method) {
+  }
+
+  R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5));
+  }
+
+ private:
+  R (T::*method_)(A1, A2, A3, A4, A5) const;
+};
+
+// Function: Arity 6.
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6>
+class RunnableAdapter<R(*)(A1, A2, A3, A4, A5, A6)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5, A6);
+
+  explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5, A6))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5,
+      typename CallbackParamTraits<A6>::ForwardType a6) {
+    return function_(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
+        CallbackForward(a6));
+  }
+
+ private:
+  R (*function_)(A1, A2, A3, A4, A5, A6);
+};
+
+// Method: Arity 6.
+template <typename R, typename T, typename A1, typename A2, typename A3,
+    typename A4, typename A5, typename A6>
+class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6)> {
+ public:
+  typedef R (RunType)(T*, A1, A2, A3, A4, A5, A6);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6))
+      : method_(method) {
+  }
+
+  R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5,
+      typename CallbackParamTraits<A6>::ForwardType a6) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
+        CallbackForward(a6));
+  }
+
+ private:
+  R (T::*method_)(A1, A2, A3, A4, A5, A6);
+};
+
+// Const Method: Arity 6.
+template <typename R, typename T, typename A1, typename A2, typename A3,
+    typename A4, typename A5, typename A6>
+class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6) const> {
+ public:
+  typedef R (RunType)(const T*, A1, A2, A3, A4, A5, A6);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6) const)
+      : method_(method) {
+  }
+
+  R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5,
+      typename CallbackParamTraits<A6>::ForwardType a6) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
+        CallbackForward(a6));
+  }
+
+ private:
+  R (T::*method_)(A1, A2, A3, A4, A5, A6) const;
+};
+
+// Function: Arity 7.
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6, typename A7>
+class RunnableAdapter<R(*)(A1, A2, A3, A4, A5, A6, A7)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7);
+
+  explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5, A6, A7))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5,
+      typename CallbackParamTraits<A6>::ForwardType a6,
+      typename CallbackParamTraits<A7>::ForwardType a7) {
+    return function_(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
+        CallbackForward(a6), CallbackForward(a7));
+  }
+
+ private:
+  R (*function_)(A1, A2, A3, A4, A5, A6, A7);
+};
+
+// Method: Arity 7.
+template <typename R, typename T, typename A1, typename A2, typename A3,
+    typename A4, typename A5, typename A6, typename A7>
+class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6, A7)> {
+ public:
+  typedef R (RunType)(T*, A1, A2, A3, A4, A5, A6, A7);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6, A7))
+      : method_(method) {
+  }
+
+  R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5,
+      typename CallbackParamTraits<A6>::ForwardType a6,
+      typename CallbackParamTraits<A7>::ForwardType a7) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
+        CallbackForward(a6), CallbackForward(a7));
+  }
+
+ private:
+  R (T::*method_)(A1, A2, A3, A4, A5, A6, A7);
+};
+
+// Const Method: Arity 7.
+template <typename R, typename T, typename A1, typename A2, typename A3,
+    typename A4, typename A5, typename A6, typename A7>
+class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6, A7) const> {
+ public:
+  typedef R (RunType)(const T*, A1, A2, A3, A4, A5, A6, A7);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6, A7) const)
+      : method_(method) {
+  }
+
+  R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5,
+      typename CallbackParamTraits<A6>::ForwardType a6,
+      typename CallbackParamTraits<A7>::ForwardType a7) {
+    return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
+        CallbackForward(a6), CallbackForward(a7));
+  }
+
+ private:
+  R (T::*method_)(A1, A2, A3, A4, A5, A6, A7) const;
+};
+
+
+// FunctionTraits<>
+//
+// Breaks a function signature apart into typedefs for easier introspection.
+template <typename Sig>
+struct FunctionTraits;
+
+template <typename R>
+struct FunctionTraits<R()> {
+  typedef R ReturnType;
+};
+
+template <typename R, typename A1>
+struct FunctionTraits<R(A1)> {
+  typedef R ReturnType;
+  typedef A1 A1Type;
+};
+
+template <typename R, typename A1, typename A2>
+struct FunctionTraits<R(A1, A2)> {
+  typedef R ReturnType;
+  typedef A1 A1Type;
+  typedef A2 A2Type;
+};
+
+template <typename R, typename A1, typename A2, typename A3>
+struct FunctionTraits<R(A1, A2, A3)> {
+  typedef R ReturnType;
+  typedef A1 A1Type;
+  typedef A2 A2Type;
+  typedef A3 A3Type;
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+struct FunctionTraits<R(A1, A2, A3, A4)> {
+  typedef R ReturnType;
+  typedef A1 A1Type;
+  typedef A2 A2Type;
+  typedef A3 A3Type;
+  typedef A4 A4Type;
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5>
+struct FunctionTraits<R(A1, A2, A3, A4, A5)> {
+  typedef R ReturnType;
+  typedef A1 A1Type;
+  typedef A2 A2Type;
+  typedef A3 A3Type;
+  typedef A4 A4Type;
+  typedef A5 A5Type;
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6>
+struct FunctionTraits<R(A1, A2, A3, A4, A5, A6)> {
+  typedef R ReturnType;
+  typedef A1 A1Type;
+  typedef A2 A2Type;
+  typedef A3 A3Type;
+  typedef A4 A4Type;
+  typedef A5 A5Type;
+  typedef A6 A6Type;
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6, typename A7>
+struct FunctionTraits<R(A1, A2, A3, A4, A5, A6, A7)> {
+  typedef R ReturnType;
+  typedef A1 A1Type;
+  typedef A2 A2Type;
+  typedef A3 A3Type;
+  typedef A4 A4Type;
+  typedef A5 A5Type;
+  typedef A6 A6Type;
+  typedef A7 A7Type;
+};
+
+
+// ForceVoidReturn<>
+//
+// Set of templates that support forcing the function return type to void.
+template <typename Sig>
+struct ForceVoidReturn;
+
+template <typename R>
+struct ForceVoidReturn<R()> {
+  typedef void(RunType)();
+};
+
+template <typename R, typename A1>
+struct ForceVoidReturn<R(A1)> {
+  typedef void(RunType)(A1);
+};
+
+template <typename R, typename A1, typename A2>
+struct ForceVoidReturn<R(A1, A2)> {
+  typedef void(RunType)(A1, A2);
+};
+
+template <typename R, typename A1, typename A2, typename A3>
+struct ForceVoidReturn<R(A1, A2, A3)> {
+  typedef void(RunType)(A1, A2, A3);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+struct ForceVoidReturn<R(A1, A2, A3, A4)> {
+  typedef void(RunType)(A1, A2, A3, A4);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5>
+struct ForceVoidReturn<R(A1, A2, A3, A4, A5)> {
+  typedef void(RunType)(A1, A2, A3, A4, A5);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6>
+struct ForceVoidReturn<R(A1, A2, A3, A4, A5, A6)> {
+  typedef void(RunType)(A1, A2, A3, A4, A5, A6);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6, typename A7>
+struct ForceVoidReturn<R(A1, A2, A3, A4, A5, A6, A7)> {
+  typedef void(RunType)(A1, A2, A3, A4, A5, A6, A7);
+};
+
+
+// FunctorTraits<>
+//
+// See description at top of file.
+template <typename T>
+struct FunctorTraits {
+  typedef RunnableAdapter<T> RunnableType;
+  typedef typename RunnableType::RunType RunType;
+};
+
+template <typename T>
+struct FunctorTraits<IgnoreResultHelper<T> > {
+  typedef typename FunctorTraits<T>::RunnableType RunnableType;
+  typedef typename ForceVoidReturn<
+      typename RunnableType::RunType>::RunType RunType;
+};
+
+template <typename T>
+struct FunctorTraits<Callback<T> > {
+  typedef Callback<T> RunnableType;
+  typedef typename Callback<T>::RunType RunType;
+};
+
+
+// MakeRunnable<>
+//
+// Converts a passed in functor to a RunnableType using type inference.
+
+template <typename T>
+typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) {
+  return RunnableAdapter<T>(t);
+}
+
+template <typename T>
+typename FunctorTraits<T>::RunnableType
+MakeRunnable(const IgnoreResultHelper<T>& t) {
+  return MakeRunnable(t.functor_);
+}
+
+template <typename T>
+const typename FunctorTraits<Callback<T> >::RunnableType&
+MakeRunnable(const Callback<T>& t) {
+  return t;
+}
+
+
+// InvokeHelper<>
+//
+// There are 3 logical InvokeHelper<> specializations: normal, void-return,
+// WeakCalls.
+//
+// The normal type just calls the underlying runnable.
+//
+// We need a InvokeHelper to handle void return types in order to support
+// IgnoreResult().  Normally, if the Runnable's RunType had a void return,
+// the template system would just accept "return functor.Run()" ignoring
+// the fact that a void function is being used with return. This piece of
+// sugar breaks though when the Runnable's RunType is not void.  Thus, we
+// need a partial specialization to change the syntax to drop the "return"
+// from the invocation call.
+//
+// WeakCalls similarly need special syntax that is applied to the first
+// argument to check if they should no-op themselves.
+template <bool IsWeakCall, typename ReturnType, typename Runnable,
+          typename ArgsType>
+struct InvokeHelper;
+
+template <typename ReturnType, typename Runnable>
+struct InvokeHelper<false, ReturnType, Runnable,
+    void()>  {
+  static ReturnType MakeItSo(Runnable runnable) {
+    return runnable.Run();
+  }
+};
+
+template <typename Runnable>
+struct InvokeHelper<false, void, Runnable,
+    void()>  {
+  static void MakeItSo(Runnable runnable) {
+    runnable.Run();
+  }
+};
+
+template <typename ReturnType, typename Runnable,typename A1>
+struct InvokeHelper<false, ReturnType, Runnable,
+    void(A1)>  {
+  static ReturnType MakeItSo(Runnable runnable, A1 a1) {
+    return runnable.Run(CallbackForward(a1));
+  }
+};
+
+template <typename Runnable,typename A1>
+struct InvokeHelper<false, void, Runnable,
+    void(A1)>  {
+  static void MakeItSo(Runnable runnable, A1 a1) {
+    runnable.Run(CallbackForward(a1));
+  }
+};
+
+template <typename Runnable, typename A1>
+struct InvokeHelper<true, void, Runnable,
+    void(A1)>  {
+  static void MakeItSo(Runnable runnable, A1 a1) {
+    if (!a1.get()) {
+      return;
+    }
+
+    runnable.Run(CallbackForward(a1));
+  }
+};
+
+template <typename ReturnType, typename Runnable,typename A1, typename A2>
+struct InvokeHelper<false, ReturnType, Runnable,
+    void(A1, A2)>  {
+  static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2) {
+    return runnable.Run(CallbackForward(a1), CallbackForward(a2));
+  }
+};
+
+template <typename Runnable,typename A1, typename A2>
+struct InvokeHelper<false, void, Runnable,
+    void(A1, A2)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2) {
+    runnable.Run(CallbackForward(a1), CallbackForward(a2));
+  }
+};
+
+template <typename Runnable, typename A1, typename A2>
+struct InvokeHelper<true, void, Runnable,
+    void(A1, A2)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2) {
+    if (!a1.get()) {
+      return;
+    }
+
+    runnable.Run(CallbackForward(a1), CallbackForward(a2));
+  }
+};
+
+template <typename ReturnType, typename Runnable,typename A1, typename A2,
+    typename A3>
+struct InvokeHelper<false, ReturnType, Runnable,
+    void(A1, A2, A3)>  {
+  static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3) {
+    return runnable.Run(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3));
+  }
+};
+
+template <typename Runnable,typename A1, typename A2, typename A3>
+struct InvokeHelper<false, void, Runnable,
+    void(A1, A2, A3)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3) {
+    runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3));
+  }
+};
+
+template <typename Runnable, typename A1, typename A2, typename A3>
+struct InvokeHelper<true, void, Runnable,
+    void(A1, A2, A3)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3) {
+    if (!a1.get()) {
+      return;
+    }
+
+    runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3));
+  }
+};
+
+template <typename ReturnType, typename Runnable,typename A1, typename A2,
+    typename A3, typename A4>
+struct InvokeHelper<false, ReturnType, Runnable,
+    void(A1, A2, A3, A4)>  {
+  static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4) {
+    return runnable.Run(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4));
+  }
+};
+
+template <typename Runnable,typename A1, typename A2, typename A3, typename A4>
+struct InvokeHelper<false, void, Runnable,
+    void(A1, A2, A3, A4)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4) {
+    runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
+        CallbackForward(a4));
+  }
+};
+
+template <typename Runnable, typename A1, typename A2, typename A3, typename A4>
+struct InvokeHelper<true, void, Runnable,
+    void(A1, A2, A3, A4)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4) {
+    if (!a1.get()) {
+      return;
+    }
+
+    runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
+        CallbackForward(a4));
+  }
+};
+
+template <typename ReturnType, typename Runnable,typename A1, typename A2,
+    typename A3, typename A4, typename A5>
+struct InvokeHelper<false, ReturnType, Runnable,
+    void(A1, A2, A3, A4, A5)>  {
+  static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4,
+      A5 a5) {
+    return runnable.Run(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5));
+  }
+};
+
+template <typename Runnable,typename A1, typename A2, typename A3, typename A4,
+    typename A5>
+struct InvokeHelper<false, void, Runnable,
+    void(A1, A2, A3, A4, A5)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
+    runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
+        CallbackForward(a4), CallbackForward(a5));
+  }
+};
+
+template <typename Runnable, typename A1, typename A2, typename A3,
+    typename A4, typename A5>
+struct InvokeHelper<true, void, Runnable,
+    void(A1, A2, A3, A4, A5)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
+    if (!a1.get()) {
+      return;
+    }
+
+    runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
+        CallbackForward(a4), CallbackForward(a5));
+  }
+};
+
+template <typename ReturnType, typename Runnable,typename A1, typename A2,
+    typename A3, typename A4, typename A5, typename A6>
+struct InvokeHelper<false, ReturnType, Runnable,
+    void(A1, A2, A3, A4, A5, A6)>  {
+  static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4,
+      A5 a5, A6 a6) {
+    return runnable.Run(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
+        CallbackForward(a6));
+  }
+};
+
+template <typename Runnable,typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6>
+struct InvokeHelper<false, void, Runnable,
+    void(A1, A2, A3, A4, A5, A6)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5,
+      A6 a6) {
+    runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
+        CallbackForward(a4), CallbackForward(a5), CallbackForward(a6));
+  }
+};
+
+template <typename Runnable, typename A1, typename A2, typename A3,
+    typename A4, typename A5, typename A6>
+struct InvokeHelper<true, void, Runnable,
+    void(A1, A2, A3, A4, A5, A6)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5,
+      A6 a6) {
+    if (!a1.get()) {
+      return;
+    }
+
+    runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
+        CallbackForward(a4), CallbackForward(a5), CallbackForward(a6));
+  }
+};
+
+template <typename ReturnType, typename Runnable,typename A1, typename A2,
+    typename A3, typename A4, typename A5, typename A6, typename A7>
+struct InvokeHelper<false, ReturnType, Runnable,
+    void(A1, A2, A3, A4, A5, A6, A7)>  {
+  static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4,
+      A5 a5, A6 a6, A7 a7) {
+    return runnable.Run(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
+        CallbackForward(a6), CallbackForward(a7));
+  }
+};
+
+template <typename Runnable,typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6, typename A7>
+struct InvokeHelper<false, void, Runnable,
+    void(A1, A2, A3, A4, A5, A6, A7)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5,
+      A6 a6, A7 a7) {
+    runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
+        CallbackForward(a4), CallbackForward(a5), CallbackForward(a6),
+        CallbackForward(a7));
+  }
+};
+
+template <typename Runnable, typename A1, typename A2, typename A3,
+    typename A4, typename A5, typename A6, typename A7>
+struct InvokeHelper<true, void, Runnable,
+    void(A1, A2, A3, A4, A5, A6, A7)>  {
+  static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5,
+      A6 a6, A7 a7) {
+    if (!a1.get()) {
+      return;
+    }
+
+    runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
+        CallbackForward(a4), CallbackForward(a5), CallbackForward(a6),
+        CallbackForward(a7));
+  }
+};
+
+#if !defined(_MSC_VER)
+
+template <typename ReturnType, typename Runnable, typename ArgsType>
+struct InvokeHelper<true, ReturnType, Runnable, ArgsType> {
+  // WeakCalls are only supported for functions with a void return type.
+  // Otherwise, the function result would be undefined if the the WeakPtr<>
+  // is invalidated.
+  COMPILE_ASSERT(is_void<ReturnType>::value,
+                 weak_ptrs_can_only_bind_to_methods_without_return_values);
+};
+
+#endif
+
+// Invoker<>
+//
+// See description at the top of the file.
+template <int NumBound, typename Storage, typename RunType>
+struct Invoker;
+
+// Arity 0 -> 0.
+template <typename StorageType, typename R>
+struct Invoker<0, StorageType, R()> {
+  typedef R(RunType)(BindStateBase*);
+
+  typedef R(UnboundRunType)();
+
+  static R Run(BindStateBase* base) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void()>
+               ::MakeItSo(storage->runnable_);
+  }
+};
+
+// Arity 1 -> 1.
+template <typename StorageType, typename R,typename X1>
+struct Invoker<0, StorageType, R(X1)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X1>::ForwardType);
+
+  typedef R(UnboundRunType)(X1);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X1>::ForwardType x1) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename CallbackParamTraits<X1>::ForwardType x1)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1));
+  }
+};
+
+// Arity 1 -> 0.
+template <typename StorageType, typename R,typename X1>
+struct Invoker<1, StorageType, R(X1)> {
+  typedef R(RunType)(BindStateBase*);
+
+  typedef R(UnboundRunType)();
+
+  static R Run(BindStateBase* base) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1));
+  }
+};
+
+// Arity 2 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2>
+struct Invoker<0, StorageType, R(X1, X2)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X1>::ForwardType,
+      typename CallbackParamTraits<X2>::ForwardType);
+
+  typedef R(UnboundRunType)(X1, X2);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X1>::ForwardType x1,
+      typename CallbackParamTraits<X2>::ForwardType x2) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename CallbackParamTraits<X1>::ForwardType x1,
+               typename CallbackParamTraits<X2>::ForwardType x2)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2));
+  }
+};
+
+// Arity 2 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2>
+struct Invoker<1, StorageType, R(X1, X2)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X2>::ForwardType);
+
+  typedef R(UnboundRunType)(X2);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X2>::ForwardType x2) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X2>::ForwardType x2)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2));
+  }
+};
+
+// Arity 2 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2>
+struct Invoker<2, StorageType, R(X1, X2)> {
+  typedef R(RunType)(BindStateBase*);
+
+  typedef R(UnboundRunType)();
+
+  static R Run(BindStateBase* base) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2));
+  }
+};
+
+// Arity 3 -> 3.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3>
+struct Invoker<0, StorageType, R(X1, X2, X3)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X1>::ForwardType,
+      typename CallbackParamTraits<X2>::ForwardType,
+      typename CallbackParamTraits<X3>::ForwardType);
+
+  typedef R(UnboundRunType)(X1, X2, X3);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X1>::ForwardType x1,
+      typename CallbackParamTraits<X2>::ForwardType x2,
+      typename CallbackParamTraits<X3>::ForwardType x3) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename CallbackParamTraits<X1>::ForwardType x1,
+               typename CallbackParamTraits<X2>::ForwardType x2,
+               typename CallbackParamTraits<X3>::ForwardType x3)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3));
+  }
+};
+
+// Arity 3 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3>
+struct Invoker<1, StorageType, R(X1, X2, X3)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X2>::ForwardType,
+      typename CallbackParamTraits<X3>::ForwardType);
+
+  typedef R(UnboundRunType)(X2, X3);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X2>::ForwardType x2,
+      typename CallbackParamTraits<X3>::ForwardType x3) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X2>::ForwardType x2,
+               typename CallbackParamTraits<X3>::ForwardType x3)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3));
+  }
+};
+
+// Arity 3 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3>
+struct Invoker<2, StorageType, R(X1, X2, X3)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X3>::ForwardType);
+
+  typedef R(UnboundRunType)(X3);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X3>::ForwardType x3) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X3>::ForwardType x3)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3));
+  }
+};
+
+// Arity 3 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3>
+struct Invoker<3, StorageType, R(X1, X2, X3)> {
+  typedef R(RunType)(BindStateBase*);
+
+  typedef R(UnboundRunType)();
+
+  static R Run(BindStateBase* base) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3));
+  }
+};
+
+// Arity 4 -> 4.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4>
+struct Invoker<0, StorageType, R(X1, X2, X3, X4)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X1>::ForwardType,
+      typename CallbackParamTraits<X2>::ForwardType,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType);
+
+  typedef R(UnboundRunType)(X1, X2, X3, X4);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X1>::ForwardType x1,
+      typename CallbackParamTraits<X2>::ForwardType x2,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename CallbackParamTraits<X1>::ForwardType x1,
+               typename CallbackParamTraits<X2>::ForwardType x2,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4));
+  }
+};
+
+// Arity 4 -> 3.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4>
+struct Invoker<1, StorageType, R(X1, X2, X3, X4)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X2>::ForwardType,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType);
+
+  typedef R(UnboundRunType)(X2, X3, X4);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X2>::ForwardType x2,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X2>::ForwardType x2,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4));
+  }
+};
+
+// Arity 4 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4>
+struct Invoker<2, StorageType, R(X1, X2, X3, X4)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType);
+
+  typedef R(UnboundRunType)(X3, X4);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4));
+  }
+};
+
+// Arity 4 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4>
+struct Invoker<3, StorageType, R(X1, X2, X3, X4)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X4>::ForwardType);
+
+  typedef R(UnboundRunType)(X4);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X4>::ForwardType x4) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X4>::ForwardType x4)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4));
+  }
+};
+
+// Arity 4 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4>
+struct Invoker<4, StorageType, R(X1, X2, X3, X4)> {
+  typedef R(RunType)(BindStateBase*);
+
+  typedef R(UnboundRunType)();
+
+  static R Run(BindStateBase* base) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+    typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    typename Bound4UnwrapTraits::ForwardType x4 =
+        Bound4UnwrapTraits::Unwrap(storage->p4_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename Bound4UnwrapTraits::ForwardType)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4));
+  }
+};
+
+// Arity 5 -> 5.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5>
+struct Invoker<0, StorageType, R(X1, X2, X3, X4, X5)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X1>::ForwardType,
+      typename CallbackParamTraits<X2>::ForwardType,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType);
+
+  typedef R(UnboundRunType)(X1, X2, X3, X4, X5);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X1>::ForwardType x1,
+      typename CallbackParamTraits<X2>::ForwardType x2,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename CallbackParamTraits<X1>::ForwardType x1,
+               typename CallbackParamTraits<X2>::ForwardType x2,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5));
+  }
+};
+
+// Arity 5 -> 4.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5>
+struct Invoker<1, StorageType, R(X1, X2, X3, X4, X5)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X2>::ForwardType,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType);
+
+  typedef R(UnboundRunType)(X2, X3, X4, X5);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X2>::ForwardType x2,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X2>::ForwardType x2,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5));
+  }
+};
+
+// Arity 5 -> 3.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5>
+struct Invoker<2, StorageType, R(X1, X2, X3, X4, X5)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType);
+
+  typedef R(UnboundRunType)(X3, X4, X5);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5));
+  }
+};
+
+// Arity 5 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5>
+struct Invoker<3, StorageType, R(X1, X2, X3, X4, X5)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType);
+
+  typedef R(UnboundRunType)(X4, X5);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5));
+  }
+};
+
+// Arity 5 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5>
+struct Invoker<4, StorageType, R(X1, X2, X3, X4, X5)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X5>::ForwardType);
+
+  typedef R(UnboundRunType)(X5);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X5>::ForwardType x5) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+    typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    typename Bound4UnwrapTraits::ForwardType x4 =
+        Bound4UnwrapTraits::Unwrap(storage->p4_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename Bound4UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X5>::ForwardType x5)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5));
+  }
+};
+
+// Arity 5 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5>
+struct Invoker<5, StorageType, R(X1, X2, X3, X4, X5)> {
+  typedef R(RunType)(BindStateBase*);
+
+  typedef R(UnboundRunType)();
+
+  static R Run(BindStateBase* base) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+    typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
+    typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    typename Bound4UnwrapTraits::ForwardType x4 =
+        Bound4UnwrapTraits::Unwrap(storage->p4_);
+    typename Bound5UnwrapTraits::ForwardType x5 =
+        Bound5UnwrapTraits::Unwrap(storage->p5_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename Bound4UnwrapTraits::ForwardType,
+               typename Bound5UnwrapTraits::ForwardType)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5));
+  }
+};
+
+// Arity 6 -> 6.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6>
+struct Invoker<0, StorageType, R(X1, X2, X3, X4, X5, X6)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X1>::ForwardType,
+      typename CallbackParamTraits<X2>::ForwardType,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType,
+      typename CallbackParamTraits<X6>::ForwardType);
+
+  typedef R(UnboundRunType)(X1, X2, X3, X4, X5, X6);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X1>::ForwardType x1,
+      typename CallbackParamTraits<X2>::ForwardType x2,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5,
+      typename CallbackParamTraits<X6>::ForwardType x6) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename CallbackParamTraits<X1>::ForwardType x1,
+               typename CallbackParamTraits<X2>::ForwardType x2,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5,
+               typename CallbackParamTraits<X6>::ForwardType x6)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6));
+  }
+};
+
+// Arity 6 -> 5.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6>
+struct Invoker<1, StorageType, R(X1, X2, X3, X4, X5, X6)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X2>::ForwardType,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType,
+      typename CallbackParamTraits<X6>::ForwardType);
+
+  typedef R(UnboundRunType)(X2, X3, X4, X5, X6);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X2>::ForwardType x2,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5,
+      typename CallbackParamTraits<X6>::ForwardType x6) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X2>::ForwardType x2,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5,
+               typename CallbackParamTraits<X6>::ForwardType x6)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6));
+  }
+};
+
+// Arity 6 -> 4.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6>
+struct Invoker<2, StorageType, R(X1, X2, X3, X4, X5, X6)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType,
+      typename CallbackParamTraits<X6>::ForwardType);
+
+  typedef R(UnboundRunType)(X3, X4, X5, X6);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5,
+      typename CallbackParamTraits<X6>::ForwardType x6) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5,
+               typename CallbackParamTraits<X6>::ForwardType x6)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6));
+  }
+};
+
+// Arity 6 -> 3.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6>
+struct Invoker<3, StorageType, R(X1, X2, X3, X4, X5, X6)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType,
+      typename CallbackParamTraits<X6>::ForwardType);
+
+  typedef R(UnboundRunType)(X4, X5, X6);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5,
+      typename CallbackParamTraits<X6>::ForwardType x6) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5,
+               typename CallbackParamTraits<X6>::ForwardType x6)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6));
+  }
+};
+
+// Arity 6 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6>
+struct Invoker<4, StorageType, R(X1, X2, X3, X4, X5, X6)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X5>::ForwardType,
+      typename CallbackParamTraits<X6>::ForwardType);
+
+  typedef R(UnboundRunType)(X5, X6);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X5>::ForwardType x5,
+      typename CallbackParamTraits<X6>::ForwardType x6) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+    typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    typename Bound4UnwrapTraits::ForwardType x4 =
+        Bound4UnwrapTraits::Unwrap(storage->p4_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename Bound4UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X5>::ForwardType x5,
+               typename CallbackParamTraits<X6>::ForwardType x6)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6));
+  }
+};
+
+// Arity 6 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6>
+struct Invoker<5, StorageType, R(X1, X2, X3, X4, X5, X6)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X6>::ForwardType);
+
+  typedef R(UnboundRunType)(X6);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X6>::ForwardType x6) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+    typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
+    typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    typename Bound4UnwrapTraits::ForwardType x4 =
+        Bound4UnwrapTraits::Unwrap(storage->p4_);
+    typename Bound5UnwrapTraits::ForwardType x5 =
+        Bound5UnwrapTraits::Unwrap(storage->p5_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename Bound4UnwrapTraits::ForwardType,
+               typename Bound5UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X6>::ForwardType x6)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6));
+  }
+};
+
+// Arity 6 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6>
+struct Invoker<6, StorageType, R(X1, X2, X3, X4, X5, X6)> {
+  typedef R(RunType)(BindStateBase*);
+
+  typedef R(UnboundRunType)();
+
+  static R Run(BindStateBase* base) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+    typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
+    typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
+    typedef typename StorageType::Bound6UnwrapTraits Bound6UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    typename Bound4UnwrapTraits::ForwardType x4 =
+        Bound4UnwrapTraits::Unwrap(storage->p4_);
+    typename Bound5UnwrapTraits::ForwardType x5 =
+        Bound5UnwrapTraits::Unwrap(storage->p5_);
+    typename Bound6UnwrapTraits::ForwardType x6 =
+        Bound6UnwrapTraits::Unwrap(storage->p6_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename Bound4UnwrapTraits::ForwardType,
+               typename Bound5UnwrapTraits::ForwardType,
+               typename Bound6UnwrapTraits::ForwardType)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6));
+  }
+};
+
+// Arity 7 -> 7.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6, typename X7>
+struct Invoker<0, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X1>::ForwardType,
+      typename CallbackParamTraits<X2>::ForwardType,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType,
+      typename CallbackParamTraits<X6>::ForwardType,
+      typename CallbackParamTraits<X7>::ForwardType);
+
+  typedef R(UnboundRunType)(X1, X2, X3, X4, X5, X6, X7);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X1>::ForwardType x1,
+      typename CallbackParamTraits<X2>::ForwardType x2,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5,
+      typename CallbackParamTraits<X6>::ForwardType x6,
+      typename CallbackParamTraits<X7>::ForwardType x7) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename CallbackParamTraits<X1>::ForwardType x1,
+               typename CallbackParamTraits<X2>::ForwardType x2,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5,
+               typename CallbackParamTraits<X6>::ForwardType x6,
+               typename CallbackParamTraits<X7>::ForwardType x7)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6), CallbackForward(x7));
+  }
+};
+
+// Arity 7 -> 6.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6, typename X7>
+struct Invoker<1, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X2>::ForwardType,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType,
+      typename CallbackParamTraits<X6>::ForwardType,
+      typename CallbackParamTraits<X7>::ForwardType);
+
+  typedef R(UnboundRunType)(X2, X3, X4, X5, X6, X7);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X2>::ForwardType x2,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5,
+      typename CallbackParamTraits<X6>::ForwardType x6,
+      typename CallbackParamTraits<X7>::ForwardType x7) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X2>::ForwardType x2,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5,
+               typename CallbackParamTraits<X6>::ForwardType x6,
+               typename CallbackParamTraits<X7>::ForwardType x7)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6), CallbackForward(x7));
+  }
+};
+
+// Arity 7 -> 5.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6, typename X7>
+struct Invoker<2, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X3>::ForwardType,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType,
+      typename CallbackParamTraits<X6>::ForwardType,
+      typename CallbackParamTraits<X7>::ForwardType);
+
+  typedef R(UnboundRunType)(X3, X4, X5, X6, X7);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X3>::ForwardType x3,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5,
+      typename CallbackParamTraits<X6>::ForwardType x6,
+      typename CallbackParamTraits<X7>::ForwardType x7) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X3>::ForwardType x3,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5,
+               typename CallbackParamTraits<X6>::ForwardType x6,
+               typename CallbackParamTraits<X7>::ForwardType x7)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6), CallbackForward(x7));
+  }
+};
+
+// Arity 7 -> 4.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6, typename X7>
+struct Invoker<3, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X4>::ForwardType,
+      typename CallbackParamTraits<X5>::ForwardType,
+      typename CallbackParamTraits<X6>::ForwardType,
+      typename CallbackParamTraits<X7>::ForwardType);
+
+  typedef R(UnboundRunType)(X4, X5, X6, X7);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X4>::ForwardType x4,
+      typename CallbackParamTraits<X5>::ForwardType x5,
+      typename CallbackParamTraits<X6>::ForwardType x6,
+      typename CallbackParamTraits<X7>::ForwardType x7) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X4>::ForwardType x4,
+               typename CallbackParamTraits<X5>::ForwardType x5,
+               typename CallbackParamTraits<X6>::ForwardType x6,
+               typename CallbackParamTraits<X7>::ForwardType x7)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6), CallbackForward(x7));
+  }
+};
+
+// Arity 7 -> 3.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6, typename X7>
+struct Invoker<4, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X5>::ForwardType,
+      typename CallbackParamTraits<X6>::ForwardType,
+      typename CallbackParamTraits<X7>::ForwardType);
+
+  typedef R(UnboundRunType)(X5, X6, X7);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X5>::ForwardType x5,
+      typename CallbackParamTraits<X6>::ForwardType x6,
+      typename CallbackParamTraits<X7>::ForwardType x7) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+    typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    typename Bound4UnwrapTraits::ForwardType x4 =
+        Bound4UnwrapTraits::Unwrap(storage->p4_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename Bound4UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X5>::ForwardType x5,
+               typename CallbackParamTraits<X6>::ForwardType x6,
+               typename CallbackParamTraits<X7>::ForwardType x7)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6), CallbackForward(x7));
+  }
+};
+
+// Arity 7 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6, typename X7>
+struct Invoker<5, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X6>::ForwardType,
+      typename CallbackParamTraits<X7>::ForwardType);
+
+  typedef R(UnboundRunType)(X6, X7);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X6>::ForwardType x6,
+      typename CallbackParamTraits<X7>::ForwardType x7) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+    typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
+    typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    typename Bound4UnwrapTraits::ForwardType x4 =
+        Bound4UnwrapTraits::Unwrap(storage->p4_);
+    typename Bound5UnwrapTraits::ForwardType x5 =
+        Bound5UnwrapTraits::Unwrap(storage->p5_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename Bound4UnwrapTraits::ForwardType,
+               typename Bound5UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X6>::ForwardType x6,
+               typename CallbackParamTraits<X7>::ForwardType x7)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6), CallbackForward(x7));
+  }
+};
+
+// Arity 7 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6, typename X7>
+struct Invoker<6, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
+  typedef R(RunType)(BindStateBase*,
+      typename CallbackParamTraits<X7>::ForwardType);
+
+  typedef R(UnboundRunType)(X7);
+
+  static R Run(BindStateBase* base,
+      typename CallbackParamTraits<X7>::ForwardType x7) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+    typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
+    typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
+    typedef typename StorageType::Bound6UnwrapTraits Bound6UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    typename Bound4UnwrapTraits::ForwardType x4 =
+        Bound4UnwrapTraits::Unwrap(storage->p4_);
+    typename Bound5UnwrapTraits::ForwardType x5 =
+        Bound5UnwrapTraits::Unwrap(storage->p5_);
+    typename Bound6UnwrapTraits::ForwardType x6 =
+        Bound6UnwrapTraits::Unwrap(storage->p6_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename Bound4UnwrapTraits::ForwardType,
+               typename Bound5UnwrapTraits::ForwardType,
+               typename Bound6UnwrapTraits::ForwardType,
+               typename CallbackParamTraits<X7>::ForwardType x7)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6), CallbackForward(x7));
+  }
+};
+
+// Arity 7 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2,
+    typename X3, typename X4, typename X5, typename X6, typename X7>
+struct Invoker<7, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
+  typedef R(RunType)(BindStateBase*);
+
+  typedef R(UnboundRunType)();
+
+  static R Run(BindStateBase* base) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
+    typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
+    typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
+    typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
+    typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
+    typedef typename StorageType::Bound6UnwrapTraits Bound6UnwrapTraits;
+    typedef typename StorageType::Bound7UnwrapTraits Bound7UnwrapTraits;
+
+    typename Bound1UnwrapTraits::ForwardType x1 =
+        Bound1UnwrapTraits::Unwrap(storage->p1_);
+    typename Bound2UnwrapTraits::ForwardType x2 =
+        Bound2UnwrapTraits::Unwrap(storage->p2_);
+    typename Bound3UnwrapTraits::ForwardType x3 =
+        Bound3UnwrapTraits::Unwrap(storage->p3_);
+    typename Bound4UnwrapTraits::ForwardType x4 =
+        Bound4UnwrapTraits::Unwrap(storage->p4_);
+    typename Bound5UnwrapTraits::ForwardType x5 =
+        Bound5UnwrapTraits::Unwrap(storage->p5_);
+    typename Bound6UnwrapTraits::ForwardType x6 =
+        Bound6UnwrapTraits::Unwrap(storage->p6_);
+    typename Bound7UnwrapTraits::ForwardType x7 =
+        Bound7UnwrapTraits::Unwrap(storage->p7_);
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(typename Bound1UnwrapTraits::ForwardType,
+               typename Bound2UnwrapTraits::ForwardType,
+               typename Bound3UnwrapTraits::ForwardType,
+               typename Bound4UnwrapTraits::ForwardType,
+               typename Bound5UnwrapTraits::ForwardType,
+               typename Bound6UnwrapTraits::ForwardType,
+               typename Bound7UnwrapTraits::ForwardType)>
+               ::MakeItSo(storage->runnable_, CallbackForward(x1),
+                   CallbackForward(x2), CallbackForward(x3),
+                   CallbackForward(x4), CallbackForward(x5),
+                   CallbackForward(x6), CallbackForward(x7));
+  }
+};
+
+
+// BindState<>
+//
+// This stores all the state passed into Bind() and is also where most
+// of the template resolution magic occurs.
+//
+// Runnable is the functor we are binding arguments to.
+// RunType is type of the Run() function that the Invoker<> should use.
+// Normally, this is the same as the RunType of the Runnable, but it can
+// be different if an adapter like IgnoreResult() has been used.
+//
+// BoundArgsType contains the storage type for all the bound arguments by
+// (ab)using a function type.
+template <typename Runnable, typename RunType, typename BoundArgsType>
+struct BindState;
+
+template <typename Runnable, typename RunType>
+struct BindState<Runnable, RunType, void()> : public BindStateBase {
+  typedef Runnable RunnableType;
+  typedef false_type IsWeakCall;
+  typedef Invoker<0, BindState, RunType> InvokerType;
+  typedef typename InvokerType::UnboundRunType UnboundRunType;
+  explicit BindState(const Runnable& runnable)
+      : runnable_(runnable) {
+  }
+
+  virtual ~BindState() {  }
+
+  RunnableType runnable_;
+};
+
+template <typename Runnable, typename RunType, typename P1>
+struct BindState<Runnable, RunType, void(P1)> : public BindStateBase {
+  typedef Runnable RunnableType;
+  typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
+  typedef Invoker<1, BindState, RunType> InvokerType;
+  typedef typename InvokerType::UnboundRunType UnboundRunType;
+
+  // Convenience typedefs for bound argument types.
+  typedef UnwrapTraits<P1> Bound1UnwrapTraits;
+
+  BindState(const Runnable& runnable, const P1& p1)
+      : runnable_(runnable),
+        p1_(p1) {
+    MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
+  }
+
+  virtual ~BindState() {    MaybeRefcount<HasIsMethodTag<Runnable>::value,
+      P1>::Release(p1_);  }
+
+  RunnableType runnable_;
+  P1 p1_;
+};
+
+template <typename Runnable, typename RunType, typename P1, typename P2>
+struct BindState<Runnable, RunType, void(P1, P2)> : public BindStateBase {
+  typedef Runnable RunnableType;
+  typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
+  typedef Invoker<2, BindState, RunType> InvokerType;
+  typedef typename InvokerType::UnboundRunType UnboundRunType;
+
+  // Convenience typedefs for bound argument types.
+  typedef UnwrapTraits<P1> Bound1UnwrapTraits;
+  typedef UnwrapTraits<P2> Bound2UnwrapTraits;
+
+  BindState(const Runnable& runnable, const P1& p1, const P2& p2)
+      : runnable_(runnable),
+        p1_(p1),
+        p2_(p2) {
+    MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
+  }
+
+  virtual ~BindState() {    MaybeRefcount<HasIsMethodTag<Runnable>::value,
+      P1>::Release(p1_);  }
+
+  RunnableType runnable_;
+  P1 p1_;
+  P2 p2_;
+};
+
+template <typename Runnable, typename RunType, typename P1, typename P2,
+    typename P3>
+struct BindState<Runnable, RunType, void(P1, P2, P3)> : public BindStateBase {
+  typedef Runnable RunnableType;
+  typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
+  typedef Invoker<3, BindState, RunType> InvokerType;
+  typedef typename InvokerType::UnboundRunType UnboundRunType;
+
+  // Convenience typedefs for bound argument types.
+  typedef UnwrapTraits<P1> Bound1UnwrapTraits;
+  typedef UnwrapTraits<P2> Bound2UnwrapTraits;
+  typedef UnwrapTraits<P3> Bound3UnwrapTraits;
+
+  BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3)
+      : runnable_(runnable),
+        p1_(p1),
+        p2_(p2),
+        p3_(p3) {
+    MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
+  }
+
+  virtual ~BindState() {    MaybeRefcount<HasIsMethodTag<Runnable>::value,
+      P1>::Release(p1_);  }
+
+  RunnableType runnable_;
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+};
+
+template <typename Runnable, typename RunType, typename P1, typename P2,
+    typename P3, typename P4>
+struct BindState<Runnable, RunType, void(P1, P2, P3,
+    P4)> : public BindStateBase {
+  typedef Runnable RunnableType;
+  typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
+  typedef Invoker<4, BindState, RunType> InvokerType;
+  typedef typename InvokerType::UnboundRunType UnboundRunType;
+
+  // Convenience typedefs for bound argument types.
+  typedef UnwrapTraits<P1> Bound1UnwrapTraits;
+  typedef UnwrapTraits<P2> Bound2UnwrapTraits;
+  typedef UnwrapTraits<P3> Bound3UnwrapTraits;
+  typedef UnwrapTraits<P4> Bound4UnwrapTraits;
+
+  BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3,
+      const P4& p4)
+      : runnable_(runnable),
+        p1_(p1),
+        p2_(p2),
+        p3_(p3),
+        p4_(p4) {
+    MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
+  }
+
+  virtual ~BindState() {    MaybeRefcount<HasIsMethodTag<Runnable>::value,
+      P1>::Release(p1_);  }
+
+  RunnableType runnable_;
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+};
+
+template <typename Runnable, typename RunType, typename P1, typename P2,
+    typename P3, typename P4, typename P5>
+struct BindState<Runnable, RunType, void(P1, P2, P3, P4,
+    P5)> : public BindStateBase {
+  typedef Runnable RunnableType;
+  typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
+  typedef Invoker<5, BindState, RunType> InvokerType;
+  typedef typename InvokerType::UnboundRunType UnboundRunType;
+
+  // Convenience typedefs for bound argument types.
+  typedef UnwrapTraits<P1> Bound1UnwrapTraits;
+  typedef UnwrapTraits<P2> Bound2UnwrapTraits;
+  typedef UnwrapTraits<P3> Bound3UnwrapTraits;
+  typedef UnwrapTraits<P4> Bound4UnwrapTraits;
+  typedef UnwrapTraits<P5> Bound5UnwrapTraits;
+
+  BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3,
+      const P4& p4, const P5& p5)
+      : runnable_(runnable),
+        p1_(p1),
+        p2_(p2),
+        p3_(p3),
+        p4_(p4),
+        p5_(p5) {
+    MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
+  }
+
+  virtual ~BindState() {    MaybeRefcount<HasIsMethodTag<Runnable>::value,
+      P1>::Release(p1_);  }
+
+  RunnableType runnable_;
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+  P5 p5_;
+};
+
+template <typename Runnable, typename RunType, typename P1, typename P2,
+    typename P3, typename P4, typename P5, typename P6>
+struct BindState<Runnable, RunType, void(P1, P2, P3, P4, P5,
+    P6)> : public BindStateBase {
+  typedef Runnable RunnableType;
+  typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
+  typedef Invoker<6, BindState, RunType> InvokerType;
+  typedef typename InvokerType::UnboundRunType UnboundRunType;
+
+  // Convenience typedefs for bound argument types.
+  typedef UnwrapTraits<P1> Bound1UnwrapTraits;
+  typedef UnwrapTraits<P2> Bound2UnwrapTraits;
+  typedef UnwrapTraits<P3> Bound3UnwrapTraits;
+  typedef UnwrapTraits<P4> Bound4UnwrapTraits;
+  typedef UnwrapTraits<P5> Bound5UnwrapTraits;
+  typedef UnwrapTraits<P6> Bound6UnwrapTraits;
+
+  BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3,
+      const P4& p4, const P5& p5, const P6& p6)
+      : runnable_(runnable),
+        p1_(p1),
+        p2_(p2),
+        p3_(p3),
+        p4_(p4),
+        p5_(p5),
+        p6_(p6) {
+    MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
+  }
+
+  virtual ~BindState() {    MaybeRefcount<HasIsMethodTag<Runnable>::value,
+      P1>::Release(p1_);  }
+
+  RunnableType runnable_;
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+  P5 p5_;
+  P6 p6_;
+};
+
+template <typename Runnable, typename RunType, typename P1, typename P2,
+    typename P3, typename P4, typename P5, typename P6, typename P7>
+struct BindState<Runnable, RunType, void(P1, P2, P3, P4, P5, P6,
+    P7)> : public BindStateBase {
+  typedef Runnable RunnableType;
+  typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
+  typedef Invoker<7, BindState, RunType> InvokerType;
+  typedef typename InvokerType::UnboundRunType UnboundRunType;
+
+  // Convenience typedefs for bound argument types.
+  typedef UnwrapTraits<P1> Bound1UnwrapTraits;
+  typedef UnwrapTraits<P2> Bound2UnwrapTraits;
+  typedef UnwrapTraits<P3> Bound3UnwrapTraits;
+  typedef UnwrapTraits<P4> Bound4UnwrapTraits;
+  typedef UnwrapTraits<P5> Bound5UnwrapTraits;
+  typedef UnwrapTraits<P6> Bound6UnwrapTraits;
+  typedef UnwrapTraits<P7> Bound7UnwrapTraits;
+
+  BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3,
+      const P4& p4, const P5& p5, const P6& p6, const P7& p7)
+      : runnable_(runnable),
+        p1_(p1),
+        p2_(p2),
+        p3_(p3),
+        p4_(p4),
+        p5_(p5),
+        p6_(p6),
+        p7_(p7) {
+    MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
+  }
+
+  virtual ~BindState() {    MaybeRefcount<HasIsMethodTag<Runnable>::value,
+      P1>::Release(p1_);  }
+
+  RunnableType runnable_;
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+  P5 p5_;
+  P6 p6_;
+  P7 p7_;
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_BIND_INTERNAL_H_
diff --git a/base/bind_internal.h.pump b/base/bind_internal.h.pump
new file mode 100644
index 0000000..0712027
--- /dev/null
+++ b/base/bind_internal.h.pump
@@ -0,0 +1,496 @@
+$$ This is a pump file for generating file templates.  Pump is a python
+$$ script that is part of the Google Test suite of utilities.  Description
+$$ can be found here:
+$$
+$$ http://code.google.com/p/googletest/wiki/PumpManual
+$$
+
+$$ See comment for MAX_ARITY in base/bind.h.pump.
+$var MAX_ARITY = 7
+$range ARITY 0..MAX_ARITY
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIND_INTERNAL_H_
+#define BASE_BIND_INTERNAL_H_
+
+#include "base/bind_helpers.h"
+#include "base/callback_internal.h"
+#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
+#include "base/memory/weak_ptr.h"
+#include "base/template_util.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/bind_internal_win.h"
+#endif
+
+namespace base {
+namespace internal {
+
+// See base/callback.h for user documentation.
+//
+//
+// CONCEPTS:
+//  Runnable -- A type (really a type class) that has a single Run() method
+//              and a RunType typedef that corresponds to the type of Run().
+//              A Runnable can declare that it should treated like a method
+//              call by including a typedef named IsMethod.  The value of
+//              this typedef is NOT inspected, only the existence.  When a
+//              Runnable declares itself a method, Bind() will enforce special
+//              refcounting + WeakPtr handling semantics for the first
+//              parameter which is expected to be an object.
+//  Functor -- A copyable type representing something that should be called.
+//             All function pointers, Callback<>, and Runnables are functors
+//             even if the invocation syntax differs.
+//  RunType -- A function type (as opposed to function _pointer_ type) for
+//             a Run() function.  Usually just a convenience typedef.
+//  (Bound)ArgsType -- A function type that is being (ab)used to store the
+//                     types of set of arguments.  The "return" type is always
+//                     void here.  We use this hack so that we do not need
+//                     a new type name for each arity of type. (eg.,
+//                     BindState1, BindState2).  This makes forward
+//                     declarations and friending much much easier.
+//
+// Types:
+//  RunnableAdapter<> -- Wraps the various "function" pointer types into an
+//                       object that adheres to the Runnable interface.
+//                       There are |3*ARITY| RunnableAdapter types.
+//  FunctionTraits<> -- Type traits that unwrap a function signature into a
+//                      a set of easier to use typedefs.  Used mainly for
+//                      compile time asserts.
+//                      There are |ARITY| FunctionTraits types.
+//  ForceVoidReturn<> -- Helper class for translating function signatures to
+//                       equivalent forms with a "void" return type.
+//                    There are |ARITY| ForceVoidReturn types.
+//  FunctorTraits<> -- Type traits used determine the correct RunType and
+//                     RunnableType for a Functor.  This is where function
+//                     signature adapters are applied.
+//                    There are |ARITY| ForceVoidReturn types.
+//  MakeRunnable<> -- Takes a Functor and returns an object in the Runnable
+//                    type class that represents the underlying Functor.
+//                    There are |O(1)| MakeRunnable types.
+//  InvokeHelper<> -- Take a Runnable + arguments and actully invokes it.
+//                    Handle the differing syntaxes needed for WeakPtr<> support,
+//                    and for ignoring return values.  This is separate from
+//                    Invoker to avoid creating multiple version of Invoker<>
+//                    which grows at O(n^2) with the arity.
+//                    There are |k*ARITY| InvokeHelper types.
+//  Invoker<> -- Unwraps the curried parameters and executes the Runnable.
+//               There are |(ARITY^2 + ARITY)/2| Invoketypes.
+//  BindState<> -- Stores the curried parameters, and is the main entry point
+//                 into the Bind() system, doing most of the type resolution.
+//                 There are ARITY BindState types.
+
+// RunnableAdapter<>
+//
+// The RunnableAdapter<> templates provide a uniform interface for invoking
+// a function pointer, method pointer, or const method pointer. The adapter
+// exposes a Run() method with an appropriate signature. Using this wrapper
+// allows for writing code that supports all three pointer types without
+// undue repetition.  Without it, a lot of code would need to be repeated 3
+// times.
+//
+// For method pointers and const method pointers the first argument to Run()
+// is considered to be the received of the method.  This is similar to STL's
+// mem_fun().
+//
+// This class also exposes a RunType typedef that is the function type of the
+// Run() function.
+//
+// If and only if the wrapper contains a method or const method pointer, an
+// IsMethod typedef is exposed.  The existence of this typedef (NOT the value)
+// marks that the wrapper should be considered a method wrapper.
+
+template <typename Functor>
+class RunnableAdapter;
+
+$for ARITY [[
+$range ARG 1..ARITY
+
+// Function: Arity $(ARITY).
+template <typename R[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
+class RunnableAdapter<R(*)($for ARG , [[A$(ARG)]])> {
+ public:
+  typedef R (RunType)($for ARG , [[A$(ARG)]]);
+
+  explicit RunnableAdapter(R(*function)($for ARG , [[A$(ARG)]]))
+      : function_(function) {
+  }
+
+  R Run($for ARG , [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
+    return function_($for ARG , [[CallbackForward(a$(ARG))]]);
+  }
+
+ private:
+  R (*function_)($for ARG , [[A$(ARG)]]);
+};
+
+// Method: Arity $(ARITY).
+template <typename R, typename T[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
+class RunnableAdapter<R(T::*)($for ARG , [[A$(ARG)]])> {
+ public:
+  typedef R (RunType)(T*[[]]
+$if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)($for ARG , [[A$(ARG)]]))
+      : method_(method) {
+  }
+
+  R Run(T* object[[]]
+$if ARITY > 0[[, ]]  $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
+    return (object->*method_)($for ARG , [[CallbackForward(a$(ARG))]]);
+  }
+
+ private:
+  R (T::*method_)($for ARG , [[A$(ARG)]]);
+};
+
+// Const Method: Arity $(ARITY).
+template <typename R, typename T[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
+class RunnableAdapter<R(T::*)($for ARG , [[A$(ARG)]]) const> {
+ public:
+  typedef R (RunType)(const T*[[]]
+$if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)($for ARG , [[A$(ARG)]]) const)
+      : method_(method) {
+  }
+
+  R Run(const T* object[[]]
+$if ARITY > 0[[, ]]  $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
+    return (object->*method_)($for ARG , [[CallbackForward(a$(ARG))]]);
+  }
+
+ private:
+  R (T::*method_)($for ARG , [[A$(ARG)]]) const;
+};
+
+]]  $$ for ARITY
+
+
+// FunctionTraits<>
+//
+// Breaks a function signature apart into typedefs for easier introspection.
+template <typename Sig>
+struct FunctionTraits;
+
+$for ARITY [[
+$range ARG 1..ARITY
+
+template <typename R[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
+struct FunctionTraits<R($for ARG , [[A$(ARG)]])> {
+  typedef R ReturnType;
+$for ARG [[
+
+  typedef A$(ARG) A$(ARG)Type;
+]]
+
+};
+
+]]
+
+
+// ForceVoidReturn<>
+//
+// Set of templates that support forcing the function return type to void.
+template <typename Sig>
+struct ForceVoidReturn;
+
+$for ARITY [[
+$range ARG 1..ARITY
+
+template <typename R[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
+struct ForceVoidReturn<R($for ARG , [[A$(ARG)]])> {
+  typedef void(RunType)($for ARG , [[A$(ARG)]]);
+};
+
+]]  $$ for ARITY
+
+
+// FunctorTraits<>
+//
+// See description at top of file.
+template <typename T>
+struct FunctorTraits {
+  typedef RunnableAdapter<T> RunnableType;
+  typedef typename RunnableType::RunType RunType;
+};
+
+template <typename T>
+struct FunctorTraits<IgnoreResultHelper<T> > {
+  typedef typename FunctorTraits<T>::RunnableType RunnableType;
+  typedef typename ForceVoidReturn<
+      typename RunnableType::RunType>::RunType RunType;
+};
+
+template <typename T>
+struct FunctorTraits<Callback<T> > {
+  typedef Callback<T> RunnableType;
+  typedef typename Callback<T>::RunType RunType;
+};
+
+
+// MakeRunnable<>
+//
+// Converts a passed in functor to a RunnableType using type inference.
+
+template <typename T>
+typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) {
+  return RunnableAdapter<T>(t);
+}
+
+template <typename T>
+typename FunctorTraits<T>::RunnableType
+MakeRunnable(const IgnoreResultHelper<T>& t) {
+  return MakeRunnable(t.functor_);
+}
+
+template <typename T>
+const typename FunctorTraits<Callback<T> >::RunnableType&
+MakeRunnable(const Callback<T>& t) {
+  return t;
+}
+
+
+// InvokeHelper<>
+//
+// There are 3 logical InvokeHelper<> specializations: normal, void-return,
+// WeakCalls.
+//
+// The normal type just calls the underlying runnable.
+//
+// We need a InvokeHelper to handle void return types in order to support
+// IgnoreResult().  Normally, if the Runnable's RunType had a void return,
+// the template system would just accept "return functor.Run()" ignoring
+// the fact that a void function is being used with return. This piece of
+// sugar breaks though when the Runnable's RunType is not void.  Thus, we
+// need a partial specialization to change the syntax to drop the "return"
+// from the invocation call.
+//
+// WeakCalls similarly need special syntax that is applied to the first
+// argument to check if they should no-op themselves.
+template <bool IsWeakCall, typename ReturnType, typename Runnable,
+          typename ArgsType>
+struct InvokeHelper;
+
+$for ARITY [[
+$range ARG 1..ARITY
+
+template <typename ReturnType, typename Runnable[[]]
+$if ARITY > 0 [[,]] $for ARG , [[typename A$(ARG)]]>
+struct InvokeHelper<false, ReturnType, Runnable,
+    void($for ARG , [[A$(ARG)]])>  {
+  static ReturnType MakeItSo(Runnable runnable[[]]
+$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) {
+    return runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]);
+  }
+};
+
+template <typename Runnable[[]]
+$if ARITY > 0 [[,]] $for ARG , [[typename A$(ARG)]]>
+struct InvokeHelper<false, void, Runnable,
+    void($for ARG , [[A$(ARG)]])>  {
+  static void MakeItSo(Runnable runnable[[]]
+$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) {
+    runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]);
+  }
+};
+
+$if ARITY > 0 [[
+
+template <typename Runnable[[]], $for ARG , [[typename A$(ARG)]]>
+struct InvokeHelper<true, void, Runnable,
+    void($for ARG , [[A$(ARG)]])>  {
+  static void MakeItSo(Runnable runnable[[]]
+$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) {
+    if (!a1.get()) {
+      return;
+    }
+
+    runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]);
+  }
+};
+
+]]
+
+]] $$ for ARITY
+
+#if !defined(_MSC_VER)
+
+template <typename ReturnType, typename Runnable, typename ArgsType>
+struct InvokeHelper<true, ReturnType, Runnable, ArgsType> {
+  // WeakCalls are only supported for functions with a void return type.
+  // Otherwise, the function result would be undefined if the the WeakPtr<>
+  // is invalidated.
+  COMPILE_ASSERT(is_void<ReturnType>::value,
+                 weak_ptrs_can_only_bind_to_methods_without_return_values);
+};
+
+#endif
+
+// Invoker<>
+//
+// See description at the top of the file.
+template <int NumBound, typename Storage, typename RunType>
+struct Invoker;
+
+$for ARITY [[
+
+$$ Number of bound arguments.
+$range BOUND 0..ARITY
+$for BOUND [[
+
+$var UNBOUND = ARITY - BOUND
+$range ARG 1..ARITY
+$range BOUND_ARG 1..BOUND
+$range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY
+
+// Arity $(ARITY) -> $(UNBOUND).
+template <typename StorageType, typename R[[]]
+$if ARITY > 0 [[,]][[]]
+$for ARG , [[typename X$(ARG)]]>
+struct Invoker<$(BOUND), StorageType, R($for ARG , [[X$(ARG)]])> {
+  typedef R(RunType)(BindStateBase*[[]]
+$if UNBOUND != 0 [[, ]]
+$for UNBOUND_ARG , [[typename CallbackParamTraits<X$(UNBOUND_ARG)>::ForwardType]]);
+
+  typedef R(UnboundRunType)($for UNBOUND_ARG , [[X$(UNBOUND_ARG)]]);
+
+  static R Run(BindStateBase* base[[]]
+$if UNBOUND != 0 [[, ]][[]]
+$for UNBOUND_ARG , [[
+typename CallbackParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG)
+]][[]]
+) {
+    StorageType* storage = static_cast<StorageType*>(base);
+
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+$for BOUND_ARG
+[[
+
+    typedef typename StorageType::Bound$(BOUND_ARG)UnwrapTraits Bound$(BOUND_ARG)UnwrapTraits;
+]]
+
+
+$for BOUND_ARG
+[[
+
+    typename Bound$(BOUND_ARG)UnwrapTraits::ForwardType x$(BOUND_ARG) =
+        Bound$(BOUND_ARG)UnwrapTraits::Unwrap(storage->p$(BOUND_ARG)_);
+]]
+
+    return InvokeHelper<StorageType::IsWeakCall::value, R,
+           typename StorageType::RunnableType,
+           void(
+$for BOUND_ARG , [[
+typename Bound$(BOUND_ARG)UnwrapTraits::ForwardType
+]]
+
+$if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]]
+
+$for UNBOUND_ARG , [[
+typename CallbackParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG)
+]]
+)>
+               ::MakeItSo(storage->runnable_
+$if ARITY > 0[[, ]] $for ARG , [[CallbackForward(x$(ARG))]]);
+  }
+};
+
+]] $$ for BOUND
+]] $$ for ARITY
+
+
+// BindState<>
+//
+// This stores all the state passed into Bind() and is also where most
+// of the template resolution magic occurs.
+//
+// Runnable is the functor we are binding arguments to.
+// RunType is type of the Run() function that the Invoker<> should use.
+// Normally, this is the same as the RunType of the Runnable, but it can
+// be different if an adapter like IgnoreResult() has been used.
+//
+// BoundArgsType contains the storage type for all the bound arguments by
+// (ab)using a function type.
+template <typename Runnable, typename RunType, typename BoundArgsType>
+struct BindState;
+
+$for ARITY [[
+$range ARG 1..ARITY
+
+template <typename Runnable, typename RunType[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename P$(ARG)]]>
+struct BindState<Runnable, RunType, void($for ARG , [[P$(ARG)]])> : public BindStateBase {
+  typedef Runnable RunnableType;
+
+$if ARITY > 0 [[
+  typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
+]] $else [[
+  typedef false_type IsWeakCall;
+]]
+
+  typedef Invoker<$(ARITY), BindState, RunType> InvokerType;
+  typedef typename InvokerType::UnboundRunType UnboundRunType;
+
+$if ARITY > 0 [[
+
+  // Convenience typedefs for bound argument types.
+
+$for ARG [[
+  typedef UnwrapTraits<P$(ARG)> Bound$(ARG)UnwrapTraits;
+
+]]  $$ for ARG
+
+
+]]  $$ if ARITY > 0
+
+$$ The extra [[ ]] is needed to massage spacing. Silly pump.py.
+[[  ]]$if ARITY == 0 [[explicit ]]BindState(const Runnable& runnable
+$if ARITY > 0 [[, ]] $for ARG , [[const P$(ARG)& p$(ARG)]])
+      : runnable_(runnable)[[]]
+$if ARITY == 0 [[
+ {
+
+]] $else [[
+, $for ARG , [[
+
+        p$(ARG)_(p$(ARG))
+]] {
+    MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
+
+]]
+  }
+
+  virtual ~BindState() {
+$if ARITY > 0 [[
+    MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::Release(p1_);
+]]
+  }
+
+  RunnableType runnable_;
+
+$for ARG [[
+  P$(ARG) p$(ARG)_;
+
+]]
+};
+
+]] $$ for ARITY
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_BIND_INTERNAL_H_
diff --git a/base/bind_internal_win.h b/base/bind_internal_win.h
new file mode 100644
index 0000000..7a8486a
--- /dev/null
+++ b/base/bind_internal_win.h
@@ -0,0 +1,368 @@
+// This file was GENERATED by command:
+//     pump.py bind_internal_win.h.pump
+// DO NOT EDIT BY HAND!!!
+
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Specializations of RunnableAdapter<> for Windows specific calling
+// conventions.  Please see base/bind_internal.h for more info.
+
+#ifndef BASE_BIND_INTERNAL_WIN_H_
+#define BASE_BIND_INTERNAL_WIN_H_
+
+// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all
+// the same as __cdecl which would turn the following specializations into
+// multiple definitions.
+#if !defined(ARCH_CPU_X86_64)
+
+namespace base {
+namespace internal {
+
+template <typename Functor>
+class RunnableAdapter;
+
+// __stdcall Function: Arity 0.
+template <typename R>
+class RunnableAdapter<R(__stdcall *)()> {
+ public:
+  typedef R (RunType)();
+
+  explicit RunnableAdapter(R(__stdcall *function)())
+      : function_(function) {
+  }
+
+  R Run() {
+    return function_();
+  }
+
+ private:
+  R (__stdcall *function_)();
+};
+
+// __fastcall Function: Arity 0.
+template <typename R>
+class RunnableAdapter<R(__fastcall *)()> {
+ public:
+  typedef R (RunType)();
+
+  explicit RunnableAdapter(R(__fastcall *function)())
+      : function_(function) {
+  }
+
+  R Run() {
+    return function_();
+  }
+
+ private:
+  R (__fastcall *function_)();
+};
+
+// __stdcall Function: Arity 1.
+template <typename R, typename A1>
+class RunnableAdapter<R(__stdcall *)(A1)> {
+ public:
+  typedef R (RunType)(A1);
+
+  explicit RunnableAdapter(R(__stdcall *function)(A1))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1) {
+    return function_(a1);
+  }
+
+ private:
+  R (__stdcall *function_)(A1);
+};
+
+// __fastcall Function: Arity 1.
+template <typename R, typename A1>
+class RunnableAdapter<R(__fastcall *)(A1)> {
+ public:
+  typedef R (RunType)(A1);
+
+  explicit RunnableAdapter(R(__fastcall *function)(A1))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1) {
+    return function_(a1);
+  }
+
+ private:
+  R (__fastcall *function_)(A1);
+};
+
+// __stdcall Function: Arity 2.
+template <typename R, typename A1, typename A2>
+class RunnableAdapter<R(__stdcall *)(A1, A2)> {
+ public:
+  typedef R (RunType)(A1, A2);
+
+  explicit RunnableAdapter(R(__stdcall *function)(A1, A2))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2) {
+    return function_(a1, a2);
+  }
+
+ private:
+  R (__stdcall *function_)(A1, A2);
+};
+
+// __fastcall Function: Arity 2.
+template <typename R, typename A1, typename A2>
+class RunnableAdapter<R(__fastcall *)(A1, A2)> {
+ public:
+  typedef R (RunType)(A1, A2);
+
+  explicit RunnableAdapter(R(__fastcall *function)(A1, A2))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2) {
+    return function_(a1, a2);
+  }
+
+ private:
+  R (__fastcall *function_)(A1, A2);
+};
+
+// __stdcall Function: Arity 3.
+template <typename R, typename A1, typename A2, typename A3>
+class RunnableAdapter<R(__stdcall *)(A1, A2, A3)> {
+ public:
+  typedef R (RunType)(A1, A2, A3);
+
+  explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3) {
+    return function_(a1, a2, a3);
+  }
+
+ private:
+  R (__stdcall *function_)(A1, A2, A3);
+};
+
+// __fastcall Function: Arity 3.
+template <typename R, typename A1, typename A2, typename A3>
+class RunnableAdapter<R(__fastcall *)(A1, A2, A3)> {
+ public:
+  typedef R (RunType)(A1, A2, A3);
+
+  explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3) {
+    return function_(a1, a2, a3);
+  }
+
+ private:
+  R (__fastcall *function_)(A1, A2, A3);
+};
+
+// __stdcall Function: Arity 4.
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+class RunnableAdapter<R(__stdcall *)(A1, A2, A3, A4)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4);
+
+  explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4) {
+    return function_(a1, a2, a3, a4);
+  }
+
+ private:
+  R (__stdcall *function_)(A1, A2, A3, A4);
+};
+
+// __fastcall Function: Arity 4.
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+class RunnableAdapter<R(__fastcall *)(A1, A2, A3, A4)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4);
+
+  explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4) {
+    return function_(a1, a2, a3, a4);
+  }
+
+ private:
+  R (__fastcall *function_)(A1, A2, A3, A4);
+};
+
+// __stdcall Function: Arity 5.
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5>
+class RunnableAdapter<R(__stdcall *)(A1, A2, A3, A4, A5)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5);
+
+  explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4, A5))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5) {
+    return function_(a1, a2, a3, a4, a5);
+  }
+
+ private:
+  R (__stdcall *function_)(A1, A2, A3, A4, A5);
+};
+
+// __fastcall Function: Arity 5.
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5>
+class RunnableAdapter<R(__fastcall *)(A1, A2, A3, A4, A5)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5);
+
+  explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4, A5))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5) {
+    return function_(a1, a2, a3, a4, a5);
+  }
+
+ private:
+  R (__fastcall *function_)(A1, A2, A3, A4, A5);
+};
+
+// __stdcall Function: Arity 6.
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6>
+class RunnableAdapter<R(__stdcall *)(A1, A2, A3, A4, A5, A6)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5, A6);
+
+  explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4, A5, A6))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5,
+      typename CallbackParamTraits<A6>::ForwardType a6) {
+    return function_(a1, a2, a3, a4, a5, a6);
+  }
+
+ private:
+  R (__stdcall *function_)(A1, A2, A3, A4, A5, A6);
+};
+
+// __fastcall Function: Arity 6.
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6>
+class RunnableAdapter<R(__fastcall *)(A1, A2, A3, A4, A5, A6)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5, A6);
+
+  explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4, A5, A6))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5,
+      typename CallbackParamTraits<A6>::ForwardType a6) {
+    return function_(a1, a2, a3, a4, a5, a6);
+  }
+
+ private:
+  R (__fastcall *function_)(A1, A2, A3, A4, A5, A6);
+};
+
+// __stdcall Function: Arity 7.
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6, typename A7>
+class RunnableAdapter<R(__stdcall *)(A1, A2, A3, A4, A5, A6, A7)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7);
+
+  explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4, A5, A6, A7))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5,
+      typename CallbackParamTraits<A6>::ForwardType a6,
+      typename CallbackParamTraits<A7>::ForwardType a7) {
+    return function_(a1, a2, a3, a4, a5, a6, a7);
+  }
+
+ private:
+  R (__stdcall *function_)(A1, A2, A3, A4, A5, A6, A7);
+};
+
+// __fastcall Function: Arity 7.
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6, typename A7>
+class RunnableAdapter<R(__fastcall *)(A1, A2, A3, A4, A5, A6, A7)> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7);
+
+  explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4, A5, A6, A7))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4,
+      typename CallbackParamTraits<A5>::ForwardType a5,
+      typename CallbackParamTraits<A6>::ForwardType a6,
+      typename CallbackParamTraits<A7>::ForwardType a7) {
+    return function_(a1, a2, a3, a4, a5, a6, a7);
+  }
+
+ private:
+  R (__fastcall *function_)(A1, A2, A3, A4, A5, A6, A7);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // !defined(ARCH_CPU_X86_64)
+
+#endif  // BASE_BIND_INTERNAL_WIN_H_
diff --git a/base/bind_internal_win.h.pump b/base/bind_internal_win.h.pump
new file mode 100644
index 0000000..cd108b6
--- /dev/null
+++ b/base/bind_internal_win.h.pump
@@ -0,0 +1,81 @@
+$$ This is a pump file for generating file templates.  Pump is a python
+$$ script that is part of the Google Test suite of utilities.  Description
+$$ can be found here:
+$$
+$$ http://code.google.com/p/googletest/wiki/PumpManual
+$$
+
+$$ See comment for MAX_ARITY in base/bind.h.pump.
+$var MAX_ARITY = 7
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Specializations of RunnableAdapter<> for Windows specific calling
+// conventions.  Please see base/bind_internal.h for more info.
+
+#ifndef BASE_BIND_INTERNAL_WIN_H_
+#define BASE_BIND_INTERNAL_WIN_H_
+
+// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all
+// the same as __cdecl which would turn the following specializations into
+// multiple definitions.
+#if !defined(ARCH_CPU_X86_64)
+
+namespace base {
+namespace internal {
+
+template <typename Functor>
+class RunnableAdapter;
+
+$range ARITY 0..MAX_ARITY
+$for ARITY [[
+$range ARG 1..ARITY
+
+// __stdcall Function: Arity $(ARITY).
+template <typename R[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
+class RunnableAdapter<R(__stdcall *)($for ARG , [[A$(ARG)]])> {
+ public:
+  typedef R (RunType)($for ARG , [[A$(ARG)]]);
+
+  explicit RunnableAdapter(R(__stdcall *function)($for ARG , [[A$(ARG)]]))
+      : function_(function) {
+  }
+
+  R Run($for ARG , [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
+    return function_($for ARG , [[a$(ARG)]]);
+  }
+
+ private:
+  R (__stdcall *function_)($for ARG , [[A$(ARG)]]);
+};
+
+// __fastcall Function: Arity $(ARITY).
+template <typename R[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
+class RunnableAdapter<R(__fastcall *)($for ARG , [[A$(ARG)]])> {
+ public:
+  typedef R (RunType)($for ARG , [[A$(ARG)]]);
+
+  explicit RunnableAdapter(R(__fastcall *function)($for ARG , [[A$(ARG)]]))
+      : function_(function) {
+  }
+
+  R Run($for ARG , [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
+    return function_($for ARG , [[a$(ARG)]]);
+  }
+
+ private:
+  R (__fastcall *function_)($for ARG , [[A$(ARG)]]);
+};
+
+]]  $$for ARITY
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // !defined(ARCH_CPU_X86_64)
+
+#endif  // BASE_BIND_INTERNAL_WIN_H_
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc
new file mode 100644
index 0000000..0f91b2e
--- /dev/null
+++ b/base/bind_unittest.cc
@@ -0,0 +1,802 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+namespace base {
+namespace {
+
+class IncompleteType;
+
+class NoRef {
+ public:
+  NoRef() {}
+
+  MOCK_METHOD0(VoidMethod0, void(void));
+  MOCK_CONST_METHOD0(VoidConstMethod0, void(void));
+
+  MOCK_METHOD0(IntMethod0, int(void));
+  MOCK_CONST_METHOD0(IntConstMethod0, int(void));
+
+ private:
+  // Particularly important in this test to ensure no copies are made.
+  DISALLOW_COPY_AND_ASSIGN(NoRef);
+};
+
+class HasRef : public NoRef {
+ public:
+  HasRef() {}
+
+  MOCK_CONST_METHOD0(AddRef, void(void));
+  MOCK_CONST_METHOD0(Release, bool(void));
+
+ private:
+  // Particularly important in this test to ensure no copies are made.
+  DISALLOW_COPY_AND_ASSIGN(HasRef);
+};
+
+class HasRefPrivateDtor : public HasRef {
+ private:
+  ~HasRefPrivateDtor() {}
+};
+
+static const int kParentValue = 1;
+static const int kChildValue = 2;
+
+class Parent {
+ public:
+  void AddRef(void) const {}
+  void Release(void) const {}
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class Child : public Parent {
+ public:
+  virtual void VirtualSet() OVERRIDE { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+class NoRefParent {
+ public:
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class NoRefChild : public NoRefParent {
+  virtual void VirtualSet() OVERRIDE { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+// Used for probing the number of copies that occur if a type must be coerced
+// during argument forwarding in the Run() methods.
+struct DerivedCopyCounter {
+  DerivedCopyCounter(int* copies, int* assigns)
+      : copies_(copies), assigns_(assigns) {
+  }
+  int* copies_;
+  int* assigns_;
+};
+
+// Used for probing the number of copies in an argument.
+class CopyCounter {
+ public:
+  CopyCounter(int* copies, int* assigns)
+      : copies_(copies), assigns_(assigns) {
+  }
+
+  CopyCounter(const CopyCounter& other)
+      : copies_(other.copies_),
+        assigns_(other.assigns_) {
+    (*copies_)++;
+  }
+
+  // Probing for copies from coercion.
+  CopyCounter(const DerivedCopyCounter& other)
+      : copies_(other.copies_),
+        assigns_(other.assigns_) {
+    (*copies_)++;
+  }
+
+  const CopyCounter& operator=(const CopyCounter& rhs) {
+    copies_ = rhs.copies_;
+    assigns_ = rhs.assigns_;
+
+    if (assigns_) {
+      (*assigns_)++;
+    }
+
+    return *this;
+  }
+
+  int copies() const {
+    return *copies_;
+  }
+
+  int assigns() const {
+    return *assigns_;
+  }
+
+ private:
+  int* copies_;
+  int* assigns_;
+};
+
+class DeleteCounter {
+ public:
+  explicit DeleteCounter(int* deletes)
+      : deletes_(deletes) {
+  }
+
+  ~DeleteCounter() {
+    (*deletes_)++;
+  }
+
+  void VoidMethod0() {}
+
+ private:
+  int* deletes_;
+};
+
+template <typename T>
+T PassThru(T scoper) {
+  return scoper.Pass();
+}
+
+// Some test functions that we can Bind to.
+template <typename T>
+T PolymorphicIdentity(T t) {
+  return t;
+}
+
+template <typename T>
+void VoidPolymorphic1(T t) {
+}
+
+int Identity(int n) {
+  return n;
+}
+
+int ArrayGet(const int array[], int n) {
+  return array[n];
+}
+
+int Sum(int a, int b, int c, int d, int e, int f) {
+  return a + b + c + d + e + f;
+}
+
+const char* CStringIdentity(const char* s) {
+  return s;
+}
+
+int GetCopies(const CopyCounter& counter) {
+  return counter.copies();
+}
+
+int UnwrapNoRefParent(NoRefParent p) {
+  return p.value;
+}
+
+int UnwrapNoRefParentPtr(NoRefParent* p) {
+  return p->value;
+}
+
+int UnwrapNoRefParentConstRef(const NoRefParent& p) {
+  return p.value;
+}
+
+void RefArgSet(int &n) {
+  n = 2;
+}
+
+void PtrArgSet(int *n) {
+  *n = 2;
+}
+
+int FunctionWithWeakFirstParam(WeakPtr<NoRef> o, int n) {
+  return n;
+}
+
+void TakesACallback(const Closure& callback) {
+  callback.Run();
+}
+
+class BindTest : public ::testing::Test {
+ public:
+  BindTest() {
+    const_has_ref_ptr_ = &has_ref_;
+    const_no_ref_ptr_ = &no_ref_;
+    static_func_mock_ptr = &static_func_mock_;
+  }
+
+  virtual ~BindTest() {
+  }
+
+  static void VoidFunc0(void) {
+    static_func_mock_ptr->VoidMethod0();
+  }
+
+  static int IntFunc0(void) { return static_func_mock_ptr->IntMethod0(); }
+
+ protected:
+  StrictMock<NoRef> no_ref_;
+  StrictMock<HasRef> has_ref_;
+  const HasRef* const_has_ref_ptr_;
+  const NoRef* const_no_ref_ptr_;
+  StrictMock<NoRef> static_func_mock_;
+
+  // Used by the static functions to perform expectations.
+  static StrictMock<NoRef>* static_func_mock_ptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BindTest);
+};
+
+StrictMock<NoRef>* BindTest::static_func_mock_ptr;
+
+// Sanity check that we can instantiate a callback for each arity.
+TEST_F(BindTest, ArityTest) {
+  Callback<int(void)> c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1);
+  EXPECT_EQ(63, c0.Run());
+
+  Callback<int(int)> c1 = Bind(&Sum, 32, 16, 8, 4, 2);
+  EXPECT_EQ(75, c1.Run(13));
+
+  Callback<int(int,int)> c2 = Bind(&Sum, 32, 16, 8, 4);
+  EXPECT_EQ(85, c2.Run(13, 12));
+
+  Callback<int(int,int,int)> c3 = Bind(&Sum, 32, 16, 8);
+  EXPECT_EQ(92, c3.Run(13, 12, 11));
+
+  Callback<int(int,int,int,int)> c4 = Bind(&Sum, 32, 16);
+  EXPECT_EQ(94, c4.Run(13, 12, 11, 10));
+
+  Callback<int(int,int,int,int,int)> c5 = Bind(&Sum, 32);
+  EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9));
+
+  Callback<int(int,int,int,int,int,int)> c6 = Bind(&Sum);
+  EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14));
+}
+
+// Test the Currying ability of the Callback system.
+TEST_F(BindTest, CurryingTest) {
+  Callback<int(int,int,int,int,int,int)> c6 = Bind(&Sum);
+  EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14));
+
+  Callback<int(int,int,int,int,int)> c5 = Bind(c6, 32);
+  EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9));
+
+  Callback<int(int,int,int,int)> c4 = Bind(c5, 16);
+  EXPECT_EQ(94, c4.Run(13, 12, 11, 10));
+
+  Callback<int(int,int,int)> c3 = Bind(c4, 8);
+  EXPECT_EQ(92, c3.Run(13, 12, 11));
+
+  Callback<int(int,int)> c2 = Bind(c3, 4);
+  EXPECT_EQ(85, c2.Run(13, 12));
+
+  Callback<int(int)> c1 = Bind(c2, 2);
+  EXPECT_EQ(75, c1.Run(13));
+
+  Callback<int(void)> c0 = Bind(c1, 1);
+  EXPECT_EQ(63, c0.Run());
+}
+
+// Test that currying the rvalue result of another Bind() works correctly.
+//   - rvalue should be usable as argument to Bind().
+//   - multiple runs of resulting Callback remain valid.
+TEST_F(BindTest, CurryingRvalueResultOfBind) {
+  int n = 0;
+  Closure cb = base::Bind(&TakesACallback, base::Bind(&PtrArgSet, &n));
+
+  // If we implement Bind() such that the return value has auto_ptr-like
+  // semantics, the second call here will fail because ownership of
+  // the internal BindState<> would have been transfered to a *temporary*
+  // constructon of a Callback object on the first call.
+  cb.Run();
+  EXPECT_EQ(2, n);
+
+  n = 0;
+  cb.Run();
+  EXPECT_EQ(2, n);
+}
+
+// Function type support.
+//   - Normal function.
+//   - Normal function bound with non-refcounted first argument.
+//   - Method bound to non-const object.
+//   - Method bound to scoped_refptr.
+//   - Const method bound to non-const object.
+//   - Const method bound to const object.
+//   - Derived classes can be used with pointers to non-virtual base functions.
+//   - Derived classes can be used with pointers to virtual base functions (and
+//     preserve virtual dispatch).
+TEST_F(BindTest, FunctionTypeSupport) {
+  EXPECT_CALL(static_func_mock_, VoidMethod0());
+  EXPECT_CALL(has_ref_, AddRef()).Times(5);
+  EXPECT_CALL(has_ref_, Release()).Times(5);
+  EXPECT_CALL(has_ref_, VoidMethod0()).Times(2);
+  EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2);
+
+  Closure normal_cb = Bind(&VoidFunc0);
+  Callback<NoRef*(void)> normal_non_refcounted_cb =
+      Bind(&PolymorphicIdentity<NoRef*>, &no_ref_);
+  normal_cb.Run();
+  EXPECT_EQ(&no_ref_, normal_non_refcounted_cb.Run());
+
+  Closure method_cb = Bind(&HasRef::VoidMethod0, &has_ref_);
+  Closure method_refptr_cb = Bind(&HasRef::VoidMethod0,
+                                  make_scoped_refptr(&has_ref_));
+  Closure const_method_nonconst_obj_cb = Bind(&HasRef::VoidConstMethod0,
+                                              &has_ref_);
+  Closure const_method_const_obj_cb = Bind(&HasRef::VoidConstMethod0,
+                                           const_has_ref_ptr_);
+  method_cb.Run();
+  method_refptr_cb.Run();
+  const_method_nonconst_obj_cb.Run();
+  const_method_const_obj_cb.Run();
+
+  Child child;
+  child.value = 0;
+  Closure virtual_set_cb = Bind(&Parent::VirtualSet, &child);
+  virtual_set_cb.Run();
+  EXPECT_EQ(kChildValue, child.value);
+
+  child.value = 0;
+  Closure non_virtual_set_cb = Bind(&Parent::NonVirtualSet, &child);
+  non_virtual_set_cb.Run();
+  EXPECT_EQ(kParentValue, child.value);
+}
+
+// Return value support.
+//   - Function with return value.
+//   - Method with return value.
+//   - Const method with return value.
+TEST_F(BindTest, ReturnValues) {
+  EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337));
+  EXPECT_CALL(has_ref_, AddRef()).Times(3);
+  EXPECT_CALL(has_ref_, Release()).Times(3);
+  EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(31337));
+  EXPECT_CALL(has_ref_, IntConstMethod0())
+      .WillOnce(Return(41337))
+      .WillOnce(Return(51337));
+
+  Callback<int(void)> normal_cb = Bind(&IntFunc0);
+  Callback<int(void)> method_cb = Bind(&HasRef::IntMethod0, &has_ref_);
+  Callback<int(void)> const_method_nonconst_obj_cb =
+      Bind(&HasRef::IntConstMethod0, &has_ref_);
+  Callback<int(void)> const_method_const_obj_cb =
+      Bind(&HasRef::IntConstMethod0, const_has_ref_ptr_);
+  EXPECT_EQ(1337, normal_cb.Run());
+  EXPECT_EQ(31337, method_cb.Run());
+  EXPECT_EQ(41337, const_method_nonconst_obj_cb.Run());
+  EXPECT_EQ(51337, const_method_const_obj_cb.Run());
+}
+
+// IgnoreResult adapter test.
+//   - Function with return value.
+//   - Method with return value.
+//   - Const Method with return.
+//   - Method with return value bound to WeakPtr<>.
+//   - Const Method with return bound to WeakPtr<>.
+TEST_F(BindTest, IgnoreResult) {
+  EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337));
+  EXPECT_CALL(has_ref_, AddRef()).Times(2);
+  EXPECT_CALL(has_ref_, Release()).Times(2);
+  EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(10));
+  EXPECT_CALL(has_ref_, IntConstMethod0()).WillOnce(Return(11));
+  EXPECT_CALL(no_ref_, IntMethod0()).WillOnce(Return(12));
+  EXPECT_CALL(no_ref_, IntConstMethod0()).WillOnce(Return(13));
+
+  Closure normal_func_cb = Bind(IgnoreResult(&IntFunc0));
+  normal_func_cb.Run();
+
+  Closure non_void_method_cb =
+      Bind(IgnoreResult(&HasRef::IntMethod0), &has_ref_);
+  non_void_method_cb.Run();
+
+  Closure non_void_const_method_cb =
+      Bind(IgnoreResult(&HasRef::IntConstMethod0), &has_ref_);
+  non_void_const_method_cb.Run();
+
+  WeakPtrFactory<NoRef> weak_factory(&no_ref_);
+  WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_);
+
+  Closure non_void_weak_method_cb  =
+      Bind(IgnoreResult(&NoRef::IntMethod0), weak_factory.GetWeakPtr());
+  non_void_weak_method_cb.Run();
+
+  Closure non_void_weak_const_method_cb =
+      Bind(IgnoreResult(&NoRef::IntConstMethod0), weak_factory.GetWeakPtr());
+  non_void_weak_const_method_cb.Run();
+
+  weak_factory.InvalidateWeakPtrs();
+  non_void_weak_const_method_cb.Run();
+  non_void_weak_method_cb.Run();
+}
+
+// Argument binding tests.
+//   - Argument binding to primitive.
+//   - Argument binding to primitive pointer.
+//   - Argument binding to a literal integer.
+//   - Argument binding to a literal string.
+//   - Argument binding with template function.
+//   - Argument binding to an object.
+//   - Argument binding to pointer to incomplete type.
+//   - Argument gets type converted.
+//   - Pointer argument gets converted.
+//   - Const Reference forces conversion.
+TEST_F(BindTest, ArgumentBinding) {
+  int n = 2;
+
+  Callback<int(void)> bind_primitive_cb = Bind(&Identity, n);
+  EXPECT_EQ(n, bind_primitive_cb.Run());
+
+  Callback<int*(void)> bind_primitive_pointer_cb =
+      Bind(&PolymorphicIdentity<int*>, &n);
+  EXPECT_EQ(&n, bind_primitive_pointer_cb.Run());
+
+  Callback<int(void)> bind_int_literal_cb = Bind(&Identity, 3);
+  EXPECT_EQ(3, bind_int_literal_cb.Run());
+
+  Callback<const char*(void)> bind_string_literal_cb =
+      Bind(&CStringIdentity, "hi");
+  EXPECT_STREQ("hi", bind_string_literal_cb.Run());
+
+  Callback<int(void)> bind_template_function_cb =
+      Bind(&PolymorphicIdentity<int>, 4);
+  EXPECT_EQ(4, bind_template_function_cb.Run());
+
+  NoRefParent p;
+  p.value = 5;
+  Callback<int(void)> bind_object_cb = Bind(&UnwrapNoRefParent, p);
+  EXPECT_EQ(5, bind_object_cb.Run());
+
+  IncompleteType* incomplete_ptr = reinterpret_cast<IncompleteType*>(123);
+  Callback<IncompleteType*(void)> bind_incomplete_ptr_cb =
+      Bind(&PolymorphicIdentity<IncompleteType*>, incomplete_ptr);
+  EXPECT_EQ(incomplete_ptr, bind_incomplete_ptr_cb.Run());
+
+  NoRefChild c;
+  c.value = 6;
+  Callback<int(void)> bind_promotes_cb = Bind(&UnwrapNoRefParent, c);
+  EXPECT_EQ(6, bind_promotes_cb.Run());
+
+  c.value = 7;
+  Callback<int(void)> bind_pointer_promotes_cb =
+      Bind(&UnwrapNoRefParentPtr, &c);
+  EXPECT_EQ(7, bind_pointer_promotes_cb.Run());
+
+  c.value = 8;
+  Callback<int(void)> bind_const_reference_promotes_cb =
+      Bind(&UnwrapNoRefParentConstRef, c);
+  EXPECT_EQ(8, bind_const_reference_promotes_cb.Run());
+}
+
+// Unbound argument type support tests.
+//   - Unbound value.
+//   - Unbound pointer.
+//   - Unbound reference.
+//   - Unbound const reference.
+//   - Unbound unsized array.
+//   - Unbound sized array.
+//   - Unbound array-of-arrays.
+TEST_F(BindTest, UnboundArgumentTypeSupport) {
+  Callback<void(int)> unbound_value_cb = Bind(&VoidPolymorphic1<int>);
+  Callback<void(int*)> unbound_pointer_cb = Bind(&VoidPolymorphic1<int*>);
+  Callback<void(int&)> unbound_ref_cb = Bind(&VoidPolymorphic1<int&>);
+  Callback<void(const int&)> unbound_const_ref_cb =
+      Bind(&VoidPolymorphic1<const int&>);
+  Callback<void(int[])> unbound_unsized_array_cb =
+      Bind(&VoidPolymorphic1<int[]>);
+  Callback<void(int[2])> unbound_sized_array_cb =
+      Bind(&VoidPolymorphic1<int[2]>);
+  Callback<void(int[][2])> unbound_array_of_arrays_cb =
+      Bind(&VoidPolymorphic1<int[][2]>);
+}
+
+// Function with unbound reference parameter.
+//   - Original parameter is modified by callback.
+TEST_F(BindTest, UnboundReferenceSupport) {
+  int n = 0;
+  Callback<void(int&)> unbound_ref_cb = Bind(&RefArgSet);
+  unbound_ref_cb.Run(n);
+  EXPECT_EQ(2, n);
+}
+
+// Functions that take reference parameters.
+//  - Forced reference parameter type still stores a copy.
+//  - Forced const reference parameter type still stores a copy.
+TEST_F(BindTest, ReferenceArgumentBinding) {
+  int n = 1;
+  int& ref_n = n;
+  const int& const_ref_n = n;
+
+  Callback<int(void)> ref_copies_cb = Bind(&Identity, ref_n);
+  EXPECT_EQ(n, ref_copies_cb.Run());
+  n++;
+  EXPECT_EQ(n - 1, ref_copies_cb.Run());
+
+  Callback<int(void)> const_ref_copies_cb = Bind(&Identity, const_ref_n);
+  EXPECT_EQ(n, const_ref_copies_cb.Run());
+  n++;
+  EXPECT_EQ(n - 1, const_ref_copies_cb.Run());
+}
+
+// Check that we can pass in arrays and have them be stored as a pointer.
+//  - Array of values stores a pointer.
+//  - Array of const values stores a pointer.
+TEST_F(BindTest, ArrayArgumentBinding) {
+  int array[4] = {1, 1, 1, 1};
+  const int (*const_array_ptr)[4] = &array;
+
+  Callback<int(void)> array_cb = Bind(&ArrayGet, array, 1);
+  EXPECT_EQ(1, array_cb.Run());
+
+  Callback<int(void)> const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1);
+  EXPECT_EQ(1, const_array_cb.Run());
+
+  array[1] = 3;
+  EXPECT_EQ(3, array_cb.Run());
+  EXPECT_EQ(3, const_array_cb.Run());
+}
+
+// Verify SupportsAddRefAndRelease correctly introspects the class type for
+// AddRef() and Release().
+//  - Class with AddRef() and Release()
+//  - Class without AddRef() and Release()
+//  - Derived Class with AddRef() and Release()
+//  - Derived Class without AddRef() and Release()
+//  - Derived Class with AddRef() and Release() and a private destructor.
+TEST_F(BindTest, SupportsAddRefAndRelease) {
+  EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRef>::value);
+  EXPECT_FALSE(internal::SupportsAddRefAndRelease<NoRef>::value);
+
+  // StrictMock<T> is a derived class of T.  So, we use StrictMock<HasRef> and
+  // StrictMock<NoRef> to test that SupportsAddRefAndRelease works over
+  // inheritance.
+  EXPECT_TRUE(internal::SupportsAddRefAndRelease<StrictMock<HasRef> >::value);
+  EXPECT_FALSE(internal::SupportsAddRefAndRelease<StrictMock<NoRef> >::value);
+
+  // This matters because the implementation creates a dummy class that
+  // inherits from the template type.
+  EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRefPrivateDtor>::value);
+}
+
+// Unretained() wrapper support.
+//   - Method bound to Unretained() non-const object.
+//   - Const method bound to Unretained() non-const object.
+//   - Const method bound to Unretained() const object.
+TEST_F(BindTest, Unretained) {
+  EXPECT_CALL(no_ref_, VoidMethod0());
+  EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2);
+
+  Callback<void(void)> method_cb =
+      Bind(&NoRef::VoidMethod0, Unretained(&no_ref_));
+  method_cb.Run();
+
+  Callback<void(void)> const_method_cb =
+      Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref_));
+  const_method_cb.Run();
+
+  Callback<void(void)> const_method_const_ptr_cb =
+      Bind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr_));
+  const_method_const_ptr_cb.Run();
+}
+
+// WeakPtr() support.
+//   - Method bound to WeakPtr<> to non-const object.
+//   - Const method bound to WeakPtr<> to non-const object.
+//   - Const method bound to WeakPtr<> to const object.
+//   - Normal Function with WeakPtr<> as P1 can have return type and is
+//     not canceled.
+TEST_F(BindTest, WeakPtr) {
+  EXPECT_CALL(no_ref_, VoidMethod0());
+  EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2);
+
+  WeakPtrFactory<NoRef> weak_factory(&no_ref_);
+  WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_);
+
+  Closure method_cb =
+      Bind(&NoRef::VoidMethod0, weak_factory.GetWeakPtr());
+  method_cb.Run();
+
+  Closure const_method_cb =
+      Bind(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr());
+  const_method_cb.Run();
+
+  Closure const_method_const_ptr_cb =
+      Bind(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr());
+  const_method_const_ptr_cb.Run();
+
+  Callback<int(int)> normal_func_cb =
+      Bind(&FunctionWithWeakFirstParam, weak_factory.GetWeakPtr());
+  EXPECT_EQ(1, normal_func_cb.Run(1));
+
+  weak_factory.InvalidateWeakPtrs();
+  const_weak_factory.InvalidateWeakPtrs();
+
+  method_cb.Run();
+  const_method_cb.Run();
+  const_method_const_ptr_cb.Run();
+
+  // Still runs even after the pointers are invalidated.
+  EXPECT_EQ(2, normal_func_cb.Run(2));
+}
+
+// ConstRef() wrapper support.
+//   - Binding w/o ConstRef takes a copy.
+//   - Binding a ConstRef takes a reference.
+//   - Binding ConstRef to a function ConstRef does not copy on invoke.
+TEST_F(BindTest, ConstRef) {
+  int n = 1;
+
+  Callback<int(void)> copy_cb = Bind(&Identity, n);
+  Callback<int(void)> const_ref_cb = Bind(&Identity, ConstRef(n));
+  EXPECT_EQ(n, copy_cb.Run());
+  EXPECT_EQ(n, const_ref_cb.Run());
+  n++;
+  EXPECT_EQ(n - 1, copy_cb.Run());
+  EXPECT_EQ(n, const_ref_cb.Run());
+
+  int copies = 0;
+  int assigns = 0;
+  CopyCounter counter(&copies, &assigns);
+  Callback<int(void)> all_const_ref_cb =
+      Bind(&GetCopies, ConstRef(counter));
+  EXPECT_EQ(0, all_const_ref_cb.Run());
+  EXPECT_EQ(0, copies);
+  EXPECT_EQ(0, assigns);
+}
+
+// Test Owned() support.
+TEST_F(BindTest, Owned) {
+  int deletes = 0;
+  DeleteCounter* counter = new DeleteCounter(&deletes);
+
+  // If we don't capture, delete happens on Callback destruction/reset.
+  // return the same value.
+  Callback<DeleteCounter*(void)> no_capture_cb =
+      Bind(&PolymorphicIdentity<DeleteCounter*>, Owned(counter));
+  ASSERT_EQ(counter, no_capture_cb.Run());
+  ASSERT_EQ(counter, no_capture_cb.Run());
+  EXPECT_EQ(0, deletes);
+  no_capture_cb.Reset();  // This should trigger a delete.
+  EXPECT_EQ(1, deletes);
+
+  deletes = 0;
+  counter = new DeleteCounter(&deletes);
+  base::Closure own_object_cb =
+      Bind(&DeleteCounter::VoidMethod0, Owned(counter));
+  own_object_cb.Run();
+  EXPECT_EQ(0, deletes);
+  own_object_cb.Reset();
+  EXPECT_EQ(1, deletes);
+}
+
+// Passed() wrapper support.
+//   - Passed() can be constructed from a pointer to scoper.
+//   - Passed() can be constructed from a scoper rvalue.
+//   - Using Passed() gives Callback Ownership.
+//   - Ownership is transferred from Callback to callee on the first Run().
+//   - Callback supports unbound arguments.
+TEST_F(BindTest, ScopedPtr) {
+  int deletes = 0;
+
+  // Tests the Passed() function's support for pointers.
+  scoped_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes));
+  Callback<scoped_ptr<DeleteCounter>(void)> unused_callback =
+      Bind(&PassThru<scoped_ptr<DeleteCounter> >, Passed(&ptr));
+  EXPECT_FALSE(ptr.get());
+  EXPECT_EQ(0, deletes);
+
+  // If we never invoke the Callback, it retains ownership and deletes.
+  unused_callback.Reset();
+  EXPECT_EQ(1, deletes);
+
+  // Tests the Passed() function's support for rvalues.
+  deletes = 0;
+  DeleteCounter* counter = new DeleteCounter(&deletes);
+  Callback<scoped_ptr<DeleteCounter>(void)> callback =
+      Bind(&PassThru<scoped_ptr<DeleteCounter> >,
+           Passed(scoped_ptr<DeleteCounter>(counter)));
+  EXPECT_FALSE(ptr.get());
+  EXPECT_EQ(0, deletes);
+
+  // Check that ownership can be transferred back out.
+  scoped_ptr<DeleteCounter> result = callback.Run();
+  ASSERT_EQ(counter, result.get());
+  EXPECT_EQ(0, deletes);
+
+  // Resetting does not delete since ownership was transferred.
+  callback.Reset();
+  EXPECT_EQ(0, deletes);
+
+  // Ensure that we actually did get ownership.
+  result.reset();
+  EXPECT_EQ(1, deletes);
+
+  // Test unbound argument forwarding.
+  Callback<scoped_ptr<DeleteCounter>(scoped_ptr<DeleteCounter>)> cb_unbound =
+      Bind(&PassThru<scoped_ptr<DeleteCounter> >);
+  ptr.reset(new DeleteCounter(&deletes));
+  cb_unbound.Run(ptr.Pass());
+}
+
+// Argument Copy-constructor usage for non-reference parameters.
+//   - Bound arguments are only copied once.
+//   - Forwarded arguments are only copied once.
+//   - Forwarded arguments with coercions are only copied twice (once for the
+//     coercion, and one for the final dispatch).
+TEST_F(BindTest, ArgumentCopies) {
+  int copies = 0;
+  int assigns = 0;
+
+  CopyCounter counter(&copies, &assigns);
+
+  Callback<void(void)> copy_cb =
+      Bind(&VoidPolymorphic1<CopyCounter>, counter);
+  EXPECT_GE(1, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  Callback<void(CopyCounter)> forward_cb =
+      Bind(&VoidPolymorphic1<CopyCounter>);
+  forward_cb.Run(counter);
+  EXPECT_GE(1, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  DerivedCopyCounter dervied(&copies, &assigns);
+  Callback<void(CopyCounter)> coerce_cb =
+      Bind(&VoidPolymorphic1<CopyCounter>);
+  coerce_cb.Run(dervied);
+  EXPECT_GE(2, copies);
+  EXPECT_EQ(0, assigns);
+}
+
+// Callback construction and assignment tests.
+//   - Construction from an InvokerStorageHolder should not cause ref/deref.
+//   - Assignment from other callback should only cause one ref
+//
+// TODO(ajwong): Is there actually a way to test this?
+
+#if defined(OS_WIN)
+int __fastcall FastCallFunc(int n) {
+  return n;
+}
+
+int __stdcall StdCallFunc(int n) {
+  return n;
+}
+
+// Windows specific calling convention support.
+//   - Can bind a __fastcall function.
+//   - Can bind a __stdcall function.
+TEST_F(BindTest, WindowsCallingConventions) {
+  Callback<int(void)> fastcall_cb = Bind(&FastCallFunc, 1);
+  EXPECT_EQ(1, fastcall_cb.Run());
+
+  Callback<int(void)> stdcall_cb = Bind(&StdCallFunc, 2);
+  EXPECT_EQ(2, stdcall_cb.Run());
+}
+#endif
+
+}  // namespace
+}  // namespace base
diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc
new file mode 100644
index 0000000..069092c
--- /dev/null
+++ b/base/bind_unittest.nc
@@ -0,0 +1,203 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback.h"
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+// Do not put everything inside an anonymous namespace.  If you do, many of the
+// helper function declarations will generate unused definition warnings unless
+// unused definition warnings.
+
+static const int kParentValue = 1;
+static const int kChildValue = 2;
+
+class NoRef {
+ public:
+  void VoidMethod0() {}
+  void VoidConstMethod0() const {}
+  int IntMethod0() { return 1; }
+};
+
+class HasRef : public NoRef, public base::RefCounted<HasRef> {
+};
+
+class Parent {
+ public:
+  void AddRef(void) const {}
+  void Release(void) const {}
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class Child : public Parent {
+ public:
+  virtual void VirtualSet() { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+class NoRefParent {
+ public:
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class NoRefChild : public NoRefParent {
+  virtual void VirtualSet() { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+template <typename T>
+T PolymorphicIdentity(T t) {
+  return t;
+}
+
+int UnwrapParentRef(Parent& p) {
+  return p.value;
+}
+
+template <typename T>
+void VoidPolymorphic1(T t) {
+}
+
+#if defined(NCTEST_METHOD_ON_CONST_OBJECT)  // [r"invalid conversion from 'const base::NoRef\*' to 'base::NoRef\*'"]
+
+// Method bound to const-object.
+//
+// Only const methods should be allowed to work with const objects.
+void WontCompile() {
+  HasRef has_ref;
+  const HasRef* const_has_ref_ptr_ = &has_ref;
+  Callback<void(void)> method_to_const_cb =
+      Bind(&HasRef::VoidMethod0, const_has_ref_ptr_);
+  method_to_const_cb.Run();
+}
+
+#elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT)  // [r"has no member named 'AddRef'"]
+
+// Method bound to non-refcounted object.
+//
+// We require refcounts unless you have Unretained().
+void WontCompile() {
+  NoRef no_ref;
+  Callback<void(void)> no_ref_cb =
+      Bind(&NoRef::VoidMethod0, &no_ref);
+  no_ref_cb.Run();
+}
+
+#elif defined(NCTEST_CONST_METHOD_NEEDS_REFCOUNTED_OBJECT)  // [r"has no member named 'AddRef'"]
+
+// Const Method bound to non-refcounted object.
+//
+// We require refcounts unless you have Unretained().
+void WontCompile() {
+  NoRef no_ref;
+  Callback<void(void)> no_ref_const_cb =
+      Bind(&NoRef::VoidConstMethod0, &no_ref);
+  no_ref_const_cb.Run();
+}
+
+#elif defined(NCTEST_CONST_POINTER)  // [r"invalid conversion from 'const base::NoRef\*' to 'base::NoRef\*'"]
+
+// Const argument used with non-const pointer parameter of same type.
+//
+// This is just a const-correctness check.
+void WontCompile() {
+  const NoRef* const_no_ref_ptr;
+  Callback<NoRef*(void)> pointer_same_cb =
+      Bind(&PolymorphicIdentity<NoRef*>, const_no_ref_ptr);
+  pointer_same_cb.Run();
+}
+
+#elif defined(NCTEST_CONST_POINTER_SUBTYPE)  // [r"'const base::NoRefParent\*' to 'base::NoRefParent\*'"]
+
+// Const argument used with non-const pointer parameter of super type.
+//
+// This is just a const-correctness check.
+void WontCompile() {
+  const NoRefChild* const_child_ptr;
+  Callback<NoRefParent*(void)> pointer_super_cb =
+    Bind(&PolymorphicIdentity<NoRefParent*>, const_child_ptr);
+  pointer_super_cb.Run();
+}
+
+#elif defined(DISABLED_NCTEST_DISALLOW_NON_CONST_REF_PARAM)  // [r"badstring"]
+// I think there's a type safety promotion issue here where we can pass a const
+// ref to a non const-ref function, or vice versa accidentally. Or we make a
+// copy accidentally. Check.
+
+// Functions with reference parameters, unsupported.
+//
+// First, non-const reference parameters are disallowed by the Google
+// style guide. Second, since we are doing argument forwarding it becomes
+// very tricky to avoid copies, maintain const correctness, and not
+// accidentally have the function be modifying a temporary, or a copy.
+void WontCompile() {
+  Parent p;
+  Callback<int(Parent&)> ref_arg_cb = Bind(&UnwrapParentRef);
+  ref_arg_cb.Run(p);
+}
+
+#elif defined(NCTEST_DISALLOW_BIND_TO_NON_CONST_REF_PARAM)  // [r"creating array with negative size"]
+
+// Binding functions with reference parameters, unsupported.
+//
+// See comment in NCTEST_DISALLOW_NON_CONST_REF_PARAM
+void WontCompile() {
+  Parent p;
+  Callback<int(void)> ref_cb = Bind(&UnwrapParentRef, p);
+  ref_cb.Run();
+}
+
+#elif defined(NCTEST_NO_IMPLICIT_ARRAY_PTR_CONVERSION)  // [r"creating array with negative size"]
+
+// A method should not be bindable with an array of objects.
+//
+// This is likely not wanted behavior. We specifically check for it though
+// because it is possible, depending on how you implement prebinding, to
+// implicitly convert an array type to a pointer type.
+void WontCompile() {
+  HasRef p[10];
+  Callback<void(void)> method_bound_to_array_cb =
+      Bind(&HasRef::VoidMethod0, p);
+  method_bound_to_array_cb.Run();
+}
+
+#elif defined(NCTEST_NO_RAW_PTR_FOR_REFCOUNTED_TYPES)  // [r"creating array with negative size"]
+
+// Refcounted types should not be bound as a raw pointer.
+void WontCompile() {
+  HasRef for_raw_ptr;
+  int a;
+  Callback<void(void)> ref_count_as_raw_ptr_a =
+      Bind(&VoidPolymorphic1<int*>, &a);
+  Callback<void(void)> ref_count_as_raw_ptr =
+      Bind(&VoidPolymorphic1<HasRef*>, &for_raw_ptr);
+}
+
+#elif defined(NCTEST_WEAKPTR_BIND_MUST_RETURN_VOID)  // [r"creating array with negative size"]
+
+// WeakPtrs cannot be bound to methods with return types.
+void WontCompile() {
+  NoRef no_ref;
+  WeakPtrFactory<NoRef> weak_factory(&no_ref);
+  Callback<int(void)> weak_ptr_with_non_void_return_type =
+      Bind(&NoRef::IntMethod0, weak_factory.GetWeakPtr());
+  weak_ptr_with_non_void_return_type.Run();
+}
+
+#elif defined(NCTEST_DISALLOW_ASSIGN_DIFFERINT_TYPES)  // [r"invalid conversion from"]
+
+// Bind result cannot be assigned to Callbacks with a mismatching type.
+void WontCompile() {
+  Closure callback_mismatches_bind_type = Bind(&VoidPolymorphic1<int>);
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/bits.h b/base/bits.h
new file mode 100644
index 0000000..b2209e8
--- /dev/null
+++ b/base/bits.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines some bit utilities.
+
+#ifndef BASE_BITS_H_
+#define BASE_BITS_H_
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace bits {
+
+// Returns the integer i such as 2^i <= n < 2^(i+1)
+inline int Log2Floor(uint32 n) {
+  if (n == 0)
+    return -1;
+  int log = 0;
+  uint32 value = n;
+  for (int i = 4; i >= 0; --i) {
+    int shift = (1 << i);
+    uint32 x = value >> shift;
+    if (x != 0) {
+      value = x;
+      log += shift;
+    }
+  }
+  DCHECK_EQ(value, 1u);
+  return log;
+}
+
+// Returns the integer i such as 2^(i-1) < n <= 2^i
+inline int Log2Ceiling(uint32 n) {
+  if (n == 0) {
+    return -1;
+  } else {
+    // Log2Floor returns -1 for 0, so the following works correctly for n=1.
+    return 1 + Log2Floor(n - 1);
+  }
+}
+
+}  // namespace bits
+}  // namespace base
+
+#endif  // BASE_BITS_H_
diff --git a/base/bits_unittest.cc b/base/bits_unittest.cc
new file mode 100644
index 0000000..e913d6a
--- /dev/null
+++ b/base/bits_unittest.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the unit tests for the bit utilities.
+
+#include "base/bits.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace bits {
+
+TEST(BitsTest, Log2Floor) {
+  EXPECT_EQ(-1, Log2Floor(0));
+  EXPECT_EQ(0, Log2Floor(1));
+  EXPECT_EQ(1, Log2Floor(2));
+  EXPECT_EQ(1, Log2Floor(3));
+  EXPECT_EQ(2, Log2Floor(4));
+  for (int i = 3; i < 31; ++i) {
+    unsigned int value = 1U << i;
+    EXPECT_EQ(i, Log2Floor(value));
+    EXPECT_EQ(i, Log2Floor(value + 1));
+    EXPECT_EQ(i, Log2Floor(value + 2));
+    EXPECT_EQ(i - 1, Log2Floor(value - 1));
+    EXPECT_EQ(i - 1, Log2Floor(value - 2));
+  }
+  EXPECT_EQ(31, Log2Floor(0xffffffffU));
+}
+
+TEST(BitsTest, Log2Ceiling) {
+  EXPECT_EQ(-1, Log2Ceiling(0));
+  EXPECT_EQ(0, Log2Ceiling(1));
+  EXPECT_EQ(1, Log2Ceiling(2));
+  EXPECT_EQ(2, Log2Ceiling(3));
+  EXPECT_EQ(2, Log2Ceiling(4));
+  for (int i = 3; i < 31; ++i) {
+    unsigned int value = 1U << i;
+    EXPECT_EQ(i, Log2Ceiling(value));
+    EXPECT_EQ(i + 1, Log2Ceiling(value + 1));
+    EXPECT_EQ(i + 1, Log2Ceiling(value + 2));
+    EXPECT_EQ(i, Log2Ceiling(value - 1));
+    EXPECT_EQ(i, Log2Ceiling(value - 2));
+  }
+  EXPECT_EQ(32, Log2Ceiling(0xffffffffU));
+}
+
+}  // namespace bits
+}  // namespace base
diff --git a/base/build_time.cc b/base/build_time.cc
new file mode 100644
index 0000000..bb2274b
--- /dev/null
+++ b/base/build_time.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/build_time.h"
+
+#include "base/logging.h"
+#include "base/time.h"
+
+namespace base {
+
+Time GetBuildTime() {
+  Time integral_build_time;
+  // The format of __DATE__ and __TIME__ is specified by the ANSI C Standard,
+  // section 6.8.8.
+  //
+  // __DATE__ is exactly "Mmm DD YYYY".
+  // __TIME__ is exactly "hh:mm:ss".
+  const char kDateTime[] = __DATE__ " " __TIME__ " PST";
+  bool result = Time::FromString(kDateTime, &integral_build_time);
+  DCHECK(result);
+  return integral_build_time;
+}
+
+}  // namespace base
diff --git a/base/build_time.h b/base/build_time.h
new file mode 100644
index 0000000..e7bbb39
--- /dev/null
+++ b/base/build_time.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_BUILD_TIME_
+#define BASE_BUILD_TIME_
+
+#include "base/base_export.h"
+#include "base/time.h"
+
+namespace base {
+
+// GetBuildTime returns the time at which the current binary was built.
+//
+// This uses the __DATE__ and __TIME__ macros, which don't trigger a rebuild
+// when they change. However, official builds will always be rebuilt from
+// scratch.
+//
+// Also, since __TIME__ doesn't include a timezone, this value should only be
+// considered accurate to a day.
+Time BASE_EXPORT GetBuildTime();
+
+}  // namespace base
+
+#endif  // BASE_BUILD_TIME_
diff --git a/base/build_time_unittest.cc b/base/build_time_unittest.cc
new file mode 100644
index 0000000..399a53f
--- /dev/null
+++ b/base/build_time_unittest.cc
@@ -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.
+
+#include "base/build_time.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(BuildTime, DateLooksValid) {
+  char build_date[] = __DATE__;
+
+  EXPECT_EQ(11u, strlen(build_date));
+  EXPECT_EQ(' ', build_date[3]);
+  EXPECT_EQ(' ', build_date[6]);
+}
+
+TEST(BuildTime, TimeLooksValid) {
+  char build_time[] = __TIME__;
+
+  EXPECT_EQ(8u, strlen(build_time));
+  EXPECT_EQ(':', build_time[2]);
+  EXPECT_EQ(':', build_time[5]);
+}
+
+TEST(BuildTime, DoesntCrash) {
+  // Since __DATE__ isn't updated unless one does a clobber build, we can't
+  // really test the value returned by it, except to check that it doesn't
+  // crash.
+  base::GetBuildTime();
+}
diff --git a/base/callback.h b/base/callback.h
new file mode 100644
index 0000000..594c9d6
--- /dev/null
+++ b/base/callback.h
@@ -0,0 +1,760 @@
+// This file was GENERATED by command:
+//     pump.py callback.h.pump
+// DO NOT EDIT BY HAND!!!
+
+
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CALLBACK_H_
+#define BASE_CALLBACK_H_
+
+#include "base/callback_forward.h"
+#include "base/callback_internal.h"
+#include "base/template_util.h"
+
+// NOTE: Header files that do not require the full definition of Callback or
+// Closure should #include "base/callback_forward.h" instead of this file.
+
+// -----------------------------------------------------------------------------
+// Introduction
+// -----------------------------------------------------------------------------
+//
+// The templated Callback class is a generalized function object. Together
+// with the Bind() function in bind.h, they provide a type-safe method for
+// performing currying of arguments, and creating a "closure."
+//
+// In programming languages, a closure is a first-class function where all its
+// parameters have been bound (usually via currying).  Closures are well
+// suited for representing, and passing around a unit of delayed execution.
+// They are used in Chromium code to schedule tasks on different MessageLoops.
+//
+//
+// MEMORY MANAGEMENT AND PASSING
+//
+// The Callback objects themselves should be passed by const-reference, and
+// stored by copy. They internally store their state via a refcounted class
+// and thus do not need to be deleted.
+//
+// The reason to pass via a const-reference is to avoid unnecessary
+// AddRef/Release pairs to the internal state.
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for basic stuff
+// -----------------------------------------------------------------------------
+//
+// BINDING A BARE FUNCTION
+//
+//   int Return5() { return 5; }
+//   base::Callback<int(void)> func_cb = base::Bind(&Return5);
+//   LOG(INFO) << func_cb.Run();  // Prints 5.
+//
+// BINDING A CLASS METHOD
+//
+//   The first argument to bind is the member function to call, the second is
+//   the object on which to call it.
+//
+//   class Ref : public base::RefCountedThreadSafe<Ref> {
+//    public:
+//     int Foo() { return 3; }
+//     void PrintBye() { LOG(INFO) << "bye."; }
+//   };
+//   scoped_refptr<Ref> ref = new Ref();
+//   base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
+//   LOG(INFO) << ref_cb.Run();  // Prints out 3.
+//
+//   By default the object must support RefCounted or you will get a compiler
+//   error. If you're passing between threads, be sure it's
+//   RefCountedThreadSafe! See "Advanced binding of member functions" below if
+//   you don't want to use reference counting.
+//
+// RUNNING A CALLBACK
+//
+//   Callbacks can be run with their "Run" method, which has the same
+//   signature as the template argument to the callback.
+//
+//   void DoSomething(const base::Callback<void(int, std::string)>& callback) {
+//     callback.Run(5, "hello");
+//   }
+//
+//   Callbacks can be run more than once (they don't get deleted or marked when
+//   run). However, this precludes using base::Passed (see below).
+//
+//   void DoSomething(const base::Callback<double(double)>& callback) {
+//     double myresult = callback.Run(3.14159);
+//     myresult += callback.Run(2.71828);
+//   }
+//
+// PASSING UNBOUND INPUT PARAMETERS
+//
+//   Unbound parameters are specified at the time a callback is Run(). They are
+//   specified in the Callback template type:
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
+//   cb.Run(23, "hello, world");
+//
+// PASSING BOUND INPUT PARAMETERS
+//
+//   Bound parameters are specified when you create thee callback as arguments
+//   to Bind(). They will be passed to the function and the Run()ner of the
+//   callback doesn't see those values or even know that the function it's
+//   calling.
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
+//   cb.Run();
+//
+//   A callback with no unbound input parameters (base::Callback<void(void)>)
+//   is called a base::Closure. So we could have also written:
+//
+//   base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
+//
+//   When calling member functions, bound parameters just go after the object
+//   pointer.
+//
+//   base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");
+//
+// PARTIAL BINDING OF PARAMETERS
+//
+//   You can specify some parameters when you create the callback, and specify
+//   the rest when you execute the callback.
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);
+//   cb.Run("hello world");
+//
+//   When calling a function bound parameters are first, followed by unbound
+//   parameters.
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for advanced binding
+// -----------------------------------------------------------------------------
+//
+// BINDING A CLASS METHOD WITH WEAK POINTERS
+//
+//   base::Bind(&MyClass::Foo, GetWeakPtr());
+//
+//   The callback will not be issued if the object is destroyed at the time
+//   it's issued. DANGER: weak pointers are not threadsafe, so don't use this
+//   when passing between threads!
+//
+// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT
+//
+//   base::Bind(&MyClass::Foo, base::Unretained(this));
+//
+//   This disables all lifetime management on the object. You're responsible
+//   for making sure the object is alive at the time of the call. You break it,
+//   you own it!
+//
+// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS
+//
+//   MyClass* myclass = new MyClass;
+//   base::Bind(&MyClass::Foo, base::Owned(myclass));
+//
+//   The object will be deleted when the callback is destroyed, even if it's
+//   not run (like if you post a task during shutdown). Potentially useful for
+//   "fire and forget" cases.
+//
+// IGNORING RETURN VALUES
+//
+//   Sometimes you want to call a function that returns a value in a callback
+//   that doesn't expect a return value.
+//
+//   int DoSomething(int arg) { cout << arg << endl; }
+//   base::Callback<void<int>) cb =
+//       base::Bind(base::IgnoreResult(&DoSomething));
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for binding parameters to Bind()
+// -----------------------------------------------------------------------------
+//
+// Bound parameters are specified as arguments to Bind() and are passed to the
+// function. A callback with no parameters or no unbound parameters is called a
+// Closure (base::Callback<void(void)> and base::Closure are the same thing).
+//
+// PASSING PARAMETERS OWNED BY THE CALLBACK
+//
+//   void Foo(int* arg) { cout << *arg << endl; }
+//   int* pn = new int(1);
+//   base::Closure foo_callback = base::Bind(&foo, base::Owned(pn));
+//
+//   The parameter will be deleted when the callback is destroyed, even if it's
+//   not run (like if you post a task during shutdown).
+//
+// PASSING PARAMETERS AS A scoped_ptr
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) {}
+//   scoped_ptr<Foo> f(new Foo);
+//   // f becomes null during the following call.
+//   base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f));
+//
+//   Ownership of the parameter will be with the callback until the it is run,
+//   when ownership is passed to the callback function. This means the callback
+//   can only be run once. If the callback is never run, it will delete the
+//   object when it's destroyed.
+//
+// PASSING PARAMETERS AS A scoped_refptr
+//
+//   void TakesOneRef(scoped_refptr<Foo> arg) {}
+//   scoped_refptr<Foo> f(new Foo)
+//   base::Closure cb = base::Bind(&TakesOneRef, f);
+//
+//   This should "just work." The closure will take a reference as long as it
+//   is alive, and another reference will be taken for the called function.
+//
+// PASSING PARAMETERS BY REFERENCE
+//
+//   void foo(int arg) { cout << arg << endl }
+//   int n = 1;
+//   base::Closure has_ref = base::Bind(&foo, base::ConstRef(n));
+//   n = 2;
+//   has_ref.Run();  // Prints "2"
+//
+//   Normally parameters are copied in the closure. DANGER: ConstRef stores a
+//   const reference instead, referencing the original parameter. This means
+//   that you must ensure the object outlives the callback!
+//
+//
+// -----------------------------------------------------------------------------
+// Implementation notes
+// -----------------------------------------------------------------------------
+//
+// WHERE IS THIS DESIGN FROM:
+//
+// The design Callback and Bind is heavily influenced by C++'s
+// tr1::function/tr1::bind, and by the "Google Callback" system used inside
+// Google.
+//
+//
+// HOW THE IMPLEMENTATION WORKS:
+//
+// There are three main components to the system:
+//   1) The Callback classes.
+//   2) The Bind() functions.
+//   3) The arguments wrappers (e.g., Unretained() and ConstRef()).
+//
+// The Callback classes represent a generic function pointer. Internally,
+// it stores a refcounted piece of state that represents the target function
+// and all its bound parameters.  Each Callback specialization has a templated
+// constructor that takes an BindState<>*.  In the context of the constructor,
+// the static type of this BindState<> pointer uniquely identifies the
+// function it is representing, all its bound parameters, and a Run() method
+// that is capable of invoking the target.
+//
+// Callback's constructor takes the BindState<>* that has the full static type
+// and erases the target function type as well as the types of the bound
+// parameters.  It does this by storing a pointer to the specific Run()
+// function, and upcasting the state of BindState<>* to a
+// BindStateBase*. This is safe as long as this BindStateBase pointer
+// is only used with the stored Run() pointer.
+//
+// To BindState<> objects are created inside the Bind() functions.
+// These functions, along with a set of internal templates, are responsible for
+//
+//  - Unwrapping the function signature into return type, and parameters
+//  - Determining the number of parameters that are bound
+//  - Creating the BindState storing the bound parameters
+//  - Performing compile-time asserts to avoid error-prone behavior
+//  - Returning an Callback<> with an arity matching the number of unbound
+//    parameters and that knows the correct refcounting semantics for the
+//    target object if we are binding a method.
+//
+// The Bind functions do the above using type-inference, and template
+// specializations.
+//
+// By default Bind() will store copies of all bound parameters, and attempt
+// to refcount a target object if the function being bound is a class method.
+// These copies are created even if the function takes parameters as const
+// references. (Binding to non-const references is forbidden, see bind.h)
+//
+// To change this behavior, we introduce a set of argument wrappers
+// (e.g., Unretained(), and ConstRef()).  These are simple container templates
+// that are passed by value, and wrap a pointer to argument.  See the
+// file-level comment in base/bind_helpers.h for more info.
+//
+// These types are passed to the Unwrap() functions, and the MaybeRefcount()
+// functions respectively to modify the behavior of Bind().  The Unwrap()
+// and MaybeRefcount() functions change behavior by doing partial
+// specialization based on whether or not a parameter is a wrapper type.
+//
+// ConstRef() is similar to tr1::cref.  Unretained() is specific to Chromium.
+//
+//
+// WHY NOT TR1 FUNCTION/BIND?
+//
+// Direct use of tr1::function and tr1::bind was considered, but ultimately
+// rejected because of the number of copy constructors invocations involved
+// in the binding of arguments during construction, and the forwarding of
+// arguments during invocation.  These copies will no longer be an issue in
+// C++0x because C++0x will support rvalue reference allowing for the compiler
+// to avoid these copies.  However, waiting for C++0x is not an option.
+//
+// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
+// tr1::bind call itself will invoke a non-trivial copy constructor three times
+// for each bound parameter.  Also, each when passing a tr1::function, each
+// bound argument will be copied again.
+//
+// In addition to the copies taken at binding and invocation, copying a
+// tr1::function causes a copy to be made of all the bound parameters and
+// state.
+//
+// Furthermore, in Chromium, it is desirable for the Callback to take a
+// reference on a target object when representing a class method call.  This
+// is not supported by tr1.
+//
+// Lastly, tr1::function and tr1::bind has a more general and flexible API.
+// This includes things like argument reordering by use of
+// tr1::bind::placeholder, support for non-const reference parameters, and some
+// limited amount of subtyping of the tr1::function object (e.g.,
+// tr1::function<int(int)> is convertible to tr1::function<void(int)>).
+//
+// These are not features that are required in Chromium. Some of them, such as
+// allowing for reference parameters, and subtyping of functions, may actually
+// become a source of errors. Removing support for these features actually
+// allows for a simpler implementation, and a terser Currying API.
+//
+//
+// WHY NOT GOOGLE CALLBACKS?
+//
+// The Google callback system also does not support refcounting.  Furthermore,
+// its implementation has a number of strange edge cases with respect to type
+// conversion of its arguments.  In particular, the argument's constness must
+// at times match exactly the function signature, or the type-inference might
+// break.  Given the above, writing a custom solution was easier.
+//
+//
+// MISSING FUNCTIONALITY
+//  - Invoking the return of Bind.  Bind(&foo).Run() does not work;
+//  - Binding arrays to functions that take a non-const pointer.
+//    Example:
+//      void Foo(const char* ptr);
+//      void Bar(char* ptr);
+//      Bind(&Foo, "test");
+//      Bind(&Bar, "test");  // This fails because ptr is not const.
+
+namespace base {
+
+// First, we forward declare the Callback class template. This informs the
+// compiler that the template only has 1 type parameter which is the function
+// signature that the Callback is representing.
+//
+// After this, create template specializations for 0-7 parameters. Note that
+// even though the template typelist grows, the specialization still
+// only has one type: the function signature.
+//
+// If you are thinking of forward declaring Callback in your own header file,
+// please include "base/callback_forward.h" instead.
+template <typename Sig>
+class Callback;
+
+namespace internal {
+template <typename Runnable, typename RunType, typename BoundArgsType>
+struct BindState;
+}  // namespace internal
+
+template <typename R>
+class Callback<R(void)> : public internal::CallbackBase {
+ public:
+  typedef R(RunType)();
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run() const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get());
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*);
+
+};
+
+template <typename R, typename A1>
+class Callback<R(A1)> : public internal::CallbackBase {
+ public:
+  typedef R(RunType)(A1);
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1) const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get(), internal::CallbackForward(a1));
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*,
+          typename internal::CallbackParamTraits<A1>::ForwardType);
+
+};
+
+template <typename R, typename A1, typename A2>
+class Callback<R(A1, A2)> : public internal::CallbackBase {
+ public:
+  typedef R(RunType)(A1, A2);
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
+        typename internal::CallbackParamTraits<A2>::ForwardType a2) const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get(), internal::CallbackForward(a1),
+             internal::CallbackForward(a2));
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*,
+          typename internal::CallbackParamTraits<A1>::ForwardType,
+          typename internal::CallbackParamTraits<A2>::ForwardType);
+
+};
+
+template <typename R, typename A1, typename A2, typename A3>
+class Callback<R(A1, A2, A3)> : public internal::CallbackBase {
+ public:
+  typedef R(RunType)(A1, A2, A3);
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
+        typename internal::CallbackParamTraits<A2>::ForwardType a2,
+        typename internal::CallbackParamTraits<A3>::ForwardType a3) const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get(), internal::CallbackForward(a1),
+             internal::CallbackForward(a2),
+             internal::CallbackForward(a3));
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*,
+          typename internal::CallbackParamTraits<A1>::ForwardType,
+          typename internal::CallbackParamTraits<A2>::ForwardType,
+          typename internal::CallbackParamTraits<A3>::ForwardType);
+
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase {
+ public:
+  typedef R(RunType)(A1, A2, A3, A4);
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
+        typename internal::CallbackParamTraits<A2>::ForwardType a2,
+        typename internal::CallbackParamTraits<A3>::ForwardType a3,
+        typename internal::CallbackParamTraits<A4>::ForwardType a4) const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get(), internal::CallbackForward(a1),
+             internal::CallbackForward(a2),
+             internal::CallbackForward(a3),
+             internal::CallbackForward(a4));
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*,
+          typename internal::CallbackParamTraits<A1>::ForwardType,
+          typename internal::CallbackParamTraits<A2>::ForwardType,
+          typename internal::CallbackParamTraits<A3>::ForwardType,
+          typename internal::CallbackParamTraits<A4>::ForwardType);
+
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5>
+class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase {
+ public:
+  typedef R(RunType)(A1, A2, A3, A4, A5);
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
+        typename internal::CallbackParamTraits<A2>::ForwardType a2,
+        typename internal::CallbackParamTraits<A3>::ForwardType a3,
+        typename internal::CallbackParamTraits<A4>::ForwardType a4,
+        typename internal::CallbackParamTraits<A5>::ForwardType a5) const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get(), internal::CallbackForward(a1),
+             internal::CallbackForward(a2),
+             internal::CallbackForward(a3),
+             internal::CallbackForward(a4),
+             internal::CallbackForward(a5));
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*,
+          typename internal::CallbackParamTraits<A1>::ForwardType,
+          typename internal::CallbackParamTraits<A2>::ForwardType,
+          typename internal::CallbackParamTraits<A3>::ForwardType,
+          typename internal::CallbackParamTraits<A4>::ForwardType,
+          typename internal::CallbackParamTraits<A5>::ForwardType);
+
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6>
+class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase {
+ public:
+  typedef R(RunType)(A1, A2, A3, A4, A5, A6);
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
+        typename internal::CallbackParamTraits<A2>::ForwardType a2,
+        typename internal::CallbackParamTraits<A3>::ForwardType a3,
+        typename internal::CallbackParamTraits<A4>::ForwardType a4,
+        typename internal::CallbackParamTraits<A5>::ForwardType a5,
+        typename internal::CallbackParamTraits<A6>::ForwardType a6) const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get(), internal::CallbackForward(a1),
+             internal::CallbackForward(a2),
+             internal::CallbackForward(a3),
+             internal::CallbackForward(a4),
+             internal::CallbackForward(a5),
+             internal::CallbackForward(a6));
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*,
+          typename internal::CallbackParamTraits<A1>::ForwardType,
+          typename internal::CallbackParamTraits<A2>::ForwardType,
+          typename internal::CallbackParamTraits<A3>::ForwardType,
+          typename internal::CallbackParamTraits<A4>::ForwardType,
+          typename internal::CallbackParamTraits<A5>::ForwardType,
+          typename internal::CallbackParamTraits<A6>::ForwardType);
+
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+    typename A5, typename A6, typename A7>
+class Callback<R(A1, A2, A3, A4, A5, A6, A7)> : public internal::CallbackBase {
+ public:
+  typedef R(RunType)(A1, A2, A3, A4, A5, A6, A7);
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
+        typename internal::CallbackParamTraits<A2>::ForwardType a2,
+        typename internal::CallbackParamTraits<A3>::ForwardType a3,
+        typename internal::CallbackParamTraits<A4>::ForwardType a4,
+        typename internal::CallbackParamTraits<A5>::ForwardType a5,
+        typename internal::CallbackParamTraits<A6>::ForwardType a6,
+        typename internal::CallbackParamTraits<A7>::ForwardType a7) const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get(), internal::CallbackForward(a1),
+             internal::CallbackForward(a2),
+             internal::CallbackForward(a3),
+             internal::CallbackForward(a4),
+             internal::CallbackForward(a5),
+             internal::CallbackForward(a6),
+             internal::CallbackForward(a7));
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*,
+          typename internal::CallbackParamTraits<A1>::ForwardType,
+          typename internal::CallbackParamTraits<A2>::ForwardType,
+          typename internal::CallbackParamTraits<A3>::ForwardType,
+          typename internal::CallbackParamTraits<A4>::ForwardType,
+          typename internal::CallbackParamTraits<A5>::ForwardType,
+          typename internal::CallbackParamTraits<A6>::ForwardType,
+          typename internal::CallbackParamTraits<A7>::ForwardType);
+
+};
+
+
+// Syntactic sugar to make Callbacks<void(void)> easier to declare since it
+// will be used in a lot of APIs with delayed execution.
+typedef Callback<void(void)> Closure;
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_H
diff --git a/base/callback.h.pump b/base/callback.h.pump
new file mode 100644
index 0000000..e236254
--- /dev/null
+++ b/base/callback.h.pump
@@ -0,0 +1,429 @@
+$$ This is a pump file for generating file templates.  Pump is a python
+$$ script that is part of the Google Test suite of utilities.  Description
+$$ can be found here:
+$$
+$$ http://code.google.com/p/googletest/wiki/PumpManual
+$$
+
+$$ See comment for MAX_ARITY in base/bind.h.pump.
+$var MAX_ARITY = 7
+
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CALLBACK_H_
+#define BASE_CALLBACK_H_
+
+#include "base/callback_forward.h"
+#include "base/callback_internal.h"
+#include "base/template_util.h"
+
+// NOTE: Header files that do not require the full definition of Callback or
+// Closure should #include "base/callback_forward.h" instead of this file.
+
+// -----------------------------------------------------------------------------
+// Introduction
+// -----------------------------------------------------------------------------
+//
+// The templated Callback class is a generalized function object. Together
+// with the Bind() function in bind.h, they provide a type-safe method for
+// performing currying of arguments, and creating a "closure."
+//
+// In programming languages, a closure is a first-class function where all its
+// parameters have been bound (usually via currying).  Closures are well
+// suited for representing, and passing around a unit of delayed execution.
+// They are used in Chromium code to schedule tasks on different MessageLoops.
+//
+//
+// MEMORY MANAGEMENT AND PASSING
+//
+// The Callback objects themselves should be passed by const-reference, and
+// stored by copy. They internally store their state via a refcounted class
+// and thus do not need to be deleted.
+//
+// The reason to pass via a const-reference is to avoid unnecessary
+// AddRef/Release pairs to the internal state.
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for basic stuff
+// -----------------------------------------------------------------------------
+//
+// BINDING A BARE FUNCTION
+//
+//   int Return5() { return 5; }
+//   base::Callback<int(void)> func_cb = base::Bind(&Return5);
+//   LOG(INFO) << func_cb.Run();  // Prints 5.
+//
+// BINDING A CLASS METHOD
+//
+//   The first argument to bind is the member function to call, the second is
+//   the object on which to call it.
+//
+//   class Ref : public base::RefCountedThreadSafe<Ref> {
+//    public:
+//     int Foo() { return 3; }
+//     void PrintBye() { LOG(INFO) << "bye."; }
+//   };
+//   scoped_refptr<Ref> ref = new Ref();
+//   base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
+//   LOG(INFO) << ref_cb.Run();  // Prints out 3.
+//
+//   By default the object must support RefCounted or you will get a compiler
+//   error. If you're passing between threads, be sure it's
+//   RefCountedThreadSafe! See "Advanced binding of member functions" below if
+//   you don't want to use reference counting.
+//
+// RUNNING A CALLBACK
+//
+//   Callbacks can be run with their "Run" method, which has the same
+//   signature as the template argument to the callback.
+//
+//   void DoSomething(const base::Callback<void(int, std::string)>& callback) {
+//     callback.Run(5, "hello");
+//   }
+//
+//   Callbacks can be run more than once (they don't get deleted or marked when
+//   run). However, this precludes using base::Passed (see below).
+//
+//   void DoSomething(const base::Callback<double(double)>& callback) {
+//     double myresult = callback.Run(3.14159);
+//     myresult += callback.Run(2.71828);
+//   }
+//
+// PASSING UNBOUND INPUT PARAMETERS
+//
+//   Unbound parameters are specified at the time a callback is Run(). They are
+//   specified in the Callback template type:
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
+//   cb.Run(23, "hello, world");
+//
+// PASSING BOUND INPUT PARAMETERS
+//
+//   Bound parameters are specified when you create thee callback as arguments
+//   to Bind(). They will be passed to the function and the Run()ner of the
+//   callback doesn't see those values or even know that the function it's
+//   calling.
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
+//   cb.Run();
+//
+//   A callback with no unbound input parameters (base::Callback<void(void)>)
+//   is called a base::Closure. So we could have also written:
+//
+//   base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
+//
+//   When calling member functions, bound parameters just go after the object
+//   pointer.
+//
+//   base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");
+//
+// PARTIAL BINDING OF PARAMETERS
+//
+//   You can specify some parameters when you create the callback, and specify
+//   the rest when you execute the callback.
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);
+//   cb.Run("hello world");
+//
+//   When calling a function bound parameters are first, followed by unbound
+//   parameters.
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for advanced binding
+// -----------------------------------------------------------------------------
+//
+// BINDING A CLASS METHOD WITH WEAK POINTERS
+//
+//   base::Bind(&MyClass::Foo, GetWeakPtr());
+//
+//   The callback will not be issued if the object is destroyed at the time
+//   it's issued. DANGER: weak pointers are not threadsafe, so don't use this
+//   when passing between threads!
+//
+// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT
+//
+//   base::Bind(&MyClass::Foo, base::Unretained(this));
+//
+//   This disables all lifetime management on the object. You're responsible
+//   for making sure the object is alive at the time of the call. You break it,
+//   you own it!
+//
+// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS
+//
+//   MyClass* myclass = new MyClass;
+//   base::Bind(&MyClass::Foo, base::Owned(myclass));
+//
+//   The object will be deleted when the callback is destroyed, even if it's
+//   not run (like if you post a task during shutdown). Potentially useful for
+//   "fire and forget" cases.
+//
+// IGNORING RETURN VALUES
+//
+//   Sometimes you want to call a function that returns a value in a callback
+//   that doesn't expect a return value.
+//
+//   int DoSomething(int arg) { cout << arg << endl; }
+//   base::Callback<void<int>) cb =
+//       base::Bind(base::IgnoreResult(&DoSomething));
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for binding parameters to Bind()
+// -----------------------------------------------------------------------------
+//
+// Bound parameters are specified as arguments to Bind() and are passed to the
+// function. A callback with no parameters or no unbound parameters is called a
+// Closure (base::Callback<void(void)> and base::Closure are the same thing).
+//
+// PASSING PARAMETERS OWNED BY THE CALLBACK
+//
+//   void Foo(int* arg) { cout << *arg << endl; }
+//   int* pn = new int(1);
+//   base::Closure foo_callback = base::Bind(&foo, base::Owned(pn));
+//
+//   The parameter will be deleted when the callback is destroyed, even if it's
+//   not run (like if you post a task during shutdown).
+//
+// PASSING PARAMETERS AS A scoped_ptr
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) {}
+//   scoped_ptr<Foo> f(new Foo);
+//   // f becomes null during the following call.
+//   base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f));
+//
+//   Ownership of the parameter will be with the callback until the it is run,
+//   when ownership is passed to the callback function. This means the callback
+//   can only be run once. If the callback is never run, it will delete the
+//   object when it's destroyed.
+//
+// PASSING PARAMETERS AS A scoped_refptr
+//
+//   void TakesOneRef(scoped_refptr<Foo> arg) {}
+//   scoped_refptr<Foo> f(new Foo)
+//   base::Closure cb = base::Bind(&TakesOneRef, f);
+//
+//   This should "just work." The closure will take a reference as long as it
+//   is alive, and another reference will be taken for the called function.
+//
+// PASSING PARAMETERS BY REFERENCE
+//
+//   void foo(int arg) { cout << arg << endl }
+//   int n = 1;
+//   base::Closure has_ref = base::Bind(&foo, base::ConstRef(n));
+//   n = 2;
+//   has_ref.Run();  // Prints "2"
+//
+//   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.
+//
+// To change this behavior, we introduce a set of argument wrappers
+// (e.g., Unretained(), and ConstRef()).  These are simple container templates
+// that are passed by value, and wrap a pointer to argument.  See the
+// file-level comment in base/bind_helpers.h for more info.
+//
+// These types are passed to the Unwrap() functions, and the MaybeRefcount()
+// functions respectively to modify the behavior of Bind().  The Unwrap()
+// and MaybeRefcount() functions change behavior by doing partial
+// specialization based on whether or not a parameter is a wrapper type.
+//
+// ConstRef() is similar to tr1::cref.  Unretained() is specific to Chromium.
+//
+//
+// WHY NOT TR1 FUNCTION/BIND?
+//
+// Direct use of tr1::function and tr1::bind was considered, but ultimately
+// rejected because of the number of copy constructors invocations involved
+// in the binding of arguments during construction, and the forwarding of
+// arguments during invocation.  These copies will no longer be an issue in
+// C++0x because C++0x will support rvalue reference allowing for the compiler
+// to avoid these copies.  However, waiting for C++0x is not an option.
+//
+// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
+// tr1::bind call itself will invoke a non-trivial copy constructor three times
+// for each bound parameter.  Also, each when passing a tr1::function, each
+// bound argument will be copied again.
+//
+// In addition to the copies taken at binding and invocation, copying a
+// tr1::function causes a copy to be made of all the bound parameters and
+// state.
+//
+// Furthermore, in Chromium, it is desirable for the Callback to take a
+// reference on a target object when representing a class method call.  This
+// is not supported by tr1.
+//
+// Lastly, tr1::function and tr1::bind has a more general and flexible API.
+// This includes things like argument reordering by use of
+// tr1::bind::placeholder, support for non-const reference parameters, and some
+// limited amount of subtyping of the tr1::function object (e.g.,
+// tr1::function<int(int)> is convertible to tr1::function<void(int)>).
+//
+// These are not features that are required in Chromium. Some of them, such as
+// allowing for reference parameters, and subtyping of functions, may actually
+// become a source of errors. Removing support for these features actually
+// allows for a simpler implementation, and a terser Currying API.
+//
+//
+// WHY NOT GOOGLE CALLBACKS?
+//
+// The Google callback system also does not support refcounting.  Furthermore,
+// its implementation has a number of strange edge cases with respect to type
+// conversion of its arguments.  In particular, the argument's constness must
+// at times match exactly the function signature, or the type-inference might
+// break.  Given the above, writing a custom solution was easier.
+//
+//
+// MISSING FUNCTIONALITY
+//  - Invoking the return of Bind.  Bind(&foo).Run() does not work;
+//  - Binding arrays to functions that take a non-const pointer.
+//    Example:
+//      void Foo(const char* ptr);
+//      void Bar(char* ptr);
+//      Bind(&Foo, "test");
+//      Bind(&Bar, "test");  // This fails because ptr is not const.
+
+namespace base {
+
+// First, we forward declare the Callback class template. This informs the
+// compiler that the template only has 1 type parameter which is the function
+// signature that the Callback is representing.
+//
+// After this, create template specializations for 0-$(MAX_ARITY) parameters. Note that
+// even though the template typelist grows, the specialization still
+// only has one type: the function signature.
+//
+// If you are thinking of forward declaring Callback in your own header file,
+// please include "base/callback_forward.h" instead.
+template <typename Sig>
+class Callback;
+
+namespace internal {
+template <typename Runnable, typename RunType, typename BoundArgsType>
+struct BindState;
+}  // namespace internal
+
+
+$range ARITY 0..MAX_ARITY
+$for ARITY [[
+$range ARG 1..ARITY
+
+$if ARITY == 0 [[
+template <typename R>
+class Callback<R(void)> : public internal::CallbackBase {
+]] $else [[
+template <typename R, $for ARG , [[typename A$(ARG)]]>
+class Callback<R($for ARG , [[A$(ARG)]])> : public internal::CallbackBase {
+]]
+
+ public:
+  typedef R(RunType)($for ARG , [[A$(ARG)]]);
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run($for ARG ,
+        [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get()[[]]
+$if ARITY != 0 [[, ]]
+$for ARG ,
+             [[internal::CallbackForward(a$(ARG))]]);
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*[[]]
+$if ARITY != 0 [[, ]]
+$for ARG , [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType]]);
+
+};
+
+
+]]  $$ for ARITY
+
+// Syntactic sugar to make Callbacks<void(void)> easier to declare since it
+// will be used in a lot of APIs with delayed execution.
+typedef Callback<void(void)> Closure;
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_H
diff --git a/base/callback_forward.h b/base/callback_forward.h
new file mode 100644
index 0000000..7983248
--- /dev/null
+++ b/base/callback_forward.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CALLBACK_FORWARD_H_
+#define BASE_CALLBACK_FORWARD_H_
+
+namespace base {
+
+template <typename Sig>
+class Callback;
+
+typedef Callback<void(void)> Closure;
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_FORWARD_H
diff --git a/base/callback_helpers.h b/base/callback_helpers.h
new file mode 100644
index 0000000..52cb71b
--- /dev/null
+++ b/base/callback_helpers.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// 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"
+
+namespace base {
+
+template <typename Sig>
+base::Callback<Sig> ResetAndReturn(base::Callback<Sig>* cb) {
+  base::Callback<Sig> ret(*cb);
+  cb->Reset();
+  return ret;
+}
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_HELPERS_H_
diff --git a/base/callback_internal.cc b/base/callback_internal.cc
new file mode 100644
index 0000000..2dde402
--- /dev/null
+++ b/base/callback_internal.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/callback_internal.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace internal {
+
+bool CallbackBase::is_null() const {
+  return bind_state_.get() == NULL;
+}
+
+void CallbackBase::Reset() {
+  polymorphic_invoke_ = NULL;
+  // NULL the bind_state_ last, since it may be holding the last ref to whatever
+  // object owns us, and we may be deleted after that.
+  bind_state_ = NULL;
+}
+
+bool CallbackBase::Equals(const CallbackBase& other) const {
+  return bind_state_.get() == other.bind_state_.get() &&
+         polymorphic_invoke_ == other.polymorphic_invoke_;
+}
+
+CallbackBase::CallbackBase(BindStateBase* bind_state)
+    : bind_state_(bind_state),
+      polymorphic_invoke_(NULL) {
+  DCHECK(!bind_state_ || bind_state_->HasOneRef());
+}
+
+CallbackBase::~CallbackBase() {
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/callback_internal.h b/base/callback_internal.h
new file mode 100644
index 0000000..2f834c3
--- /dev/null
+++ b/base/callback_internal.h
@@ -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.
+
+// This file contains utility functions and classes that help the
+// implementation, and management of the Callback objects.
+
+#ifndef BASE_CALLBACK_INTERNAL_H_
+#define BASE_CALLBACK_INTERNAL_H_
+
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+
+template <typename T>
+class ScopedVector;
+
+namespace base {
+namespace internal {
+
+// 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."
+class BindStateBase : public RefCountedThreadSafe<BindStateBase> {
+ protected:
+  friend class RefCountedThreadSafe<BindStateBase>;
+  virtual ~BindStateBase() {}
+};
+
+// Holds the Callback methods that don't require specialization to reduce
+// template bloat.
+class BASE_EXPORT CallbackBase {
+ public:
+  // Returns true if Callback is null (doesn't refer to anything).
+  bool is_null() const;
+
+  // Returns the Callback into an uninitialized state.
+  void Reset();
+
+ protected:
+  // In C++, it is safe to cast function pointers to function pointers of
+  // another type. It is not okay to use void*. We create a InvokeFuncStorage
+  // that that can store our function pointer, and then cast it back to
+  // the original type on usage.
+  typedef void(*InvokeFuncStorage)(void);
+
+  // Returns true if this callback equals |other|. |other| may be null.
+  bool Equals(const CallbackBase& other) const;
+
+  // Allow initializing of |bind_state_| via the constructor to avoid default
+  // initialization of the scoped_refptr.  We do not also initialize
+  // |polymorphic_invoke_| here because doing a normal assignment in the
+  // derived Callback templates makes for much nicer compiler errors.
+  explicit CallbackBase(BindStateBase* bind_state);
+
+  // Force the destructor to be instantiated inside this translation unit so
+  // that our subclasses will not get inlined versions.  Avoids more template
+  // bloat.
+  ~CallbackBase();
+
+  scoped_refptr<BindStateBase> bind_state_;
+  InvokeFuncStorage polymorphic_invoke_;
+};
+
+// This is a typetraits object that's used to take an argument type, and
+// extract a suitable type for storing and forwarding arguments.
+//
+// In particular, it strips off references, and converts arrays to
+// pointers for storage; and it avoids accidentally trying to create a
+// "reference of a reference" if the argument is a reference type.
+//
+// This array type becomes an issue for storage because we are passing bound
+// parameters by const reference. In this case, we end up passing an actual
+// array type in the initializer list which C++ does not allow.  This will
+// break passing of C-string literals.
+template <typename T>
+struct CallbackParamTraits {
+  typedef const T& ForwardType;
+  typedef T StorageType;
+};
+
+// The Storage should almost be impossible to trigger unless someone manually
+// specifies type of the bind parameters.  However, in case they do,
+// this will guard against us accidentally storing a reference parameter.
+//
+// The ForwardType should only be used for unbound arguments.
+template <typename T>
+struct CallbackParamTraits<T&> {
+  typedef T& ForwardType;
+  typedef T StorageType;
+};
+
+// Note that for array types, we implicitly add a const in the conversion. This
+// means that it is not possible to bind array arguments to functions that take
+// a non-const pointer. Trying to specialize the template based on a "const
+// T[n]" does not seem to match correctly, so we are stuck with this
+// restriction.
+template <typename T, size_t n>
+struct CallbackParamTraits<T[n]> {
+  typedef const T* ForwardType;
+  typedef const T* StorageType;
+};
+
+// See comment for CallbackParamTraits<T[n]>.
+template <typename T>
+struct CallbackParamTraits<T[]> {
+  typedef const T* ForwardType;
+  typedef const T* StorageType;
+};
+
+// Parameter traits for movable-but-not-copyable scopers.
+//
+// Callback<>/Bind() understands movable-but-not-copyable semantics where
+// the type cannot be copied but can still have its state destructively
+// transferred (aka. moved) to another instance of the same type by calling a
+// helper function.  When used with Bind(), this signifies transferal of the
+// object's state to the target function.
+//
+// For these types, the ForwardType must not be a const reference, or a
+// reference.  A const reference is inappropriate, and would break const
+// correctness, because we are implementing a destructive move.  A non-const
+// reference cannot be used with temporaries which means the result of a
+// function or a cast would not be usable with Callback<> or Bind().
+//
+// TODO(ajwong): We might be able to use SFINAE to search for the existence of
+// a Pass() function in the type and avoid the whitelist in CallbackParamTraits
+// and CallbackForward.
+template <typename T>
+struct CallbackParamTraits<scoped_ptr<T> > {
+  typedef scoped_ptr<T> ForwardType;
+  typedef scoped_ptr<T> StorageType;
+};
+
+template <typename T>
+struct CallbackParamTraits<scoped_array<T> > {
+  typedef scoped_array<T> ForwardType;
+  typedef scoped_array<T> StorageType;
+};
+
+template <typename T, typename R>
+struct CallbackParamTraits<scoped_ptr_malloc<T, R> > {
+  typedef scoped_ptr_malloc<T, R> ForwardType;
+  typedef scoped_ptr_malloc<T, R> StorageType;
+};
+
+template <typename T>
+struct CallbackParamTraits<ScopedVector<T> > {
+  typedef ScopedVector<T> ForwardType;
+  typedef ScopedVector<T> StorageType;
+};
+
+// CallbackForward() is a very limited simulation of C++11's std::forward()
+// used by the Callback/Bind system for a set of movable-but-not-copyable
+// types.  It is needed because forwarding a movable-but-not-copyable
+// argument to another function requires us to invoke the proper move
+// operator to create a rvalue version of the type.  The supported types are
+// whitelisted below as overloads of the CallbackForward() function. The
+// default template compiles out to be a no-op.
+//
+// In C++11, std::forward would replace all uses of this function.  However, it
+// is impossible to implement a general std::forward with C++11 due to a lack
+// of rvalue references.
+//
+// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
+// simulate std::forward() and forward the result of one Callback as a
+// parameter to another callback. This is to support Callbacks that return
+// the movable-but-not-copyable types whitelisted above.
+template <typename T>
+T& CallbackForward(T& t) { return t; }
+
+template <typename T>
+scoped_ptr<T> CallbackForward(scoped_ptr<T>& p) { return p.Pass(); }
+
+template <typename T>
+scoped_array<T> CallbackForward(scoped_array<T>& p) { return p.Pass(); }
+
+template <typename T, typename R>
+scoped_ptr_malloc<T, R> CallbackForward(scoped_ptr_malloc<T, R>& p) {
+  return p.Pass();
+}
+
+template <typename T>
+ScopedVector<T> CallbackForward(ScopedVector<T>& p) { return p.Pass(); }
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_CALLBACK_INTERNAL_H_
diff --git a/base/callback_unittest.cc b/base/callback_unittest.cc
new file mode 100644
index 0000000..2c2bef1
--- /dev/null
+++ b/base/callback_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/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/callback_internal.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+struct FakeInvoker {
+  typedef void(RunType)(internal::BindStateBase*);
+  static void Run(internal::BindStateBase*) {
+  }
+};
+
+}  // namespace
+
+namespace internal {
+template <typename Runnable, typename RunType, typename BoundArgsType>
+struct BindState;
+
+// White-box testpoints to inject into a Callback<> object for checking
+// comparators and emptiness APIs.  Use a BindState that is specialized
+// based on a type we declared in the anonymous namespace above to remove any
+// chance of colliding with another instantiation and breaking the
+// one-definition-rule.
+template <>
+struct BindState<void(void), void(void), void(FakeInvoker)>
+    : public BindStateBase {
+ public:
+  typedef FakeInvoker InvokerType;
+};
+
+template <>
+struct BindState<void(void), void(void),
+                           void(FakeInvoker, FakeInvoker)>
+    : public BindStateBase {
+ public:
+  typedef FakeInvoker InvokerType;
+};
+}  // namespace internal
+
+namespace {
+
+typedef internal::BindState<void(void), void(void), void(FakeInvoker)>
+    FakeBindState1;
+typedef internal::BindState<void(void), void(void),
+                            void(FakeInvoker, FakeInvoker)>
+   FakeBindState2;
+
+class CallbackTest : public ::testing::Test {
+ public:
+  CallbackTest()
+      : callback_a_(new FakeBindState1()),
+        callback_b_(new FakeBindState2()) {
+  }
+
+  virtual ~CallbackTest() {
+  }
+
+ protected:
+  Callback<void(void)> callback_a_;
+  const Callback<void(void)> callback_b_;  // Ensure APIs work with const.
+  Callback<void(void)> null_callback_;
+};
+
+// Ensure we can create unbound callbacks. We need this to be able to store
+// them in class members that can be initialized later.
+TEST_F(CallbackTest, DefaultConstruction) {
+  Callback<void(void)> c0;
+  Callback<void(int)> c1;
+  Callback<void(int,int)> c2;
+  Callback<void(int,int,int)> c3;
+  Callback<void(int,int,int,int)> c4;
+  Callback<void(int,int,int,int,int)> c5;
+  Callback<void(int,int,int,int,int,int)> c6;
+
+  EXPECT_TRUE(c0.is_null());
+  EXPECT_TRUE(c1.is_null());
+  EXPECT_TRUE(c2.is_null());
+  EXPECT_TRUE(c3.is_null());
+  EXPECT_TRUE(c4.is_null());
+  EXPECT_TRUE(c5.is_null());
+  EXPECT_TRUE(c6.is_null());
+}
+
+TEST_F(CallbackTest, IsNull) {
+  EXPECT_TRUE(null_callback_.is_null());
+  EXPECT_FALSE(callback_a_.is_null());
+  EXPECT_FALSE(callback_b_.is_null());
+}
+
+TEST_F(CallbackTest, Equals) {
+  EXPECT_TRUE(callback_a_.Equals(callback_a_));
+  EXPECT_FALSE(callback_a_.Equals(callback_b_));
+  EXPECT_FALSE(callback_b_.Equals(callback_a_));
+
+  // We should compare based on instance, not type.
+  Callback<void(void)> callback_c(new FakeBindState1());
+  Callback<void(void)> callback_a2 = callback_a_;
+  EXPECT_TRUE(callback_a_.Equals(callback_a2));
+  EXPECT_FALSE(callback_a_.Equals(callback_c));
+
+  // Empty, however, is always equal to empty.
+  Callback<void(void)> empty2;
+  EXPECT_TRUE(null_callback_.Equals(empty2));
+}
+
+TEST_F(CallbackTest, Reset) {
+  // Resetting should bring us back to empty.
+  ASSERT_FALSE(callback_a_.is_null());
+  ASSERT_FALSE(callback_a_.Equals(null_callback_));
+
+  callback_a_.Reset();
+
+  EXPECT_TRUE(callback_a_.is_null());
+  EXPECT_TRUE(callback_a_.Equals(null_callback_));
+}
+
+struct TestForReentrancy {
+  TestForReentrancy()
+      : cb_already_run(false),
+        cb(Bind(&TestForReentrancy::AssertCBIsNull, Unretained(this))) {
+  }
+  void AssertCBIsNull() {
+    ASSERT_TRUE(cb.is_null());
+    cb_already_run = true;
+  }
+  bool cb_already_run;
+  Closure cb;
+};
+
+TEST_F(CallbackTest, ResetAndReturn) {
+  TestForReentrancy tfr;
+  ASSERT_FALSE(tfr.cb.is_null());
+  ASSERT_FALSE(tfr.cb_already_run);
+  ResetAndReturn(&tfr.cb).Run();
+  ASSERT_TRUE(tfr.cb.is_null());
+  ASSERT_TRUE(tfr.cb_already_run);
+}
+
+class CallbackOwner : public base::RefCounted<CallbackOwner> {
+ public:
+  CallbackOwner(bool* deleted) {
+    callback_ = Bind(&CallbackOwner::Unused, this);
+    deleted_ = deleted;
+  }
+  void Reset() {
+    callback_.Reset();
+    // We are deleted here if no-one else had a ref to us.
+  }
+
+ private:
+  friend class base::RefCounted<CallbackOwner>;
+  virtual ~CallbackOwner() {
+    *deleted_ = true;
+  }
+  void Unused() {
+    FAIL() << "Should never be called";
+  }
+
+  Closure callback_;
+  bool* deleted_;
+};
+
+TEST_F(CallbackTest, CallbackHasLastRefOnContainingObject) {
+  bool deleted = false;
+  CallbackOwner* owner = new CallbackOwner(&deleted);
+  owner->Reset();
+  ASSERT_TRUE(deleted);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/callback_unittest.nc b/base/callback_unittest.nc
new file mode 100644
index 0000000..9bddd1f
--- /dev/null
+++ b/base/callback_unittest.nc
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback.h"
+
+namespace base {
+
+class Parent {
+};
+
+class Child : Parent {
+};
+
+#if defined(NCTEST_EQUALS_REQUIRES_SAMETYPE)  // [r"no matching function for call to 'base::Callback<void\(\)>::Equals\(base::Callback<int\(\)>&\)'"]
+
+// Attempting to call comparison function on two callbacks of different type.
+//
+// This should be a compile time failure because each callback type should be
+// considered distinct.
+void WontCompile() {
+  Closure c1;
+  Callback<int(void)> c2;
+  c1.Equals(c2);
+}
+
+#elif defined(NCTEST_CONSTRUCTION_FROM_SUBTYPE)  // [r"conversion from 'base::Callback<base::Parent\(\)>' to non-scalar type 'base::Callback<base::Child\(\)>'"]
+
+// Construction of Callback<A> from Callback<B> if A is supertype of B.
+//
+// While this is technically safe, most people aren't used to it when coding
+// C++ so if this is happening, it is almost certainly an error.
+void WontCompile() {
+  Callback<Parent(void)> cb_a;
+  Callback<Child(void)> cb_b = cb_a;
+}
+
+#elif defined(NCTEST_ASSIGNMENT_FROM_SUBTYPE)  // [r"no match for 'operator=' in 'cb_a = cb_b'"]
+
+// Assignment of Callback<A> from Callback<B> if A is supertype of B.
+// See explanation for NCTEST_CONSTRUCTION_FROM_SUBTYPE
+void WontCompile() {
+  Callback<Parent(void)> cb_a;
+  Callback<Child(void)> cb_b;
+  cb_a = cb_b;
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/cancelable_callback.h b/base/cancelable_callback.h
new file mode 100644
index 0000000..b781677
--- /dev/null
+++ b/base/cancelable_callback.h
@@ -0,0 +1,202 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// 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 CancellableCallback::Cancel() brings the object back to its natural,
+// default-constructed state, i.e., CancellableCallback::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()->Quit();
+// }
+//
+// CancelableClosure timeout(base::Bind(&TimeoutCallback, "Test timed out."));
+// MessageLoop::current()->PostDelayedTask(FROM_HERE, timeout.callback(),
+//                                         4000)  // 4 seconds to run.
+// RunIntensiveTest();
+// MessageLoop::current()->Run();
+// timeout.Cancel();  // Hopefully this is hit before the timeout callback runs.
+//
+
+#ifndef BASE_CANCELABLE_CALLBACK_H_
+#define BASE_CANCELABLE_CALLBACK_H_
+
+#include "base/base_export.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_internal.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+
+namespace base {
+
+template <typename Sig>
+class CancelableCallback;
+
+template <>
+class CancelableCallback<void(void)> {
+ public:
+  CancelableCallback() : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {}
+
+  // |callback| must not be null.
+  explicit CancelableCallback(const base::Callback<void(void)>& callback)
+      : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
+        callback_(callback) {
+    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(void)>& 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(void)>& callback() const {
+    return forwarder_;
+  }
+
+ private:
+  void Forward() {
+    callback_.Run();
+  }
+
+  // Helper method to bind |forwarder_| using a weak pointer from
+  // |weak_factory_|.
+  void InitializeForwarder() {
+    forwarder_ = base::Bind(&CancelableCallback<void(void)>::Forward,
+                            weak_factory_.GetWeakPtr());
+  }
+
+  // Used to ensure Forward() is not run when this object is destroyed.
+  base::WeakPtrFactory<CancelableCallback<void(void)> > weak_factory_;
+
+  // The wrapper closure.
+  base::Callback<void(void)> forwarder_;
+
+  // The stored closure that may be cancelled.
+  base::Callback<void(void)> callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
+};
+
+template <typename A1>
+class CancelableCallback<void(A1)> {
+ public:
+  CancelableCallback() : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {}
+
+  // |callback| must not be null.
+  explicit CancelableCallback(const base::Callback<void(A1)>& callback)
+      : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
+        callback_(callback) {
+    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(A1)>& 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(A1)>& callback() const {
+    return forwarder_;
+  }
+
+ private:
+  void Forward(A1 a1) const {
+    callback_.Run(a1);
+  }
+
+  // Helper method to bind |forwarder_| using a weak pointer from
+  // |weak_factory_|.
+  void InitializeForwarder() {
+    forwarder_ = base::Bind(&CancelableCallback<void(A1)>::Forward,
+                            weak_factory_.GetWeakPtr());
+  }
+
+  // Used to ensure Forward() is not run when this object is destroyed.
+  base::WeakPtrFactory<CancelableCallback<void(A1)> > weak_factory_;
+
+  // The wrapper closure.
+  base::Callback<void(A1)> forwarder_;
+
+  // The stored closure that may be cancelled.
+  base::Callback<void(A1)> callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
+};
+
+typedef CancelableCallback<void(void)> CancelableClosure;
+
+}  // namespace base
+
+#endif  // BASE_CANCELABLE_CALLBACK_H_
diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc
new file mode 100644
index 0000000..51a2a09
--- /dev/null
+++ b/base/cancelable_callback_unittest.cc
@@ -0,0 +1,185 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/cancelable_callback.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> {
+ private:
+  friend class RefCountedThreadSafe<TestRefCounted>;
+  ~TestRefCounted() {};
+};
+
+void Increment(int* count) { (*count)++; }
+void IncrementBy(int* count, int n) { (*count) += n; }
+void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {}
+
+// Cancel().
+//  - Callback can be run multiple times.
+//  - After Cancel(), Run() completes but has no effect.
+TEST(CancelableCallbackTest, Cancel) {
+  int count = 0;
+  CancelableClosure cancelable(
+      base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure callback = cancelable.callback();
+  callback.Run();
+  EXPECT_EQ(1, count);
+
+  callback.Run();
+  EXPECT_EQ(2, count);
+
+  cancelable.Cancel();
+  callback.Run();
+  EXPECT_EQ(2, count);
+}
+
+// Cancel() called multiple times.
+//  - Cancel() cancels all copies of the wrapped callback.
+//  - Calling Cancel() more than once has no effect.
+//  - After Cancel(), callback() returns a null callback.
+TEST(CancelableCallbackTest, MultipleCancel) {
+  int count = 0;
+  CancelableClosure cancelable(
+      base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure callback1 = cancelable.callback();
+  base::Closure callback2 = cancelable.callback();
+  cancelable.Cancel();
+
+  callback1.Run();
+  EXPECT_EQ(0, count);
+
+  callback2.Run();
+  EXPECT_EQ(0, count);
+
+  // Calling Cancel() again has no effect.
+  cancelable.Cancel();
+
+  // callback() of a cancelled callback is null.
+  base::Closure callback3 = cancelable.callback();
+  EXPECT_TRUE(callback3.is_null());
+}
+
+// CancelableCallback destroyed before callback is run.
+//  - Destruction of CancelableCallback cancels outstanding callbacks.
+TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) {
+  int count = 0;
+  base::Closure callback;
+
+  {
+    CancelableClosure cancelable(
+        base::Bind(&Increment, base::Unretained(&count)));
+
+    callback = cancelable.callback();
+    callback.Run();
+    EXPECT_EQ(1, count);
+  }
+
+  callback.Run();
+  EXPECT_EQ(1, count);
+}
+
+// Cancel() called on bound closure with a RefCounted parameter.
+//  - Cancel drops wrapped callback (and, implicitly, its bound arguments).
+TEST(CancelableCallbackTest, CancelDropsCallback) {
+  scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted;
+  EXPECT_TRUE(ref_counted->HasOneRef());
+
+  CancelableClosure cancelable(base::Bind(RefCountedParam, ref_counted));
+  EXPECT_FALSE(cancelable.IsCancelled());
+  EXPECT_TRUE(ref_counted.get());
+  EXPECT_FALSE(ref_counted->HasOneRef());
+
+  // There is only one reference to |ref_counted| after the Cancel().
+  cancelable.Cancel();
+  EXPECT_TRUE(cancelable.IsCancelled());
+  EXPECT_TRUE(ref_counted.get());
+  EXPECT_TRUE(ref_counted->HasOneRef());
+}
+
+// Reset().
+//  - Reset() replaces the existing wrapped callback with a new callback.
+//  - Reset() deactivates outstanding callbacks.
+TEST(CancelableCallbackTest, Reset) {
+  int count = 0;
+  CancelableClosure cancelable(
+      base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure callback = cancelable.callback();
+  callback.Run();
+  EXPECT_EQ(1, count);
+
+  callback.Run();
+  EXPECT_EQ(2, count);
+
+  cancelable.Reset(
+      base::Bind(&IncrementBy, base::Unretained(&count), 3));
+  EXPECT_FALSE(cancelable.IsCancelled());
+
+  // The stale copy of the cancelable callback is non-null.
+  ASSERT_FALSE(callback.is_null());
+
+  // The stale copy of the cancelable callback is no longer active.
+  callback.Run();
+  EXPECT_EQ(2, count);
+
+  base::Closure callback2 = cancelable.callback();
+  ASSERT_FALSE(callback2.is_null());
+
+  callback2.Run();
+  EXPECT_EQ(5, count);
+}
+
+// IsCanceled().
+//  - Cancel() transforms the CancelableCallback into a cancelled state.
+TEST(CancelableCallbackTest, IsNull) {
+  CancelableClosure cancelable;
+  EXPECT_TRUE(cancelable.IsCancelled());
+
+  int count = 0;
+  cancelable.Reset(base::Bind(&Increment,
+                              base::Unretained(&count)));
+  EXPECT_FALSE(cancelable.IsCancelled());
+
+  cancelable.Cancel();
+  EXPECT_TRUE(cancelable.IsCancelled());
+}
+
+// CancelableCallback posted to a MessageLoop with PostTask.
+//  - Callbacks posted to a MessageLoop can be cancelled.
+TEST(CancelableCallbackTest, PostTask) {
+  MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+
+  int count = 0;
+  CancelableClosure cancelable(base::Bind(&Increment,
+                                           base::Unretained(&count)));
+
+  MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback());
+  MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(1, count);
+
+  MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback());
+  MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+
+  // Cancel before running the message loop.
+  cancelable.Cancel();
+  MessageLoop::current()->Run();
+
+  // Callback never ran due to cancellation; count is the same.
+  EXPECT_EQ(1, count);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/check_example.cc b/base/check_example.cc
new file mode 100644
index 0000000..4b3f428
--- /dev/null
+++ b/base/check_example.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is meant for analyzing the code generated by the CHECK
+// macros in a small executable file that's easy to disassemble.
+
+#include "base/logging.h"
+
+// An official build shouldn't generate code to print out messages for
+// the CHECK* macros, nor should it have the strings in the
+// executable.
+
+void DoCheck(bool b) {
+  CHECK(b) << "DoCheck " << b;
+}
+
+void DoCheckEq(int x, int y) {
+  CHECK_EQ(x, y);
+}
+
+int main(int argc, const char* argv[]) {
+  DoCheck(argc > 1);
+  DoCheckEq(argc, 1);
+}
diff --git a/base/chromeos/chromeos_version.cc b/base/chromeos/chromeos_version.cc
new file mode 100644
index 0000000..4a70cd5
--- /dev/null
+++ b/base/chromeos/chromeos_version.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/chromeos/chromeos_version.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace chromeos {
+
+bool IsRunningOnChromeOS() {
+  // Check if the user name is chronos. Note that we don't go with
+  // getuid() + getpwuid_r() as it may end up reading /etc/passwd, which
+  // can be expensive.
+  const char* user = getenv("USER");
+  return user && strcmp(user, "chronos") == 0;
+}
+
+}  // namespace chromeos
+}  // namespace base
diff --git a/base/chromeos/chromeos_version.h b/base/chromeos/chromeos_version.h
new file mode 100644
index 0000000..25acd43
--- /dev/null
+++ b/base/chromeos/chromeos_version.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CHROMEOS_CHROMEOS_VERSION_H_
+#define BASE_CHROMEOS_CHROMEOS_VERSION_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace chromeos {
+
+// Returns true if the browser is running on Chrome OS.
+// Useful for implementing stubs for Linux desktop.
+BASE_EXPORT bool IsRunningOnChromeOS();
+
+}  // namespace chromeos
+}  // namespace base
+
+#endif  // BASE_CHROMEOS_CHROMEOS_VERSION_H_
diff --git a/base/command_line.cc b/base/command_line.cc
new file mode 100644
index 0000000..f4553ea
--- /dev/null
+++ b/base/command_line.cc
@@ -0,0 +1,416 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+
+#include <algorithm>
+#include <ostream>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <shellapi.h>
+#endif
+
+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)
+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 GetSwitchPrefixLength(const CommandLine::StringType& string) {
+  for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
+    CommandLine::StringType prefix(kSwitchPrefixes[i]);
+    if (string.compare(0, prefix.length(), prefix) == 0)
+      return prefix.length();
+  }
+  return 0;
+}
+
+// Fills in |switch_string| and |switch_value| if |string| is a switch.
+// This will preserve the input switch prefix in the output |switch_string|.
+bool IsSwitch(const CommandLine::StringType& string,
+              CommandLine::StringType* switch_string,
+              CommandLine::StringType* switch_value) {
+  switch_string->clear();
+  switch_value->clear();
+  size_t prefix_length = GetSwitchPrefixLength(string);
+  if (prefix_length == 0 || prefix_length == string.length())
+    return false;
+
+  const size_t equals_position = string.find(kSwitchValueSeparator);
+  *switch_string = string.substr(0, equals_position);
+  if (equals_position != CommandLine::StringType::npos)
+    *switch_value = string.substr(equals_position + 1);
+  return true;
+}
+
+// Append switches and arguments, keeping switches before arguments.
+void AppendSwitchesAndArguments(CommandLine& command_line,
+                                const CommandLine::StringVector& argv) {
+  bool parse_switches = true;
+  for (size_t i = 1; i < argv.size(); ++i) {
+    CommandLine::StringType arg = argv[i];
+    TrimWhitespace(arg, TRIM_ALL, &arg);
+
+    CommandLine::StringType switch_string;
+    CommandLine::StringType switch_value;
+    parse_switches &= (arg != kSwitchTerminator);
+    if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
+#if defined(OS_WIN)
+      command_line.AppendSwitchNative(WideToASCII(switch_string), switch_value);
+#elif defined(OS_POSIX)
+      command_line.AppendSwitchNative(switch_string, switch_value);
+#endif
+    } else {
+      command_line.AppendArgNative(arg);
+    }
+  }
+}
+
+// Lowercase switches for backwards compatiblity *on Windows*.
+std::string LowerASCIIOnWindows(const std::string& string) {
+#if defined(OS_WIN)
+  return StringToLowerASCII(string);
+#elif defined(OS_POSIX)
+  return string;
+#endif
+}
+
+
+#if defined(OS_WIN)
+// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*.
+std::wstring QuoteForCommandLineToArgvW(const std::wstring& arg) {
+  // We follow the quoting rules of CommandLineToArgvW.
+  // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+  if (arg.find_first_of(L" \\\"") == std::wstring::npos) {
+    // No quoting necessary.
+    return arg;
+  }
+
+  std::wstring 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)
+        /* empty */;
+      size_t backslash_count = end - start;
+
+      // Backslashes are escapes only if the run is followed by a double quote.
+      // Since we also will end the string with a double quote, we escape for
+      // either a double quote or the end of the string.
+      if (end == arg.size() || arg[end] == '"') {
+        // To quote, we need to output 2x as many backslashes.
+        backslash_count *= 2;
+      }
+      for (size_t j = 0; j < backslash_count; ++j)
+        out.push_back('\\');
+
+      // Advance i to one before the end to balance i++ in loop.
+      i = end - 1;
+    } else if (arg[i] == '"') {
+      out.push_back('\\');
+      out.push_back('"');
+    } else {
+      out.push_back(arg[i]);
+    }
+  }
+  out.push_back('"');
+
+  return out;
+}
+#endif
+
+}  // namespace
+
+CommandLine::CommandLine(NoProgram no_program)
+    : argv_(1),
+      begin_args_(1) {
+}
+
+CommandLine::CommandLine(const FilePath& program)
+    : argv_(1),
+      begin_args_(1) {
+  SetProgram(program);
+}
+
+CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv)
+    : argv_(1),
+      begin_args_(1) {
+  InitFromArgv(argc, argv);
+}
+
+CommandLine::CommandLine(const StringVector& argv)
+    : argv_(1),
+      begin_args_(1) {
+  InitFromArgv(argv);
+}
+
+CommandLine::~CommandLine() {
+}
+
+// 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_;
+}
+
+#if defined(OS_WIN)
+// static
+CommandLine CommandLine::FromString(const std::wstring& 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);
+  begin_args_ = 1;
+  SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
+  AppendSwitchesAndArguments(*this, argv);
+}
+
+CommandLine::StringType CommandLine::GetCommandLineString() const {
+  StringType string(argv_[0]);
+#if defined(OS_WIN)
+  string = QuoteForCommandLineToArgvW(string);
+#endif
+  StringType params(GetArgumentsString());
+  if (!params.empty()) {
+    string.append(StringType(FILE_PATH_LITERAL(" ")));
+    string.append(params);
+  }
+  return string;
+}
+
+CommandLine::StringType CommandLine::GetArgumentsString() const {
+  StringType params;
+  // Append switches and arguments.
+  bool parse_switches = true;
+  for (size_t i = 1; i < argv_.size(); ++i) {
+    StringType arg = argv_[i];
+    StringType switch_string;
+    StringType switch_value;
+    parse_switches &= arg != kSwitchTerminator;
+    if (i > 1)
+      params.append(StringType(FILE_PATH_LITERAL(" ")));
+    if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
+      params.append(switch_string);
+      if (!switch_value.empty()) {
+#if defined(OS_WIN)
+        switch_value = QuoteForCommandLineToArgvW(switch_value);
+#endif
+        params.append(kSwitchValueSeparator + switch_value);
+      }
+    }
+    else {
+#if defined(OS_WIN)
+      arg = QuoteForCommandLineToArgvW(arg);
+#endif
+      params.append(arg);
+    }
+  }
+  return params;
+}
+
+FilePath CommandLine::GetProgram() const {
+  return FilePath(argv_[0]);
+}
+
+void CommandLine::SetProgram(const FilePath& program) {
+  TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]);
+}
+
+bool CommandLine::HasSwitch(const std::string& switch_string) const {
+  return switches_.find(LowerASCIIOnWindows(switch_string)) != switches_.end();
+}
+
+std::string CommandLine::GetSwitchValueASCII(
+    const std::string& 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 WideToASCII(value);
+#else
+  return value;
+#endif
+}
+
+FilePath CommandLine::GetSwitchValuePath(
+    const std::string& switch_string) const {
+  return FilePath(GetSwitchValueNative(switch_string));
+}
+
+CommandLine::StringType CommandLine::GetSwitchValueNative(
+    const std::string& switch_string) const {
+  SwitchMap::const_iterator result = switches_.end();
+  result = switches_.find(LowerASCIIOnWindows(switch_string));
+  return result == switches_.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) {
+  std::string switch_key(LowerASCIIOnWindows(switch_string));
+#if defined(OS_WIN)
+  StringType combined_switch_string(ASCIIToWide(switch_key));
+#elif defined(OS_POSIX)
+  StringType combined_switch_string(switch_string);
+#endif
+  size_t prefix_length = GetSwitchPrefixLength(combined_switch_string);
+  switches_[switch_key.substr(prefix_length)] = value;
+  // 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, ASCIIToWide(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;
+  base::SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv);
+  // Prepend the wrapper and update the switches/arguments |begin_args_|.
+  argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end());
+  begin_args_ += wrapper_argv.size();
+}
+
+#if defined(OS_WIN)
+void CommandLine::ParseFromString(const std::wstring& command_line) {
+  std::wstring 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: "
+                         << command_line;
+  InitFromArgv(num_args, args);
+  LocalFree(args);
+}
+#endif
diff --git a/base/command_line.h b/base/command_line.h
new file mode 100644
index 0000000..7d8627f
--- /dev/null
+++ b/base/command_line.h
@@ -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.
+
+// 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 "build/build_config.h"
+
+class FilePath;
+
+class BASE_EXPORT CommandLine {
+ public:
+#if defined(OS_WIN)
+  // The native command line string type.
+  typedef std::wstring StringType;
+#elif defined(OS_POSIX)
+  typedef std::string StringType;
+#endif
+
+  typedef StringType::value_type CharType;
+  typedef std::vector<StringType> StringVector;
+  typedef std::map<std::string, StringType> SwitchMap;
+
+  // 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);
+
+  ~CommandLine();
+
+  // Initialize the current process CommandLine singleton. On Windows, ignores
+  // its arguments (we instead parse GetCommandLineW() directly) because we
+  // don't trust the CRT's parsing of the command line, but it still must be
+  // called to set up the command line. Returns false if initialization has
+  // already occurred, and true otherwise. Only the caller receiving a 'true'
+  // return value should take responsibility for calling Reset.
+  static bool Init(int argc, const char* const* argv);
+
+  // Destroys the current process CommandLine singleton. This is necessary if
+  // you want to reset the base library to its initial state (for example, in an
+  // outer library that needs to be able to terminate, and be re-initialized).
+  // If Init is called only once, as in main(), Reset() is not necessary.
+  static void Reset();
+
+  // Get the singleton CommandLine representing the current process's
+  // command line. Note: returned value is mutable, but not thread safe;
+  // only mutate if you know what you're doing!
+  static CommandLine* ForCurrentProcess();
+
+#if defined(OS_WIN)
+  static CommandLine FromString(const std::wstring& 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;
+
+  // Constructs and returns the represented arguments string.
+  // CAUTION! This should be avoided on POSIX because quoting behavior is
+  // unclear.
+  StringType GetArgumentsString() const;
+
+  // 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 are case-insensitive).
+  bool HasSwitch(const std::string& switch_string) 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.
+  std::string GetSwitchValueASCII(const std::string& switch_string) const;
+  FilePath GetSwitchValuePath(const std::string& switch_string) const;
+  StringType GetSwitchValueNative(const std::string& 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 std::wstring& 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(...);
+
+  // 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_;
+
+  // The index after the program and switches, any arguments start here.
+  size_t begin_args_;
+};
+
+#endif  // BASE_COMMAND_LINE_H_
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
new file mode 100644
index 0000000..372af37
--- /dev/null
+++ b/base/command_line_unittest.cc
@@ -0,0 +1,358 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// 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"));
+  EXPECT_TRUE(cl.HasSwitch("bAr"));
+  EXPECT_TRUE(cl.HasSwitch("baz"));
+  EXPECT_TRUE(cl.HasSwitch("spaetzle"));
+#if defined(OS_WIN)
+  EXPECT_TRUE(cl.HasSwitch("SPAETZLE"));
+#endif
+  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("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";
+
+  CommandLine cl(CommandLine::NO_PROGRAM);
+  cl.AppendSwitchPath(kFirstArgName, FilePath(kPath1));
+  cl.AppendSwitchPath(kSecondArgName, FilePath(kPath2));
+  cl.AppendArg(kThirdArgName);
+  cl.AppendArg(kFourthArgName);
+
+#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));
+#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);
+#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);
+  EXPECT_EQ(expected_str, cl.GetArgumentsString());
+}
+
+// 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.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\\\"\" "
+            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());
+  CommandLine::StringType program_string(cl_program_path.GetProgram().value());
+  EXPECT_EQ('"', cmd_string[0]);
+  EXPECT_EQ(program_string, cmd_string.substr(1, program_string.length()));
+  EXPECT_EQ('"', cmd_string[program_string.length() + 1]);
+}
+#endif
+
+// Calling Init multiple times should not modify the previous CommandLine.
+TEST(CommandLineTest, Init) {
+  CommandLine* initial = CommandLine::ForCurrentProcess();
+  EXPECT_FALSE(CommandLine::Init(0, NULL));
+  CommandLine* current = CommandLine::ForCurrentProcess();
+  EXPECT_EQ(initial, current);
+}
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
new file mode 100644
index 0000000..5d7d9d1
--- /dev/null
+++ b/base/compiler_specific.h
@@ -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.
+
+#ifndef BASE_COMPILER_SPECIFIC_H_
+#define BASE_COMPILER_SPECIFIC_H_
+
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+
+// Macros for suppressing and disabling warnings on MSVC.
+//
+// Warning numbers are enumerated at:
+// http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx
+//
+// The warning pragma:
+// http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx
+//
+// Using __pragma instead of #pragma inside macros:
+// http://msdn.microsoft.com/en-us/library/d9x1s805.aspx
+
+// MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and
+// for the next line of the source file.
+#define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n))
+
+// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled.
+// The warning remains disabled until popped by MSVC_POP_WARNING.
+#define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
+                                     __pragma(warning(disable:n))
+
+// MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level.  The level
+// remains in effect until popped by MSVC_POP_WARNING().  Use 0 to disable all
+// warnings.
+#define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n))
+
+// Pop effects of innermost MSVC_PUSH_* macro.
+#define MSVC_POP_WARNING() __pragma(warning(pop))
+
+#define MSVC_DISABLE_OPTIMIZE() __pragma(optimize("", off))
+#define MSVC_ENABLE_OPTIMIZE() __pragma(optimize("", on))
+
+// Allows |this| to be passed as an argument in constructor initializer lists.
+// This uses push/pop instead of the seemingly simpler suppress feature to avoid
+// having the warning be disabled for more than just |code|.
+//
+// Example usage:
+// Foo::Foo() : x(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(y(this)), z(3) {}
+//
+// Compiler warning C4355: 'this': used in base member initializer list:
+// http://msdn.microsoft.com/en-us/library/3c594ae3(VS.80).aspx
+#define ALLOW_THIS_IN_INITIALIZER_LIST(code) MSVC_PUSH_DISABLE_WARNING(4355) \
+                                             code \
+                                             MSVC_POP_WARNING()
+
+// Allows exporting a class that inherits from a non-exported base class.
+// This uses suppress instead of push/pop because the delimiter after the
+// declaration (either "," or "{") has to be placed before the pop macro.
+//
+// Example usage:
+// class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) {
+//
+// MSVC Compiler warning C4275:
+// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'.
+// Note that this is intended to be used only when no access to the base class'
+// static data is done through derived classes or inline methods. For more info,
+// see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
+#define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \
+                                code
+
+#else  // Not MSVC
+
+#define MSVC_SUPPRESS_WARNING(n)
+#define MSVC_PUSH_DISABLE_WARNING(n)
+#define MSVC_PUSH_WARNING_LEVEL(n)
+#define MSVC_POP_WARNING()
+#define MSVC_DISABLE_OPTIMIZE()
+#define MSVC_ENABLE_OPTIMIZE()
+#define ALLOW_THIS_IN_INITIALIZER_LIST(code) code
+#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 = ...;
+#if defined(COMPILER_GCC)
+#define ALLOW_UNUSED __attribute__((unused))
+#else
+#define ALLOW_UNUSED
+#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
+// sizeof(type) prior to checking __alignof to workaround Visual C++ bug:
+// http://goo.gl/isH0C
+// Use like:
+//   ALIGNOF(int32)  // this would be 4
+#if defined(COMPILER_MSVC)
+#define ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type))
+#elif defined(COMPILER_GCC)
+#define ALIGNOF(type) __alignof__(type)
+#endif
+
+// Annotate a virtual method indicating it must be overriding a virtual
+// method in the parent class.
+// Use like:
+//   virtual void foo() OVERRIDE;
+#if defined(COMPILER_MSVC)
+#define OVERRIDE override
+#elif defined(__clang__)
+#define OVERRIDE override
+#else
+#define OVERRIDE
+#endif
+
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+//   int foo() WARN_UNUSED_RESULT;
+// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
+#if defined(COMPILER_GCC)
+#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define WARN_UNUSED_RESULT
+#endif
+
+// Tell the compiler a function is using a printf-style format string.
+// |format_param| is the one-based index of the format string parameter;
+// |dots_param| is the one-based index of the "..." parameter.
+// For v*printf functions (which take a va_list), pass 0 for dots_param.
+// (This is undocumented but matches what the system C headers do.)
+#if defined(COMPILER_GCC)
+#define PRINTF_FORMAT(format_param, dots_param) \
+    __attribute__((format(printf, format_param, dots_param)))
+#else
+#define PRINTF_FORMAT(format_param, dots_param)
+#endif
+
+// WPRINTF_FORMAT is the same, but for wide format strings.
+// This doesn't appear to yet be implemented in any compiler.
+// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 .
+#define WPRINTF_FORMAT(format_param, dots_param)
+// If available, it would look like:
+//   __attribute__((format(wprintf, format_param, dots_param)))
+
+#endif  // BASE_COMPILER_SPECIFIC_H_
diff --git a/base/containers/linked_list.h b/base/containers/linked_list.h
new file mode 100644
index 0000000..25bbe76
--- /dev/null
+++ b/base/containers/linked_list.h
@@ -0,0 +1,164 @@
+// 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_
+
+// 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_(0), next_(0) {}
+  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_;
+  }
+
+  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_;
+};
+
+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_;
+  }
+
+ private:
+  LinkNode<T> root_;
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_LINKED_LIST_H_
diff --git a/base/containers/linked_list_unittest.cc b/base/containers/linked_list_unittest.cc
new file mode 100644
index 0000000..801e302
--- /dev/null
+++ b/base/containers/linked_list_unittest.cc
@@ -0,0 +1,261 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/containers/linked_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class Node : public LinkNode<Node> {
+ public:
+  explicit Node(int id) : id_(id) {}
+
+  int id() const { return id_; }
+
+ private:
+  int id_;
+};
+
+class MultipleInheritanceNodeBase {
+ public:
+  MultipleInheritanceNodeBase() : field_taking_up_space_(0) {}
+  int field_taking_up_space_;
+};
+
+class MultipleInheritanceNode : public MultipleInheritanceNodeBase,
+                                public LinkNode<MultipleInheritanceNode> {
+ public:
+  MultipleInheritanceNode() {}
+};
+
+// Checks that when iterating |list| (either from head to tail, or from
+// tail to head, as determined by |forward|), we get back |node_ids|,
+// which is an array of size |num_nodes|.
+void ExpectListContentsForDirection(const LinkedList<Node>& list,
+  int num_nodes, const int* node_ids, bool forward) {
+  int i = 0;
+  for (const LinkNode<Node>* node = (forward ? list.head() : list.tail());
+       node != list.end();
+       node = (forward ? node->next() : node->previous())) {
+    ASSERT_LT(i, num_nodes);
+    int index_of_id = forward ? i : num_nodes - i - 1;
+    EXPECT_EQ(node_ids[index_of_id], node->value()->id());
+    ++i;
+  }
+  EXPECT_EQ(num_nodes, i);
+}
+
+void ExpectListContents(const LinkedList<Node>& list,
+                        int num_nodes,
+                        const int* node_ids) {
+  {
+    SCOPED_TRACE("Iterating forward (from head to tail)");
+    ExpectListContentsForDirection(list, num_nodes, node_ids, true);
+  }
+  {
+    SCOPED_TRACE("Iterating backward (from tail to head)");
+    ExpectListContentsForDirection(list, num_nodes, node_ids, false);
+  }
+}
+
+TEST(LinkedList, Empty) {
+  LinkedList<Node> list;
+  EXPECT_EQ(list.end(), list.head());
+  EXPECT_EQ(list.end(), list.tail());
+  ExpectListContents(list, 0, NULL);
+}
+
+TEST(LinkedList, Append) {
+  LinkedList<Node> list;
+  ExpectListContents(list, 0, NULL);
+
+  Node n1(1);
+  list.Append(&n1);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n1, list.tail());
+  {
+    const int expected[] = {1};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  Node n2(2);
+  list.Append(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  Node n3(3);
+  list.Append(&n3);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n3, list.tail());
+  {
+    const int expected[] = {1, 2, 3};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, RemoveFromList) {
+  LinkedList<Node> list;
+
+  Node n1(1);
+  Node n2(2);
+  Node n3(3);
+  Node n4(4);
+  Node n5(5);
+
+  list.Append(&n1);
+  list.Append(&n2);
+  list.Append(&n3);
+  list.Append(&n4);
+  list.Append(&n5);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n5, list.tail());
+  {
+    const int expected[] = {1, 2, 3, 4, 5};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Remove from the middle.
+  n3.RemoveFromList();
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n5, list.tail());
+  {
+    const int expected[] = {1, 2, 4, 5};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Remove from the tail.
+  n5.RemoveFromList();
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n4, list.tail());
+  {
+    const int expected[] = {1, 2, 4};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Remove from the head.
+  n1.RemoveFromList();
+
+  EXPECT_EQ(&n2, list.head());
+  EXPECT_EQ(&n4, list.tail());
+  {
+    const int expected[] = {2, 4};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Empty the list.
+  n2.RemoveFromList();
+  n4.RemoveFromList();
+
+  ExpectListContents(list, 0, NULL);
+  EXPECT_EQ(list.end(), list.head());
+  EXPECT_EQ(list.end(), list.tail());
+
+  // Fill the list once again.
+  list.Append(&n1);
+  list.Append(&n2);
+  list.Append(&n3);
+  list.Append(&n4);
+  list.Append(&n5);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n5, list.tail());
+  {
+    const int expected[] = {1, 2, 3, 4, 5};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, InsertBefore) {
+  LinkedList<Node> list;
+
+  Node n1(1);
+  Node n2(2);
+  Node n3(3);
+  Node n4(4);
+
+  list.Append(&n1);
+  list.Append(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n3.InsertBefore(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 3, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n4.InsertBefore(&n1);
+
+  EXPECT_EQ(&n4, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {4, 1, 3, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, InsertAfter) {
+  LinkedList<Node> list;
+
+  Node n1(1);
+  Node n2(2);
+  Node n3(3);
+  Node n4(4);
+
+  list.Append(&n1);
+  list.Append(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n3.InsertAfter(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n3, list.tail());
+  {
+    const int expected[] = {1, 2, 3};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n4.InsertAfter(&n1);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n3, list.tail());
+  {
+    const int expected[] = {1, 4, 2, 3};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, MultipleInheritanceNode) {
+  MultipleInheritanceNode node;
+  EXPECT_EQ(&node, node.value());
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/containers/small_map.h b/base/containers/small_map.h
new file mode 100644
index 0000000..2c9ca25
--- /dev/null
+++ b/base/containers/small_map.h
@@ -0,0 +1,652 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_SMALL_MAP_H_
+#define BASE_CONTAINERS_SMALL_MAP_H_
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/manual_constructor.h"
+
+namespace base {
+
+// An STL-like associative container which starts out backed by a simple
+// array but switches to some other container type if it grows beyond a
+// fixed size.
+//
+// WHAT TYPE OF MAP SHOULD YOU USE?
+// --------------------------------
+//
+//  - std::map should be the default if you're not sure, since it's the most
+//    difficult to mess up. Generally this is backed by a red-black tree. It
+//    will generate a lot of code (if you use a common key type like int or
+//    string the linker will probably emiminate the duplicates). It will
+//    do heap allocations for each element.
+//
+//  - If you only ever keep a couple of items and have very simple usage,
+//    consider whether a using a vector and brute-force searching it will be
+//    the most efficient. It's not a lot of generated code (less then a
+//    red-black tree if your key is "weird" and not eliminated as duplicate of
+//    something else) and will probably be faster and do fewer heap allocations
+//    than std::map if you have just a couple of items.
+//
+//  - base::hash_map should be used if you need O(1) lookups. It may waste
+//    space in the hash table, and it can be easy to write correct-looking
+//    code with the default hash function being wrong or poorly-behaving.
+//
+//  - SmallMap combines the performance benefits of the brute-force-searched
+//    vector for small cases (no extra heap allocations), but can efficiently
+//    fall back if you end up adding many items. It will generate more code
+//    than std::map (at least 160 bytes for operator[]) which is bad if you
+//    have a "weird" key where map functions can't be
+//    duplicate-code-eliminated. If you have a one-off key and aren't in
+//    performance-critical code, this bloat may negate some of the benefits and
+//    you should consider on of the other options.
+//
+// SmallMap will pick up the comparator from the underlying map type. In
+// std::map (and in MSVC additionally hash_map) only a "less" operator is
+// defined, which requires us to do two comparisons per element when doing the
+// brute-force search in the simple array.
+//
+// We define default overrides for the common map types to avoid this
+// double-compare, but you should be aware of this if you use your own
+// operator< for your map and supply yor own version of == to the SmallMap.
+// You can use regular operator== by just doing:
+//
+//   base::SmallMap<std::map<MyKey, MyValue>, 4, std::equal_to<KyKey> >
+//
+//
+// USAGE
+// -----
+//
+// NormalMap:  The map type to fall back to.  This also defines the key
+//             and value types for the SmallMap.
+// kArraySize:  The size of the initial array of results. This will be
+//              allocated with the SmallMap object rather than separately on
+//              the heap. Once the map grows beyond this size, the map type
+//              will be used instead.
+// EqualKey:  A functor which tests two keys for equality.  If the wrapped
+//            map type has a "key_equal" member (hash_map does), then that will
+//            be used by default. If the wrapped map type has a strict weak
+//            ordering "key_compare" (std::map does), that will be used to
+//            implement equality by default.
+// MapInit: A functor that takes a ManualConstructor<NormalMap>* and uses it to
+//          initialize the map. This functor will be called at most once per
+//          SmallMap, when the map exceeds the threshold of kArraySize and we
+//          are about to copy values from the array to the map. The functor
+//          *must* call one of the Init() methods provided by
+//          ManualConstructor, since after it runs we assume that the NormalMap
+//          has been initialized.
+//
+// example:
+//   base::SmallMap< std::map<string, int> > days;
+//   days["sunday"   ] = 0;
+//   days["monday"   ] = 1;
+//   days["tuesday"  ] = 2;
+//   days["wednesday"] = 3;
+//   days["thursday" ] = 4;
+//   days["friday"   ] = 5;
+//   days["saturday" ] = 6;
+//
+// You should assume that SmallMap might invalidate all the iterators
+// on any call to erase(), insert() and operator[].
+
+namespace internal {
+
+template <typename NormalMap>
+class SmallMapDefaultInit {
+ public:
+  void operator()(ManualConstructor<NormalMap>* map) const {
+    map->Init();
+  }
+};
+
+// has_key_equal<M>::value is true iff there exists a type M::key_equal. This is
+// used to dispatch to one of the select_equal_key<> metafunctions below.
+template <typename M>
+struct has_key_equal {
+  typedef char sml;  // "small" is sometimes #defined so we use an abbreviation.
+  typedef struct { char dummy[2]; } big;
+  // Two functions, one accepts types that have a key_equal member, and one that
+  // accepts anything. They each return a value of a different size, so we can
+  // determine at compile-time which function would have been called.
+  template <typename U> static big test(typename U::key_equal*);
+  template <typename> static sml test(...);
+  // Determines if M::key_equal exists by looking at the size of the return
+  // type of the compiler-chosen test() function.
+  static const bool value = (sizeof(test<M>(0)) == sizeof(big));
+};
+template <typename M> const bool has_key_equal<M>::value;
+
+// Base template used for map types that do NOT have an M::key_equal member,
+// e.g., std::map<>. These maps have a strict weak ordering comparator rather
+// than an equality functor, so equality will be implemented in terms of that
+// comparator.
+//
+// There's a partial specialization of this template below for map types that do
+// have an M::key_equal member.
+template <typename M, bool has_key_equal_value>
+struct select_equal_key {
+  struct equal_key {
+    bool operator()(const typename M::key_type& left,
+                    const typename M::key_type& right) {
+      // Implements equality in terms of a strict weak ordering comparator.
+      typename M::key_compare comp;
+      return !comp(left, right) && !comp(right, left);
+    }
+  };
+};
+
+// Provide overrides to use operator== for key compare for the "normal" map and
+// hash map types. If you override the default comparator or allocator for a
+// map or hash_map, or use another type of map, this won't get used.
+//
+// If we switch to using std::unordered_map for base::hash_map, then the
+// hash_map specialization can be removed.
+template <typename KeyType, typename ValueType>
+struct select_equal_key< std::map<KeyType, ValueType>, false> {
+  struct equal_key {
+    bool operator()(const KeyType& left, const KeyType& right) {
+      return left == right;
+    }
+  };
+};
+template <typename KeyType, typename ValueType>
+struct select_equal_key< base::hash_map<KeyType, ValueType>, false> {
+  struct equal_key {
+    bool operator()(const KeyType& left, const KeyType& right) {
+      return left == right;
+    }
+  };
+};
+
+// Partial template specialization handles case where M::key_equal exists, e.g.,
+// hash_map<>.
+template <typename M>
+struct select_equal_key<M, true> {
+  typedef typename M::key_equal equal_key;
+};
+
+}  // namespace internal
+
+template <typename NormalMap,
+          int kArraySize = 4,
+          typename EqualKey =
+              typename internal::select_equal_key<
+                  NormalMap,
+                  internal::has_key_equal<NormalMap>::value>::equal_key,
+          typename MapInit = internal::SmallMapDefaultInit<NormalMap> >
+class SmallMap {
+  // We cannot rely on the compiler to reject array of size 0.  In
+  // particular, gcc 2.95.3 does it but later versions allow 0-length
+  // arrays.  Therefore, we explicitly reject non-positive kArraySize
+  // here.
+  COMPILE_ASSERT(kArraySize > 0, default_initial_size_should_be_positive);
+
+ public:
+  typedef typename NormalMap::key_type key_type;
+  typedef typename NormalMap::mapped_type data_type;
+  typedef typename NormalMap::mapped_type mapped_type;
+  typedef typename NormalMap::value_type value_type;
+  typedef EqualKey key_equal;
+
+  SmallMap() : size_(0), functor_(MapInit()) {}
+
+  explicit SmallMap(const MapInit& functor) : size_(0), functor_(functor) {}
+
+  // Allow copy-constructor and assignment, since STL allows them too.
+  SmallMap(const SmallMap& src) {
+    // size_ and functor_ are initted in InitFrom()
+    InitFrom(src);
+  }
+  void operator=(const SmallMap& src) {
+    if (&src == this) return;
+
+    // This is not optimal. If src and dest are both using the small
+    // array, we could skip the teardown and reconstruct. One problem
+    // to be resolved is that the value_type itself is pair<const K,
+    // V>, and const K is not assignable.
+    Destroy();
+    InitFrom(src);
+  }
+  ~SmallMap() {
+    Destroy();
+  }
+
+  class const_iterator;
+
+  class iterator {
+   public:
+    typedef typename NormalMap::iterator::iterator_category iterator_category;
+    typedef typename NormalMap::iterator::value_type value_type;
+    typedef typename NormalMap::iterator::difference_type difference_type;
+    typedef typename NormalMap::iterator::pointer pointer;
+    typedef typename NormalMap::iterator::reference reference;
+
+    inline iterator(): array_iter_(NULL) {}
+
+    inline iterator& operator++() {
+      if (array_iter_ != NULL) {
+        ++array_iter_;
+      } else {
+        ++hash_iter_;
+      }
+      return *this;
+    }
+    inline iterator operator++(int /*unused*/) {
+      iterator result(*this);
+      ++(*this);
+      return result;
+    }
+    inline iterator& operator--() {
+      if (array_iter_ != NULL) {
+        --array_iter_;
+      } else {
+        --hash_iter_;
+      }
+      return *this;
+    }
+    inline iterator operator--(int /*unused*/) {
+      iterator result(*this);
+      --(*this);
+      return result;
+    }
+    inline value_type* operator->() const {
+      if (array_iter_ != NULL) {
+        return array_iter_->get();
+      } else {
+        return hash_iter_.operator->();
+      }
+    }
+
+    inline value_type& operator*() const {
+      if (array_iter_ != NULL) {
+        return *array_iter_->get();
+      } else {
+        return *hash_iter_;
+      }
+    }
+
+    inline bool operator==(const iterator& other) const {
+      if (array_iter_ != NULL) {
+        return array_iter_ == other.array_iter_;
+      } else {
+        return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_;
+      }
+    }
+
+    inline bool operator!=(const iterator& other) const {
+      return !(*this == other);
+    }
+
+    bool operator==(const const_iterator& other) const;
+    bool operator!=(const const_iterator& other) const;
+
+   private:
+    friend class SmallMap;
+    friend class const_iterator;
+    inline explicit iterator(ManualConstructor<value_type>* init)
+      : array_iter_(init) {}
+    inline explicit iterator(const typename NormalMap::iterator& init)
+      : array_iter_(NULL), hash_iter_(init) {}
+
+    ManualConstructor<value_type>* array_iter_;
+    typename NormalMap::iterator hash_iter_;
+  };
+
+  class const_iterator {
+   public:
+    typedef typename NormalMap::const_iterator::iterator_category
+        iterator_category;
+    typedef typename NormalMap::const_iterator::value_type value_type;
+    typedef typename NormalMap::const_iterator::difference_type difference_type;
+    typedef typename NormalMap::const_iterator::pointer pointer;
+    typedef typename NormalMap::const_iterator::reference reference;
+
+    inline const_iterator(): array_iter_(NULL) {}
+    // Non-explicit ctor lets us convert regular iterators to const iterators
+    inline const_iterator(const iterator& other)
+      : array_iter_(other.array_iter_), hash_iter_(other.hash_iter_) {}
+
+    inline const_iterator& operator++() {
+      if (array_iter_ != NULL) {
+        ++array_iter_;
+      } else {
+        ++hash_iter_;
+      }
+      return *this;
+    }
+    inline const_iterator operator++(int /*unused*/) {
+      const_iterator result(*this);
+      ++(*this);
+      return result;
+    }
+
+    inline const_iterator& operator--() {
+      if (array_iter_ != NULL) {
+        --array_iter_;
+      } else {
+        --hash_iter_;
+      }
+      return *this;
+    }
+    inline const_iterator operator--(int /*unused*/) {
+      const_iterator result(*this);
+      --(*this);
+      return result;
+    }
+
+    inline const value_type* operator->() const {
+      if (array_iter_ != NULL) {
+        return array_iter_->get();
+      } else {
+        return hash_iter_.operator->();
+      }
+    }
+
+    inline const value_type& operator*() const {
+      if (array_iter_ != NULL) {
+        return *array_iter_->get();
+      } else {
+        return *hash_iter_;
+      }
+    }
+
+    inline bool operator==(const const_iterator& other) const {
+      if (array_iter_ != NULL) {
+        return array_iter_ == other.array_iter_;
+      } else {
+        return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_;
+      }
+    }
+
+    inline bool operator!=(const const_iterator& other) const {
+      return !(*this == other);
+    }
+
+   private:
+    friend class SmallMap;
+    inline explicit const_iterator(
+        const ManualConstructor<value_type>* init)
+      : array_iter_(init) {}
+    inline explicit const_iterator(
+        const typename NormalMap::const_iterator& init)
+      : array_iter_(NULL), hash_iter_(init) {}
+
+    const ManualConstructor<value_type>* array_iter_;
+    typename NormalMap::const_iterator hash_iter_;
+  };
+
+  iterator find(const key_type& key) {
+    key_equal compare;
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        if (compare(array_[i]->first, key)) {
+          return iterator(array_ + i);
+        }
+      }
+      return iterator(array_ + size_);
+    } else {
+      return iterator(map()->find(key));
+    }
+  }
+
+  const_iterator find(const key_type& key) const {
+    key_equal compare;
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        if (compare(array_[i]->first, key)) {
+          return const_iterator(array_ + i);
+        }
+      }
+      return const_iterator(array_ + size_);
+    } else {
+      return const_iterator(map()->find(key));
+    }
+  }
+
+  // Invalidates iterators.
+  data_type& operator[](const key_type& key) {
+    key_equal compare;
+
+    if (size_ >= 0) {
+      // operator[] searches backwards, favoring recently-added
+      // elements.
+      for (int i = size_-1; i >= 0; --i) {
+        if (compare(array_[i]->first, key)) {
+          return array_[i]->second;
+        }
+      }
+      if (size_ == kArraySize) {
+        ConvertToRealMap();
+        return (*map_)[key];
+      } else {
+        array_[size_].Init(key, data_type());
+        return array_[size_++]->second;
+      }
+    } else {
+      return (*map_)[key];
+    }
+  }
+
+  // Invalidates iterators.
+  std::pair<iterator, bool> insert(const value_type& x) {
+    key_equal compare;
+
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        if (compare(array_[i]->first, x.first)) {
+          return std::make_pair(iterator(array_ + i), false);
+        }
+      }
+      if (size_ == kArraySize) {
+        ConvertToRealMap();  // Invalidates all iterators!
+        std::pair<typename NormalMap::iterator, bool> ret = map_->insert(x);
+        return std::make_pair(iterator(ret.first), ret.second);
+      } else {
+        array_[size_].Init(x);
+        return std::make_pair(iterator(array_ + size_++), true);
+      }
+    } else {
+      std::pair<typename NormalMap::iterator, bool> ret = map_->insert(x);
+      return std::make_pair(iterator(ret.first), ret.second);
+    }
+  }
+
+  // Invalidates iterators.
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l) {
+    while (f != l) {
+      insert(*f);
+      ++f;
+    }
+  }
+
+  iterator begin() {
+    if (size_ >= 0) {
+      return iterator(array_);
+    } else {
+      return iterator(map_->begin());
+    }
+  }
+  const_iterator begin() const {
+    if (size_ >= 0) {
+      return const_iterator(array_);
+    } else {
+      return const_iterator(map_->begin());
+    }
+  }
+
+  iterator end() {
+    if (size_ >= 0) {
+      return iterator(array_ + size_);
+    } else {
+      return iterator(map_->end());
+    }
+  }
+  const_iterator end() const {
+    if (size_ >= 0) {
+      return const_iterator(array_ + size_);
+    } else {
+      return const_iterator(map_->end());
+    }
+  }
+
+  void clear() {
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        array_[i].Destroy();
+      }
+    } else {
+      map_.Destroy();
+    }
+    size_ = 0;
+  }
+
+  // Invalidates iterators.
+  void erase(const iterator& position) {
+    if (size_ >= 0) {
+      int i = position.array_iter_ - array_;
+      array_[i].Destroy();
+      --size_;
+      if (i != size_) {
+        array_[i].Init(*array_[size_]);
+        array_[size_].Destroy();
+      }
+    } else {
+      map_->erase(position.hash_iter_);
+    }
+  }
+
+  size_t erase(const key_type& key) {
+    iterator iter = find(key);
+    if (iter == end()) return 0u;
+    erase(iter);
+    return 1u;
+  }
+
+  size_t count(const key_type& key) const {
+    return (find(key) == end()) ? 0 : 1;
+  }
+
+  size_t size() const {
+    if (size_ >= 0) {
+      return static_cast<size_t>(size_);
+    } else {
+      return map_->size();
+    }
+  }
+
+  bool empty() const {
+    if (size_ >= 0) {
+      return (size_ == 0);
+    } else {
+      return map_->empty();
+    }
+  }
+
+  // Returns true if we have fallen back to using the underlying map
+  // representation.
+  bool UsingFullMap() const {
+    return size_ < 0;
+  }
+
+  inline NormalMap* map() {
+    CHECK(UsingFullMap());
+    return map_.get();
+  }
+  inline const NormalMap* map() const {
+    CHECK(UsingFullMap());
+    return map_.get();
+  }
+
+ private:
+  int size_;  // negative = using hash_map
+
+  MapInit functor_;
+
+  // We want to call constructors and destructors manually, but we don't
+  // want to allocate and deallocate the memory used for them separately.
+  // So, we use this crazy ManualConstructor class.
+  //
+  // Since array_ and map_ are mutually exclusive, we'll put them in a
+  // union, too.  We add in a dummy_ value which quiets MSVC from otherwise
+  // giving an erroneous "union member has copy constructor" error message
+  // (C2621). This dummy member has to come before array_ to quiet the
+  // compiler.
+  //
+  // TODO(brettw) remove this and use C++11 unions when we require C++11.
+  union {
+    ManualConstructor<value_type> dummy_;
+    ManualConstructor<value_type> array_[kArraySize];
+    ManualConstructor<NormalMap> map_;
+  };
+
+  void ConvertToRealMap() {
+    // Move the current elements into a temporary array.
+    ManualConstructor<value_type> temp_array[kArraySize];
+
+    for (int i = 0; i < kArraySize; i++) {
+      temp_array[i].Init(*array_[i]);
+      array_[i].Destroy();
+    }
+
+    // Initialize the map.
+    size_ = -1;
+    functor_(&map_);
+
+    // Insert elements into it.
+    for (int i = 0; i < kArraySize; i++) {
+      map_->insert(*temp_array[i]);
+      temp_array[i].Destroy();
+    }
+  }
+
+  // Helpers for constructors and destructors.
+  void InitFrom(const SmallMap& src) {
+    functor_ = src.functor_;
+    size_ = src.size_;
+    if (src.size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        array_[i].Init(*src.array_[i]);
+      }
+    } else {
+      functor_(&map_);
+      (*map_.get()) = (*src.map_.get());
+    }
+  }
+  void Destroy() {
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        array_[i].Destroy();
+      }
+    } else {
+      map_.Destroy();
+    }
+  }
+};
+
+template <typename NormalMap, int kArraySize, typename EqualKey,
+          typename Functor>
+inline bool SmallMap<NormalMap, kArraySize, EqualKey,
+                     Functor>::iterator::operator==(
+    const const_iterator& other) const {
+  return other == *this;
+}
+template <typename NormalMap, int kArraySize, typename EqualKey,
+          typename Functor>
+inline bool SmallMap<NormalMap, kArraySize, EqualKey,
+                     Functor>::iterator::operator!=(
+    const const_iterator& other) const {
+  return other != *this;
+}
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_SMALL_MAP_H_
diff --git a/base/containers/small_map_unittest.cc b/base/containers/small_map_unittest.cc
new file mode 100644
index 0000000..d1c8680
--- /dev/null
+++ b/base/containers/small_map_unittest.cc
@@ -0,0 +1,491 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/small_map.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <functional>
+#include <map>
+
+#include "base/logging.h"
+#include "base/hash_tables.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(SmallMap, General) {
+  SmallMap<hash_map<int, int> > m;
+
+  EXPECT_TRUE(m.empty());
+
+  m[0] = 5;
+
+  EXPECT_FALSE(m.empty());
+  EXPECT_EQ(m.size(), 1u);
+
+  m[9] = 2;
+
+  EXPECT_FALSE(m.empty());
+  EXPECT_EQ(m.size(), 2u);
+
+  EXPECT_EQ(m[9], 2);
+  EXPECT_EQ(m[0], 5);
+  EXPECT_FALSE(m.UsingFullMap());
+
+  SmallMap<hash_map<int, int> >::iterator iter(m.begin());
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ((*iter).first, 9);
+  EXPECT_EQ((*iter).second, 2);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+
+  m[8] = 23;
+  m[1234] = 90;
+  m[-5] = 6;
+
+  EXPECT_EQ(m[   9],  2);
+  EXPECT_EQ(m[   0],  5);
+  EXPECT_EQ(m[1234], 90);
+  EXPECT_EQ(m[   8], 23);
+  EXPECT_EQ(m[  -5],  6);
+  EXPECT_EQ(m.size(), 5u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_TRUE(m.UsingFullMap());
+
+  iter = m.begin();
+  for (int i = 0; i < 5; i++) {
+    EXPECT_TRUE(iter != m.end());
+    ++iter;
+  }
+  EXPECT_TRUE(iter == m.end());
+
+  const SmallMap<hash_map<int, int> >& ref = m;
+  EXPECT_TRUE(ref.find(1234) != m.end());
+  EXPECT_TRUE(ref.find(5678) == m.end());
+}
+
+TEST(SmallMap, PostFixIteratorIncrement) {
+  SmallMap<hash_map<int, int> > m;
+  m[0] = 5;
+  m[2] = 3;
+
+  {
+    SmallMap<hash_map<int, int> >::iterator iter(m.begin());
+    SmallMap<hash_map<int, int> >::iterator last(iter++);
+    ++last;
+    EXPECT_TRUE(last == iter);
+  }
+
+  {
+    SmallMap<hash_map<int, int> >::const_iterator iter(m.begin());
+    SmallMap<hash_map<int, int> >::const_iterator last(iter++);
+    ++last;
+    EXPECT_TRUE(last == iter);
+  }
+}
+
+// Based on the General testcase.
+TEST(SmallMap, CopyConstructor) {
+  SmallMap<hash_map<int, int> > src;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_TRUE(m.empty());
+  }
+
+  src[0] = 5;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_FALSE(m.empty());
+    EXPECT_EQ(m.size(), 1u);
+  }
+
+  src[9] = 2;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_FALSE(m.empty());
+    EXPECT_EQ(m.size(), 2u);
+
+    EXPECT_EQ(m[9], 2);
+    EXPECT_EQ(m[0], 5);
+    EXPECT_FALSE(m.UsingFullMap());
+  }
+
+  src[8] = 23;
+  src[1234] = 90;
+  src[-5] = 6;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_EQ(m[   9],  2);
+    EXPECT_EQ(m[   0],  5);
+    EXPECT_EQ(m[1234], 90);
+    EXPECT_EQ(m[   8], 23);
+    EXPECT_EQ(m[  -5],  6);
+    EXPECT_EQ(m.size(), 5u);
+    EXPECT_FALSE(m.empty());
+    EXPECT_TRUE(m.UsingFullMap());
+  }
+}
+
+template<class inner>
+static void SmallMapToMap(SmallMap<inner> const& src, inner* dest) {
+  typename SmallMap<inner>::const_iterator it;
+  for (it = src.begin(); it != src.end(); ++it) {
+    dest->insert(std::make_pair(it->first, it->second));
+  }
+}
+
+template<class inner>
+static bool SmallMapEqual(SmallMap<inner> const& a,
+                          SmallMap<inner> const& b) {
+  inner ia, ib;
+  SmallMapToMap(a, &ia);
+  SmallMapToMap(b, &ib);
+
+  // On most systems we can use operator== here, but under some lesser STL
+  // implementations it doesn't seem to work. So we manually compare.
+  if (ia.size() != ib.size())
+    return false;
+  for (typename inner::iterator ia_it = ia.begin(), ib_it = ib.begin();
+       ia_it != ia.end(); ++ia_it, ++ib_it) {
+    if (*ia_it != *ib_it)
+      return false;
+  }
+  return true;
+}
+
+TEST(SmallMap, AssignmentOperator) {
+  SmallMap<hash_map<int, int> > src_small;
+  SmallMap<hash_map<int, int> > src_large;
+
+  src_small[1] = 20;
+  src_small[2] = 21;
+  src_small[3] = 22;
+  EXPECT_FALSE(src_small.UsingFullMap());
+
+  src_large[1] = 20;
+  src_large[2] = 21;
+  src_large[3] = 22;
+  src_large[5] = 23;
+  src_large[6] = 24;
+  src_large[7] = 25;
+  EXPECT_TRUE(src_large.UsingFullMap());
+
+  // Assignments to empty.
+  SmallMap<hash_map<int, int> > dest_small;
+  dest_small = src_small;
+  EXPECT_TRUE(SmallMapEqual(dest_small, src_small));
+  EXPECT_EQ(dest_small.UsingFullMap(),
+            src_small.UsingFullMap());
+
+  SmallMap<hash_map<int, int> > dest_large;
+  dest_large = src_large;
+  EXPECT_TRUE(SmallMapEqual(dest_large, src_large));
+  EXPECT_EQ(dest_large.UsingFullMap(),
+            src_large.UsingFullMap());
+
+  // Assignments which assign from full to small, and vice versa.
+  dest_small = src_large;
+  EXPECT_TRUE(SmallMapEqual(dest_small, src_large));
+  EXPECT_EQ(dest_small.UsingFullMap(),
+            src_large.UsingFullMap());
+
+  dest_large = src_small;
+  EXPECT_TRUE(SmallMapEqual(dest_large, src_small));
+  EXPECT_EQ(dest_large.UsingFullMap(),
+            src_small.UsingFullMap());
+
+  // Double check that SmallMapEqual works:
+  dest_large[42] = 666;
+  EXPECT_FALSE(SmallMapEqual(dest_large, src_small));
+}
+
+TEST(SmallMap, Insert) {
+  SmallMap<hash_map<int, int> > sm;
+
+  // loop through the transition from small map to map.
+  for (int i = 1; i <= 10; ++i) {
+    VLOG(1) << "Iteration " << i;
+    // insert an element
+    std::pair<SmallMap<hash_map<int, int> >::iterator,
+        bool> ret;
+    ret = sm.insert(std::make_pair(i, 100*i));
+    EXPECT_TRUE(ret.second);
+    EXPECT_TRUE(ret.first == sm.find(i));
+    EXPECT_EQ(ret.first->first, i);
+    EXPECT_EQ(ret.first->second, 100*i);
+
+    // try to insert it again with different value, fails, but we still get an
+    // iterator back with the original value.
+    ret = sm.insert(std::make_pair(i, -i));
+    EXPECT_FALSE(ret.second);
+    EXPECT_TRUE(ret.first == sm.find(i));
+    EXPECT_EQ(ret.first->first, i);
+    EXPECT_EQ(ret.first->second, 100*i);
+
+    // check the state of the map.
+    for (int j = 1; j <= i; ++j) {
+      SmallMap<hash_map<int, int> >::iterator it = sm.find(j);
+      EXPECT_TRUE(it != sm.end());
+      EXPECT_EQ(it->first, j);
+      EXPECT_EQ(it->second, j * 100);
+    }
+    EXPECT_EQ(sm.size(), static_cast<size_t>(i));
+    EXPECT_FALSE(sm.empty());
+  }
+}
+
+TEST(SmallMap, InsertRange) {
+  // loop through the transition from small map to map.
+  for (int elements = 0; elements <= 10; ++elements) {
+    VLOG(1) << "Elements " << elements;
+    hash_map<int, int> normal_map;
+    for (int i = 1; i <= elements; ++i) {
+      normal_map.insert(std::make_pair(i, 100*i));
+    }
+
+    SmallMap<hash_map<int, int> > sm;
+    sm.insert(normal_map.begin(), normal_map.end());
+    EXPECT_EQ(normal_map.size(), sm.size());
+    for (int i = 1; i <= elements; ++i) {
+      VLOG(1) << "Iteration " << i;
+      EXPECT_TRUE(sm.find(i) != sm.end());
+      EXPECT_EQ(sm.find(i)->first, i);
+      EXPECT_EQ(sm.find(i)->second, 100*i);
+    }
+  }
+}
+
+TEST(SmallMap, Erase) {
+  SmallMap<hash_map<std::string, int> > m;
+  SmallMap<hash_map<std::string, int> >::iterator iter;
+
+  m["monday"] = 1;
+  m["tuesday"] = 2;
+  m["wednesday"] = 3;
+
+  EXPECT_EQ(m["monday"   ], 1);
+  EXPECT_EQ(m["tuesday"  ], 2);
+  EXPECT_EQ(m["wednesday"], 3);
+  EXPECT_EQ(m.count("tuesday"), 1u);
+  EXPECT_FALSE(m.UsingFullMap());
+
+  iter = m.begin();
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "monday");
+  EXPECT_EQ(iter->second, 1);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "tuesday");
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "wednesday");
+  EXPECT_EQ(iter->second, 3);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+
+  EXPECT_EQ(m.erase("tuesday"), 1u);
+
+  EXPECT_EQ(m["monday"   ], 1);
+  EXPECT_EQ(m["wednesday"], 3);
+  EXPECT_EQ(m.count("tuesday"), 0u);
+  EXPECT_EQ(m.erase("tuesday"), 0u);
+
+  iter = m.begin();
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "monday");
+  EXPECT_EQ(iter->second, 1);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "wednesday");
+  EXPECT_EQ(iter->second, 3);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+
+  m["thursday"] = 4;
+  m["friday"] = 5;
+  EXPECT_EQ(m.size(), 4u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_FALSE(m.UsingFullMap());
+
+  m["saturday"] = 6;
+  EXPECT_TRUE(m.UsingFullMap());
+
+  EXPECT_EQ(m.count("friday"), 1u);
+  EXPECT_EQ(m.erase("friday"), 1u);
+  EXPECT_TRUE(m.UsingFullMap());
+  EXPECT_EQ(m.count("friday"), 0u);
+  EXPECT_EQ(m.erase("friday"), 0u);
+
+  EXPECT_EQ(m.size(), 4u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_EQ(m.erase("monday"), 1u);
+  EXPECT_EQ(m.size(), 3u);
+  EXPECT_FALSE(m.empty());
+
+  m.clear();
+  EXPECT_FALSE(m.UsingFullMap());
+  EXPECT_EQ(m.size(), 0u);
+  EXPECT_TRUE(m.empty());
+}
+
+TEST(SmallMap, NonHashMap) {
+  SmallMap<std::map<int, int>, 4, std::equal_to<int> > m;
+  EXPECT_TRUE(m.empty());
+
+  m[9] = 2;
+  m[0] = 5;
+
+  EXPECT_EQ(m[9], 2);
+  EXPECT_EQ(m[0], 5);
+  EXPECT_EQ(m.size(), 2u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_FALSE(m.UsingFullMap());
+
+  SmallMap<std::map<int, int>, 4, std::equal_to<int> >::iterator iter(
+      m.begin());
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 9);
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+  --iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+
+  m[8] = 23;
+  m[1234] = 90;
+  m[-5] = 6;
+
+  EXPECT_EQ(m[   9],  2);
+  EXPECT_EQ(m[   0],  5);
+  EXPECT_EQ(m[1234], 90);
+  EXPECT_EQ(m[   8], 23);
+  EXPECT_EQ(m[  -5],  6);
+  EXPECT_EQ(m.size(), 5u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_TRUE(m.UsingFullMap());
+
+  iter = m.begin();
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, -5);
+  EXPECT_EQ(iter->second, 6);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 8);
+  EXPECT_EQ(iter->second, 23);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 9);
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 1234);
+  EXPECT_EQ(iter->second, 90);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+  --iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 1234);
+  EXPECT_EQ(iter->second, 90);
+}
+
+TEST(SmallMap, DefaultEqualKeyWorks) {
+  // If these tests compile, they pass. The EXPECT calls are only there to avoid
+  // unused variable warnings.
+  SmallMap<hash_map<int, int> > hm;
+  EXPECT_EQ(0u, hm.size());
+  SmallMap<std::map<int, int> > m;
+  EXPECT_EQ(0u, m.size());
+}
+
+namespace {
+
+class hash_map_add_item : public hash_map<int, int> {
+ public:
+  hash_map_add_item() : hash_map<int, int>() {}
+  hash_map_add_item(const std::pair<int, int>& item) : hash_map<int, int>() {
+    insert(item);
+  }
+};
+
+void InitMap(ManualConstructor<hash_map_add_item>* map_ctor) {
+  map_ctor->Init(std::make_pair(0, 0));
+}
+
+class hash_map_add_item_initializer {
+ public:
+  explicit hash_map_add_item_initializer(int item_to_add)
+      : item_(item_to_add) {}
+  hash_map_add_item_initializer()
+      : item_(0) {}
+  void operator()(ManualConstructor<hash_map_add_item>* map_ctor) const {
+    map_ctor->Init(std::make_pair(item_, item_));
+  }
+
+  int item_;
+};
+
+}  // anonymous namespace
+
+TEST(SmallMap, SubclassInitializationWithFunctionPointer) {
+  SmallMap<hash_map_add_item, 4, std::equal_to<int>,
+      void (&)(ManualConstructor<hash_map_add_item>*)> m(InitMap);
+
+  EXPECT_TRUE(m.empty());
+
+  m[1] = 1;
+  m[2] = 2;
+  m[3] = 3;
+  m[4] = 4;
+
+  EXPECT_EQ(4u, m.size());
+  EXPECT_EQ(0u, m.count(0));
+
+  m[5] = 5;
+  EXPECT_EQ(6u, m.size());
+  // Our function adds an extra item when we convert to a map.
+  EXPECT_EQ(1u, m.count(0));
+}
+
+TEST(SmallMap, SubclassInitializationWithFunctionObject) {
+  SmallMap<hash_map_add_item, 4, std::equal_to<int>,
+      hash_map_add_item_initializer> m(hash_map_add_item_initializer(-1));
+
+  EXPECT_TRUE(m.empty());
+
+  m[1] = 1;
+  m[2] = 2;
+  m[3] = 3;
+  m[4] = 4;
+
+  EXPECT_EQ(4u, m.size());
+  EXPECT_EQ(0u, m.count(-1));
+
+  m[5] = 5;
+  EXPECT_EQ(6u, m.size());
+  // Our functor adds an extra item when we convert to a map.
+  EXPECT_EQ(1u, m.count(-1));
+}
+
+}  // namespace base
diff --git a/base/containers/stack_container.h b/base/containers/stack_container.h
new file mode 100644
index 0000000..b3e508b
--- /dev/null
+++ b/base/containers/stack_container.h
@@ -0,0 +1,258 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_STACK_CONTAINER_H_
+#define BASE_CONTAINERS_STACK_CONTAINER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+#include "base/memory/aligned_memory.h"
+#include "base/string16.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(OS_ANDROID)
+    COMPILE_ASSERT(ALIGNOF(T) <= 16, crbug_115612);
+#endif
+
+    // Set when the stack buffer is used for an allocation. We do not track
+    // how much of the buffer is used, only that somebody is using it.
+    bool used_stack_buffer_;
+  };
+
+  // Used by containers when they want to refer to an allocator of type U.
+  template<typename U>
+  struct rebind {
+    typedef StackAllocator<U, stack_capacity> other;
+  };
+
+  // For the straight up copy c-tor, we can share storage.
+  StackAllocator(const StackAllocator<T, stack_capacity>& rhs)
+      : std::allocator<T>(), source_(rhs.source_) {
+  }
+
+  // ISO C++ requires the following constructor to be defined,
+  // and std::vector in VC++2008SP1 Release fails with an error
+  // in the class _Container_base_aux_alloc_real (from <xutility>)
+  // if the constructor does not exist.
+  // For this constructor, we cannot share storage; there's
+  // no guarantee that the Source buffer of Ts is large enough
+  // for Us.
+  // TODO: If we were fancy pants, perhaps we could share storage
+  // iff sizeof(T) == sizeof(U).
+  template<typename U, size_t other_capacity>
+  StackAllocator(const StackAllocator<U, other_capacity>& other)
+      : source_(NULL) {
+  }
+
+  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_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackContainer);
+};
+
+// StackString -----------------------------------------------------------------
+
+template<size_t stack_capacity>
+class StackString : public StackContainer<
+    std::basic_string<char,
+                      std::char_traits<char>,
+                      StackAllocator<char, stack_capacity> >,
+    stack_capacity> {
+ public:
+  StackString() : StackContainer<
+      std::basic_string<char,
+                        std::char_traits<char>,
+                        StackAllocator<char, stack_capacity> >,
+      stack_capacity>() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackString);
+};
+
+// StackStrin16 ----------------------------------------------------------------
+
+template<size_t stack_capacity>
+class StackString16 : public StackContainer<
+    std::basic_string<char16,
+                      base::string16_char_traits,
+                      StackAllocator<char16, stack_capacity> >,
+    stack_capacity> {
+ public:
+  StackString16() : StackContainer<
+      std::basic_string<char16,
+                        base::string16_char_traits,
+                        StackAllocator<char16, stack_capacity> >,
+      stack_capacity>() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackString16);
+};
+
+// StackVector -----------------------------------------------------------------
+
+// Example:
+//   StackVector<int, 16> foo;
+//   foo->push_back(22);  // we have overloaded operator->
+//   foo[0] = 10;         // as well as operator[]
+template<typename T, size_t stack_capacity>
+class StackVector : public StackContainer<
+    std::vector<T, StackAllocator<T, stack_capacity> >,
+    stack_capacity> {
+ public:
+  StackVector() : StackContainer<
+      std::vector<T, StackAllocator<T, stack_capacity> >,
+      stack_capacity>() {
+  }
+
+  // We need to put this in STL containers sometimes, which requires a copy
+  // constructor. We can't call the regular copy constructor because that will
+  // take the stack buffer from the original. Here, we create an empty object
+  // and make a stack buffer of its own.
+  StackVector(const StackVector<T, stack_capacity>& other)
+      : StackContainer<
+            std::vector<T, StackAllocator<T, stack_capacity> >,
+            stack_capacity>() {
+    this->container().assign(other->begin(), other->end());
+  }
+
+  StackVector<T, stack_capacity>& operator=(
+      const StackVector<T, stack_capacity>& other) {
+    this->container().assign(other->begin(), other->end());
+    return *this;
+  }
+
+  // Vectors are commonly indexed, which isn't very convenient even with
+  // operator-> (using "->at()" does exception stuff we don't want).
+  T& operator[](size_t i) { return this->container().operator[](i); }
+  const T& operator[](size_t i) const {
+    return this->container().operator[](i);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_STACK_CONTAINER_H_
diff --git a/base/containers/stack_container_unittest.cc b/base/containers/stack_container_unittest.cc
new file mode 100644
index 0000000..3a1b3ed
--- /dev/null
+++ b/base/containers/stack_container_unittest.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/stack_container.h"
+
+#include <algorithm>
+
+#include "base/memory/aligned_memory.h"
+#include "base/memory/ref_counted.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class Dummy : public base::RefCounted<Dummy> {
+ public:
+  explicit Dummy(int* alive) : alive_(alive) {
+    ++*alive_;
+  }
+
+ private:
+  friend class base::RefCounted<Dummy>;
+
+  ~Dummy() {
+    --*alive_;
+  }
+
+  int* const alive_;
+};
+
+}  // namespace
+
+TEST(StackContainer, Vector) {
+  const int stack_size = 3;
+  StackVector<int, stack_size> vect;
+  const int* stack_buffer = &vect.stack_data().stack_buffer()[0];
+
+  // The initial |stack_size| elements should appear in the stack buffer.
+  EXPECT_EQ(static_cast<size_t>(stack_size), vect.container().capacity());
+  for (int i = 0; i < stack_size; i++) {
+    vect.container().push_back(i);
+    EXPECT_EQ(stack_buffer, &vect.container()[0]);
+    EXPECT_TRUE(vect.stack_data().used_stack_buffer_);
+  }
+
+  // Adding more elements should push the array onto the heap.
+  for (int i = 0; i < stack_size; i++) {
+    vect.container().push_back(i + stack_size);
+    EXPECT_NE(stack_buffer, &vect.container()[0]);
+    EXPECT_FALSE(vect.stack_data().used_stack_buffer_);
+  }
+
+  // The array should still be in order.
+  for (int i = 0; i < stack_size * 2; i++)
+    EXPECT_EQ(i, vect.container()[i]);
+
+  // Resize to smaller. Our STL implementation won't reallocate in this case,
+  // otherwise it might use our stack buffer. We reserve right after the resize
+  // to guarantee it isn't using the stack buffer, even though it doesn't have
+  // much data.
+  vect.container().resize(stack_size);
+  vect.container().reserve(stack_size * 2);
+  EXPECT_FALSE(vect.stack_data().used_stack_buffer_);
+
+  // Copying the small vector to another should use the same allocator and use
+  // the now-unused stack buffer. GENERALLY CALLERS SHOULD NOT DO THIS since
+  // they have to get the template types just right and it can cause errors.
+  std::vector<int, StackAllocator<int, stack_size> > other(vect.container());
+  EXPECT_EQ(stack_buffer, &other.front());
+  EXPECT_TRUE(vect.stack_data().used_stack_buffer_);
+  for (int i = 0; i < stack_size; i++)
+    EXPECT_EQ(i, other[i]);
+}
+
+TEST(StackContainer, VectorDoubleDelete) {
+  // Regression testing for double-delete.
+  typedef StackVector<scoped_refptr<Dummy>, 2> Vector;
+  typedef Vector::ContainerType Container;
+  Vector vect;
+
+  int alive = 0;
+  scoped_refptr<Dummy> dummy(new Dummy(&alive));
+  EXPECT_EQ(alive, 1);
+
+  vect->push_back(dummy);
+  EXPECT_EQ(alive, 1);
+
+  Dummy* dummy_unref = dummy.get();
+  dummy = NULL;
+  EXPECT_EQ(alive, 1);
+
+  Container::iterator itr = std::find(vect->begin(), vect->end(), dummy_unref);
+  EXPECT_EQ(itr->get(), dummy_unref);
+  vect->erase(itr);
+  EXPECT_EQ(alive, 0);
+
+  // Shouldn't crash at exit.
+}
+
+namespace {
+
+template <size_t alignment>
+class AlignedData {
+ public:
+  AlignedData() { memset(data_.void_data(), 0, alignment); }
+  ~AlignedData() {}
+  base::AlignedMemory<alignment, alignment> data_;
+};
+
+}  // anonymous namespace
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST(StackContainer, BufferAlignment) {
+  StackVector<wchar_t, 16> text;
+  text->push_back(L'A');
+  EXPECT_ALIGNED(&text[0], ALIGNOF(wchar_t));
+
+  StackVector<double, 1> doubles;
+  doubles->push_back(0.0);
+  EXPECT_ALIGNED(&doubles[0], ALIGNOF(double));
+
+  StackVector<AlignedData<16>, 1> aligned16;
+  aligned16->push_back(AlignedData<16>());
+  EXPECT_ALIGNED(&aligned16[0], 16);
+
+#if !defined(OS_ANDROID)
+  // It seems that android doesn't respect greater than 16 byte alignment for
+  // non-POD data on the stack, even though ALIGNOF(aligned256) == 256.
+  StackVector<AlignedData<256>, 1> aligned256;
+  aligned256->push_back(AlignedData<256>());
+  EXPECT_ALIGNED(&aligned256[0], 256);
+#endif
+}
+
+template class StackVector<int, 2>;
+template class StackVector<scoped_refptr<Dummy>, 2>;
+
+}  // namespace base
diff --git a/base/cpu.cc b/base/cpu.cc
new file mode 100644
index 0000000..cf4f2f1
--- /dev/null
+++ b/base/cpu.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/cpu.h"
+
+#include <string.h>
+
+#include <algorithm>
+
+#include "build/build_config.h"
+
+#if defined(ARCH_CPU_X86_FAMILY)
+#if defined(_MSC_VER)
+#include <intrin.h>
+#endif
+#endif
+
+namespace base {
+
+CPU::CPU()
+  : 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),
+    cpu_vendor_("unknown") {
+  Initialize();
+}
+
+#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)
+  );
+}
+
+void __cpuidex(int cpu_info[4], int info_type, int info_index) {
+  __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), "c"(info_index)
+  );
+}
+
+#else
+
+void __cpuid(int cpu_info[4], int info_type) {
+  __asm__ volatile (
+    "cpuid \n\t"
+    : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+    : "a"(info_type)
+  );
+}
+
+void __cpuidex(int cpu_info[4], int info_type, int info_index) {
+  __asm__ volatile (
+    "cpuid \n\t"
+    : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+    : "a"(info_type), "c"(info_index)
+  );
+}
+
+#endif
+#endif  // _MSC_VER
+#endif  // ARCH_CPU_X86_FAMILY
+
+void CPU::Initialize() {
+#if defined(ARCH_CPU_X86_FAMILY)
+  int cpu_info[4] = {-1};
+  char cpu_string[48];
+
+  // __cpuid with an InfoType argument of 0 returns the number of
+  // valid Ids in CPUInfo[0] and the CPU identification string in
+  // the other three array elements. The CPU identification string is
+  // not in linear order. The code below arranges the information
+  // in a human readable form. The human readable order is CPUInfo[1] |
+  // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped
+  // before using memcpy to copy these three array elements to cpu_string.
+  __cpuid(cpu_info, 0);
+  int num_ids = cpu_info[0];
+  std::swap(cpu_info[2], cpu_info[3]);
+  memcpy(cpu_string, &cpu_info[1], 3 * sizeof(cpu_info[1]));
+  cpu_vendor_.assign(cpu_string, 3 * sizeof(cpu_info[1]));
+
+  // Interpret CPU feature information.
+  if (num_ids > 0) {
+    __cpuid(cpu_info, 1);
+    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;
+  }
+
+  // Get the brand string of the cpu.
+  __cpuid(cpu_info, 0x80000000);
+  const int parameter_end = 0x80000004;
+
+  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);
+  }
+#endif
+}
+
+}  // namespace base
diff --git a/base/cpu.h b/base/cpu.h
new file mode 100644
index 0000000..957b1a5
--- /dev/null
+++ b/base/cpu.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_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();
+
+  // Accessors for CPU information.
+  const std::string& vendor_name() const { return cpu_vendor_; }
+  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_; }
+  const std::string& cpu_brand() const { return cpu_brand_; }
+
+ private:
+  // Query the processor for CPUID information.
+  void Initialize();
+
+  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_;
+  std::string cpu_vendor_;
+  std::string cpu_brand_;
+};
+
+}  // namespace base
+
+#endif  // BASE_CPU_H_
diff --git a/base/cpu_unittest.cc b/base/cpu_unittest.cc
new file mode 100644
index 0000000..d059dee
--- /dev/null
+++ b/base/cpu_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/cpu.h"
+#include "build/build_config.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Tests whether we can run extended instructions represented by the CPU
+// information. This test actually executes some extended instructions (such as
+// MMX, SSE, etc.) supported by the CPU and sees we can run them without
+// "undefined instruction" exceptions. That is, this test succeeds when this
+// test finishes without a crash.
+TEST(CPU, RunExtendedInstructions) {
+#if defined(ARCH_CPU_X86_FAMILY)
+  // Retrieve the CPU information.
+  base::CPU cpu;
+
+#if defined(OS_WIN)
+  ASSERT_TRUE(cpu.has_mmx());
+
+  // Execute an MMX instruction.
+  __asm emms;
+
+  if (cpu.has_sse()) {
+    // Execute an SSE instruction.
+    __asm xorps xmm0, xmm0;
+  }
+
+  if (cpu.has_sse2()) {
+    // Execute an SSE 2 instruction.
+    __asm psrldq xmm0, 0;
+  }
+
+  if (cpu.has_sse3()) {
+    // Execute an SSE 3 instruction.
+    __asm addsubpd xmm0, xmm0;
+  }
+
+  if (cpu.has_ssse3()) {
+    // Execute a Supplimental SSE 3 instruction.
+    __asm psignb xmm0, xmm0;
+  }
+
+  if (cpu.has_sse41()) {
+    // Execute an SSE 4.1 instruction.
+    __asm pmuldq xmm0, xmm0;
+  }
+
+  if (cpu.has_sse42()) {
+    // Execute an SSE 4.2 instruction.
+    __asm crc32 eax, eax;
+  }
+#elif defined(OS_POSIX) && defined(__x86_64__)
+  ASSERT_TRUE(cpu.has_mmx());
+
+  // Execute an MMX instruction.
+  __asm__ __volatile__("emms\n" : : : "mm0");
+
+  if (cpu.has_sse()) {
+    // Execute an SSE instruction.
+    __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse2()) {
+    // Execute an SSE 2 instruction.
+    __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse3()) {
+    // Execute an SSE 3 instruction.
+    __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_ssse3()) {
+    // Execute a Supplimental SSE 3 instruction.
+    __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse41()) {
+    // Execute an SSE 4.1 instruction.
+    __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse42()) {
+    // Execute an SSE 4.2 instruction.
+    __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax");
+  }
+#endif
+#endif
+}
diff --git a/base/critical_closure.h b/base/critical_closure.h
new file mode 100644
index 0000000..ca51ed5
--- /dev/null
+++ b/base/critical_closure.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_CRITICAL_CLOSURE_H_
+#define BASE_CRITICAL_CLOSURE_H_
+
+#include "base/callback.h"
+
+namespace base {
+
+// Returns a closure 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_message_loop_proxy_->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)
+base::Closure MakeCriticalClosure(const base::Closure& closure);
+#else
+inline base::Closure MakeCriticalClosure(const base::Closure& closure) {
+  // No-op for platforms where the application does not need to acquire
+  // background time for closures to finish when it goes into the background.
+  return closure;
+}
+#endif  // !defined(OS_IOS)
+
+}  // namespace base
+
+#endif  // BASE_CRITICAL_CLOSURE_H_
diff --git a/base/critical_closure_ios.mm b/base/critical_closure_ios.mm
new file mode 100644
index 0000000..156612b
--- /dev/null
+++ b/base/critical_closure_ios.mm
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/critical_closure.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/bind.h"
+#include "base/ios/scoped_critical_action.h"
+#include "base/memory/ref_counted.h"
+
+namespace {
+
+// 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
+// |base::ios::ScopedCriticalAction|.
+class CriticalClosure : public base::RefCountedThreadSafe<CriticalClosure> {
+ public:
+  explicit CriticalClosure(base::Closure* closure) : closure_(closure) {
+    background_scope_.reset(new base::ios::ScopedCriticalAction());
+  }
+
+  void Run() {
+    closure_->Run();
+
+    background_scope_.reset();
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<CriticalClosure>;
+
+  virtual ~CriticalClosure() {}
+
+  scoped_ptr<base::Closure> closure_;
+  scoped_ptr<base::ios::ScopedCriticalAction> background_scope_;
+
+  DISALLOW_COPY_AND_ASSIGN(CriticalClosure);
+};
+
+}  // namespace
+
+namespace base {
+
+base::Closure MakeCriticalClosure(const base::Closure& closure) {
+  DCHECK([[UIDevice currentDevice] isMultitaskingSupported]);
+  scoped_refptr<CriticalClosure> critical_closure(
+      new CriticalClosure(new base::Closure(closure)));
+  return base::Bind(&CriticalClosure::Run, critical_closure.get());
+}
+
+}  // namespace base
diff --git a/base/data/file_util_unittest/binary_file.bin b/base/data/file_util_unittest/binary_file.bin
new file mode 100644
index 0000000..f53cc82
--- /dev/null
+++ b/base/data/file_util_unittest/binary_file.bin
Binary files differ
diff --git a/base/data/file_util_unittest/binary_file_diff.bin b/base/data/file_util_unittest/binary_file_diff.bin
new file mode 100644
index 0000000..103b26d
--- /dev/null
+++ b/base/data/file_util_unittest/binary_file_diff.bin
Binary files differ
diff --git a/base/data/file_util_unittest/binary_file_same.bin b/base/data/file_util_unittest/binary_file_same.bin
new file mode 100644
index 0000000..f53cc82
--- /dev/null
+++ b/base/data/file_util_unittest/binary_file_same.bin
Binary files differ
diff --git a/base/data/file_util_unittest/blank_line.txt b/base/data/file_util_unittest/blank_line.txt
new file mode 100644
index 0000000..8892069
--- /dev/null
+++ b/base/data/file_util_unittest/blank_line.txt
@@ -0,0 +1,3 @@
+The next line is blank.
+
+But this one isn't.
diff --git a/base/data/file_util_unittest/blank_line_crlf.txt b/base/data/file_util_unittest/blank_line_crlf.txt
new file mode 100644
index 0000000..3aefe52
--- /dev/null
+++ b/base/data/file_util_unittest/blank_line_crlf.txt
@@ -0,0 +1,3 @@
+The next line is blank.

+

+But this one isn't.

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

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

+  "appName": {

+    "message": "Gmail",

+    "description": "App name."

+  },

+  "appDesc": {

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

+    "description":"App description."

+  }

+}
\ No newline at end of file
diff --git a/base/debug/alias.cc b/base/debug/alias.cc
new file mode 100644
index 0000000..6b0caaa
--- /dev/null
+++ b/base/debug/alias.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/alias.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace debug {
+
+#if defined(COMPILER_MSVC)
+#pragma optimize("", off)
+#endif
+
+void Alias(const void* var) {
+}
+
+#if defined(COMPILER_MSVC)
+#pragma optimize("", on)
+#endif
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/alias.h b/base/debug/alias.h
new file mode 100644
index 0000000..3b2ab64
--- /dev/null
+++ b/base/debug/alias.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_ALIAS_H_
+#define BASE_DEBUG_ALIAS_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace debug {
+
+// Make the optimizer think that var is aliased. This is to prevent it from
+// optimizing out variables that that would not otherwise be live at the point
+// of a potential crash.
+void BASE_EXPORT Alias(const void* var);
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_ALIAS_H_
diff --git a/base/debug/debug_on_start_win.cc b/base/debug/debug_on_start_win.cc
new file mode 100644
index 0000000..6ca88dd
--- /dev/null
+++ b/base/debug/debug_on_start_win.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/debug_on_start_win.h"
+
+#include <windows.h>
+
+#include "base/base_switches.h"
+#include "base/basictypes.h"
+#include "base/debug/debugger.h"
+
+namespace base {
+namespace debug {
+
+// Minimalist implementation to try to find a command line argument. We can use
+// kernel32 exported functions but not the CRT functions because we're too early
+// in the process startup.
+// The code is not that bright and will find things like ---argument or
+// /-/argument.
+// Note: command_line is non-destructively modified.
+bool DebugOnStart::FindArgument(wchar_t* command_line, const char* argument_c) {
+  wchar_t argument[50] = {};
+  for (int i = 0; argument_c[i]; ++i)
+    argument[i] = argument_c[i];
+
+  int argument_len = lstrlen(argument);
+  int command_line_len = lstrlen(command_line);
+  while (command_line_len > argument_len) {
+    wchar_t first_char = command_line[0];
+    wchar_t last_char = command_line[argument_len+1];
+    // Try to find an argument.
+    if ((first_char == L'-' || first_char == L'/') &&
+        (last_char == L' ' || last_char == 0 || last_char == L'=')) {
+      command_line[argument_len+1] = 0;
+      // Skip the - or /
+      if (lstrcmpi(command_line+1, argument) == 0) {
+        // Found it.
+        command_line[argument_len+1] = last_char;
+        return true;
+      }
+      // Fix back.
+      command_line[argument_len+1] = last_char;
+    }
+    // Continue searching.
+    ++command_line;
+    --command_line_len;
+  }
+  return false;
+}
+
+// static
+int __cdecl DebugOnStart::Init() {
+  // Try to find the argument.
+  if (FindArgument(GetCommandLine(), switches::kDebugOnStart)) {
+    // We can do 2 things here:
+    // - Ask for a debugger to attach to us. This involve reading the registry
+    //   key and creating the process.
+    // - Do a int3.
+
+    // It will fails if we run in a sandbox. That is expected.
+    base::debug::SpawnDebuggerOnProcess(GetCurrentProcessId());
+
+    // Wait for a debugger to come take us.
+    base::debug::WaitForDebugger(60, false);
+  } else if (FindArgument(GetCommandLine(), switches::kWaitForDebugger)) {
+    // Wait for a debugger to come take us.
+    base::debug::WaitForDebugger(60, true);
+  }
+  return 0;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/debug_on_start_win.h b/base/debug/debug_on_start_win.h
new file mode 100644
index 0000000..edcaa0a
--- /dev/null
+++ b/base/debug/debug_on_start_win.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Define the necessary code and global data to look for kDebugOnStart command
+// line argument. When the command line argument is detected, it invokes the
+// debugger, if no system-wide debugger is registered, a debug break is done.
+
+#ifndef BASE_DEBUG_DEBUG_ON_START_WIN_H_
+#define BASE_DEBUG_DEBUG_ON_START_WIN_H_
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+// This only works on Windows. It's legal to include on other platforms, but
+// will be a NOP.
+#if defined(OS_WIN)
+
+#ifndef DECLSPEC_SELECTANY
+#define DECLSPEC_SELECTANY  __declspec(selectany)
+#endif
+
+namespace base {
+namespace debug {
+
+// There is no way for this code, as currently implemented, to work across DLLs.
+// TODO(rvargas): It looks like we really don't use this code, at least not for
+// Chrome. Figure out if it's really worth implementing something simpler.
+#if !defined(COMPONENT_BUILD)
+
+// Debug on start functions and data.
+class DebugOnStart {
+ public:
+  // Expected function type in the .CRT$XI* section.
+  // Note: See VC\crt\src\internal.h for reference.
+  typedef int  (__cdecl *PIFV)(void);
+
+  // Looks at the command line for kDebugOnStart argument. If found, it invokes
+  // the debugger, if this fails, it crashes.
+  static int __cdecl Init();
+
+  // Returns true if the 'argument' is present in the 'command_line'. It does
+  // not use the CRT, only Kernel32 functions.
+  static bool FindArgument(wchar_t* command_line, const char* argument);
+};
+
+// Set the function pointer to our function to look for a crash on start. The
+// XIB section is started pretty early in the program initialization so in
+// theory it should be called before any user created global variable
+// initialization code and CRT initialization code.
+// Note: See VC\crt\src\defsects.inc and VC\crt\src\crt0.c for reference.
+#ifdef _WIN64
+
+// "Fix" the segment. On x64, the .CRT segment is merged into the .rdata segment
+// so it contains const data only.
+#pragma const_seg(push, ".CRT$XIB")
+// Declare the pointer so the CRT will find it.
+extern const DebugOnStart::PIFV debug_on_start;
+DECLSPEC_SELECTANY const DebugOnStart::PIFV debug_on_start =
+    &DebugOnStart::Init;
+// Fix back the segment.
+#pragma const_seg(pop)
+
+#else  // _WIN64
+
+// "Fix" the segment. On x86, the .CRT segment is merged into the .data segment
+// so it contains non-const data only.
+#pragma data_seg(push, ".CRT$XIB")
+// Declare the pointer so the CRT will find it.
+DECLSPEC_SELECTANY DebugOnStart::PIFV debug_on_start = &DebugOnStart::Init;
+// Fix back the segment.
+#pragma data_seg(pop)
+
+#endif  // _WIN64
+
+#endif  // defined(COMPONENT_BUILD)
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // defined(OS_WIN)
+
+#endif  // BASE_DEBUG_DEBUG_ON_START_WIN_H_
diff --git a/base/debug/debugger.cc b/base/debug/debugger.cc
new file mode 100644
index 0000000..79233c5
--- /dev/null
+++ b/base/debug/debugger.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/debugger.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace debug {
+
+static bool is_debug_ui_suppressed = false;
+
+bool WaitForDebugger(int wait_seconds, bool silent) {
+#if defined(OS_ANDROID)
+  // The pid from which we know which process to attach to are not output by
+  // android ddms, so we have to print it out explicitly.
+  DLOG(INFO) << "DebugUtil::WaitForDebugger(pid=" << static_cast<int>(getpid())
+             << ")";
+#endif
+  for (int i = 0; i < wait_seconds * 10; ++i) {
+    if (BeingDebugged()) {
+      if (!silent)
+        BreakDebugger();
+      return true;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  }
+  return false;
+}
+
+void SetSuppressDebugUI(bool suppress) {
+  is_debug_ui_suppressed = suppress;
+}
+
+bool IsDebugUISuppressed() {
+  return is_debug_ui_suppressed;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/debugger.h b/base/debug/debugger.h
new file mode 100644
index 0000000..4f368d9
--- /dev/null
+++ b/base/debug/debugger.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// 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 {
+
+// Starts the registered system-wide JIT debugger to attach it to specified
+// process.
+BASE_EXPORT bool SpawnDebuggerOnProcess(unsigned process_id);
+
+// Waits wait_seconds seconds for a debugger to attach to the current process.
+// When silent is false, an exception is thrown when a debugger is detected.
+BASE_EXPORT bool WaitForDebugger(int wait_seconds, bool silent);
+
+// Returns true if the given process is being run under a debugger.
+//
+// On OS X, the underlying mechanism doesn't work when the sandbox is enabled.
+// To get around this, this function caches its value.
+//
+// WARNING: Because of this, on OS X, a call MUST be made to this function
+// BEFORE the sandbox is enabled.
+BASE_EXPORT bool BeingDebugged();
+
+// Break into the debugger, assumes a debugger is present.
+BASE_EXPORT void BreakDebugger();
+
+// Used in test code, this controls whether showing dialogs and breaking into
+// the debugger is suppressed for debug errors, even in debug mode (normally
+// release mode doesn't do this stuff --  this is controlled separately).
+// Normally UI is not suppressed.  This is normally used when running automated
+// tests where we want a crash rather than a dialog or a debugger.
+BASE_EXPORT void SetSuppressDebugUI(bool suppress);
+BASE_EXPORT bool IsDebugUISuppressed();
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_DEBUGGER_H
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
new file mode 100644
index 0000000..796b0e8
--- /dev/null
+++ b/base/debug/debugger_posix.cc
@@ -0,0 +1,246 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/debugger.h"
+#include "build/build_config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#if !defined(OS_ANDROID) && !defined(OS_NACL)
+#include <execinfo.h>
+#endif
+
+#if defined(__GLIBCXX__)
+#include <cxxabi.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#endif
+
+#if defined(OS_MACOSX) || defined(OS_BSD)
+#include <sys/sysctl.h>
+#endif
+
+#if defined(OS_FREEBSD)
+#include <sys/user.h>
+#endif
+
+#include <ostream>
+
+#include "base/basictypes.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/safe_strerror_posix.h"
+#include "base/string_piece.h"
+#include "base/stringprintf.h"
+
+#if defined(USE_SYMBOLIZE)
+#include "base/third_party/symbolize/symbolize.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/threading/platform_thread.h"
+#endif
+
+namespace base {
+namespace debug {
+
+bool SpawnDebuggerOnProcess(unsigned process_id) {
+#if OS_ANDROID || OS_NACL
+  NOTIMPLEMENTED();
+  return false;
+#else
+  const std::string debug_cmd =
+      StringPrintf("xterm -e 'gdb --pid=%u' &", process_id);
+  LOG(WARNING) << "Starting debugger on pid " << process_id
+               << " with command `" << debug_cmd << "`";
+  int ret = system(debug_cmd.c_str());
+  if (ret == -1)
+    return false;
+  return true;
+#endif
+}
+
+#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() {
+  // 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() {
+  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 (HANDLE_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, send SIGTRAP; Release mode, send SIGABRT.
+// Mac: Always send SIGTRAP.
+
+#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(ARCH_CPU_ARM_FAMILY)
+#if defined(OS_ANDROID)
+// Though Android has a "helpful" process called debuggerd to catch native
+// signals on the general assumption that they are fatal errors. 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.
+#define DEBUG_BREAK() do { \
+  if (!BeingDebugged()) { \
+    abort(); \
+  } else { \
+    volatile int go = 0; \
+    while (!go) { \
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); \
+    } \
+  } \
+} while (0)
+#else
+// ARM && !ANDROID
+#define DEBUG_BREAK() asm("bkpt 0")
+#endif
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+#define DEBUG_BREAK() asm("break 2")
+#else
+#define DEBUG_BREAK() asm("int3")
+#endif
+
+void BreakDebugger() {
+  DEBUG_BREAK();
+#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)
+  // For Android development we always build release (debug builds are
+  // unmanageably large), so the unofficial build is used for debugging. It is
+  // helpful to be able to insert BreakDebugger() statements in the source,
+  // attach the debugger, inspect the state of the program and then resume it by
+  // setting the 'go' variable above.
+#elif defined(NDEBUG)
+  // Terminate the program after signaling the debug break.
+  _exit(1);
+#endif
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/debugger_win.cc b/base/debug/debugger_win.cc
new file mode 100644
index 0000000..b13dbfd
--- /dev/null
+++ b/base/debug/debugger_win.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/debugger.h"
+
+#include <windows.h>
+#include <dbghelp.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+// Minimalist key reader.
+// Note: Does not use the CRT.
+bool RegReadString(HKEY root, const wchar_t* subkey,
+                   const wchar_t* value_name, wchar_t* buffer, int* len) {
+  HKEY key = NULL;
+  DWORD res = RegOpenKeyEx(root, subkey, 0, KEY_READ, &key);
+  if (ERROR_SUCCESS != res || key == NULL)
+    return false;
+
+  DWORD type = 0;
+  DWORD buffer_size = *len * sizeof(wchar_t);
+  // We don't support REG_EXPAND_SZ.
+  res = RegQueryValueEx(key, value_name, NULL, &type,
+                        reinterpret_cast<BYTE*>(buffer), &buffer_size);
+  if (ERROR_SUCCESS == res && buffer_size != 0 && type == REG_SZ) {
+    // Make sure the buffer is NULL terminated.
+    buffer[*len - 1] = 0;
+    *len = lstrlen(buffer);
+    RegCloseKey(key);
+    return true;
+  }
+  RegCloseKey(key);
+  return false;
+}
+
+// Replaces each "%ld" in input per a value. Not efficient but it works.
+// Note: Does not use the CRT.
+bool StringReplace(const wchar_t* input, int value, wchar_t* output,
+                   int output_len) {
+  memset(output, 0, output_len*sizeof(wchar_t));
+  int input_len = lstrlen(input);
+
+  for (int i = 0; i < input_len; ++i) {
+    int current_output_len = lstrlen(output);
+
+    if (input[i] == L'%' && input[i + 1] == L'l' && input[i + 2] == L'd') {
+      // Make sure we have enough place left.
+      if ((current_output_len + 12) >= output_len)
+        return false;
+
+      // Cheap _itow().
+      wsprintf(output+current_output_len, L"%d", value);
+      i += 2;
+    } else {
+      if (current_output_len >= output_len)
+        return false;
+      output[current_output_len] = input[i];
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+// Note: Does not use the CRT.
+bool SpawnDebuggerOnProcess(unsigned process_id) {
+  wchar_t reg_value[1026];
+  int len = arraysize(reg_value);
+  if (RegReadString(HKEY_LOCAL_MACHINE,
+      L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug",
+      L"Debugger", reg_value, &len)) {
+    wchar_t command_line[1026];
+    if (StringReplace(reg_value, process_id, command_line,
+                      arraysize(command_line))) {
+      // We don't mind if the debugger is present because it will simply fail
+      // to attach to this process.
+      STARTUPINFO startup_info = {0};
+      startup_info.cb = sizeof(startup_info);
+      PROCESS_INFORMATION process_info = {0};
+
+      if (CreateProcess(NULL, command_line, NULL, NULL, FALSE, 0, NULL, NULL,
+                        &startup_info, &process_info)) {
+        CloseHandle(process_info.hThread);
+        WaitForInputIdle(process_info.hProcess, 10000);
+        CloseHandle(process_info.hProcess);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool BeingDebugged() {
+  return ::IsDebuggerPresent() != 0;
+}
+
+void BreakDebugger() {
+  if (IsDebugUISuppressed())
+    _exit(1);
+  __debugbreak();
+#if defined(NDEBUG)
+  _exit(1);
+#endif
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/leak_annotations.h b/base/debug/leak_annotations.h
new file mode 100644
index 0000000..51adfb0
--- /dev/null
+++ b/base/debug/leak_annotations.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_
+#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_NACL) && \
+    defined(USE_HEAPCHECKER)
+
+#include "third_party/tcmalloc/chromium/src/gperftools/heap-checker.h"
+
+// Annotate a program scope as having memory leaks. Tcmalloc's heap leak
+// checker will ignore them. Note that these annotations may mask real bugs
+// and should not be used in the production code.
+#define ANNOTATE_SCOPED_MEMORY_LEAK \
+    HeapLeakChecker::Disabler heap_leak_checker_disabler
+
+// Annotate an object pointer as referencing a leaky object. This object and all
+// the heap objects referenced by it will be ignored by the heap checker.
+//
+// X should be referencing an active allocated object. If it is not, the
+// annotation will be ignored.
+// No object should be annotated with ANNOTATE_SCOPED_MEMORY_LEAK twice.
+// Once an object is annotated with ANNOTATE_SCOPED_MEMORY_LEAK, it cannot be
+// deleted.
+#define ANNOTATE_LEAKING_OBJECT_PTR(X) \
+    HeapLeakChecker::IgnoreObject(X)
+
+#else
+
+// If tcmalloc is not used, the annotations should be no-ops.
+#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0)
+#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0)
+
+#endif
+
+#endif  // BASE_DEBUG_LEAK_ANNOTATIONS_H_
diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h
new file mode 100644
index 0000000..93cea39
--- /dev/null
+++ b/base/debug/leak_tracker.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_DEBUG_LEAK_TRACKER_H_
+#define BASE_DEBUG_LEAK_TRACKER_H_
+
+// Only enable leak tracking in debug builds.
+#ifndef NDEBUG
+#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].PrintBacktrace();
+    }
+  }
+
+  static int NumLiveInstances() {
+    // Walk the allocation list and count how many entries it has.
+    int count = 0;
+    for (LinkNode<LeakTracker<T> >* node = instances()->head();
+         node != instances()->end();
+         node = node->next()) {
+      ++count;
+    }
+    return count;
+  }
+
+ private:
+  // Each specialization of LeakTracker gets its own static storage.
+  static LinkedList<LeakTracker<T> >* instances() {
+    static LinkedList<LeakTracker<T> > list;
+    return &list;
+  }
+
+  StackTrace allocation_stack_;
+};
+
+#endif  // ENABLE_LEAK_TRACKER
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_LEAK_TRACKER_H_
diff --git a/base/debug/leak_tracker_unittest.cc b/base/debug/leak_tracker_unittest.cc
new file mode 100644
index 0000000..99df4c1
--- /dev/null
+++ b/base/debug/leak_tracker_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/leak_tracker.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+class ClassA {
+ private:
+  LeakTracker<ClassA> leak_tracker_;
+};
+
+class ClassB {
+ private:
+  LeakTracker<ClassB> leak_tracker_;
+};
+
+#ifndef ENABLE_LEAK_TRACKER
+
+// If leak tracking is disabled, we should do nothing.
+TEST(LeakTrackerTest, NotEnabled) {
+  EXPECT_EQ(-1, LeakTracker<ClassA>::NumLiveInstances());
+  EXPECT_EQ(-1, LeakTracker<ClassB>::NumLiveInstances());
+
+  // Use scoped_ptr so compiler doesn't complain about unused variables.
+  scoped_ptr<ClassA> a1(new ClassA);
+  scoped_ptr<ClassB> b1(new ClassB);
+  scoped_ptr<ClassB> b2(new ClassB);
+
+  EXPECT_EQ(-1, LeakTracker<ClassA>::NumLiveInstances());
+  EXPECT_EQ(-1, LeakTracker<ClassB>::NumLiveInstances());
+}
+
+#else
+
+TEST(LeakTrackerTest, Basic) {
+  {
+    ClassA a1;
+
+    EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+
+    ClassB b1;
+    ClassB b2;
+
+    EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+
+    scoped_ptr<ClassA> a2(new ClassA);
+
+    EXPECT_EQ(2, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+
+    a2.reset();
+
+    EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+  }
+
+  EXPECT_EQ(0, LeakTracker<ClassA>::NumLiveInstances());
+  EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+}
+
+// Try some orderings of create/remove to hit different cases in the linked-list
+// assembly.
+TEST(LeakTrackerTest, LinkedList) {
+  EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+
+  scoped_ptr<ClassA> a1(new ClassA);
+  scoped_ptr<ClassA> a2(new ClassA);
+  scoped_ptr<ClassA> a3(new ClassA);
+  scoped_ptr<ClassA> a4(new ClassA);
+
+  EXPECT_EQ(4, LeakTracker<ClassA>::NumLiveInstances());
+
+  // Remove the head of the list (a1).
+  a1.reset();
+  EXPECT_EQ(3, LeakTracker<ClassA>::NumLiveInstances());
+
+  // Remove the tail of the list (a4).
+  a4.reset();
+  EXPECT_EQ(2, LeakTracker<ClassA>::NumLiveInstances());
+
+  // Append to the new tail of the list (a3).
+  scoped_ptr<ClassA> a5(new ClassA);
+  EXPECT_EQ(3, LeakTracker<ClassA>::NumLiveInstances());
+
+  a2.reset();
+  a3.reset();
+
+  EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+
+  a5.reset();
+  EXPECT_EQ(0, LeakTracker<ClassA>::NumLiveInstances());
+}
+
+TEST(LeakTrackerTest, NoOpCheckForLeaks) {
+  // There are no live instances of ClassA, so this should do nothing.
+  LeakTracker<ClassA>::CheckForLeaks();
+}
+
+#endif  // ENABLE_LEAK_TRACKER
+
+}  // namespace
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc
new file mode 100644
index 0000000..de79124
--- /dev/null
+++ b/base/debug/profiler.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/debug/profiler.h"
+
+#include <string>
+
+#include "base/process_util.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+
+#if defined(OS_WIN)
+#include "base/win/pe_image.h"
+#endif  // defined(OS_WIN)
+
+#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
+#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
+#endif
+
+namespace base {
+namespace debug {
+
+#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
+
+static int profile_count = 0;
+
+void StartProfiling(const std::string& name) {
+  ++profile_count;
+  std::string full_name(name);
+  std::string pid = StringPrintf("%d", GetCurrentProcId());
+  std::string count = StringPrintf("%d", profile_count);
+  ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
+  ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
+  ProfilerStart(full_name.c_str());
+}
+
+void StopProfiling() {
+  ProfilerFlush();
+  ProfilerStop();
+}
+
+void FlushProfiling() {
+  ProfilerFlush();
+}
+
+bool BeingProfiled() {
+  return ProfilingIsEnabledForAllThreads();
+}
+
+void RestartProfilingAfterFork() {
+  ProfilerRegisterThread();
+}
+
+#else
+
+void StartProfiling(const std::string& name) {
+}
+
+void StopProfiling() {
+}
+
+void FlushProfiling() {
+}
+
+bool BeingProfiled() {
+  return false;
+}
+
+void RestartProfilingAfterFork() {
+}
+
+#endif
+
+#if !defined(OS_WIN)
+
+bool IsBinaryInstrumented() {
+  return false;
+}
+
+ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
+  return NULL;
+}
+
+#else  // defined(OS_WIN)
+
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+bool IsBinaryInstrumented() {
+  enum InstrumentationCheckState {
+    UNINITIALIZED,
+    INSTRUMENTED_IMAGE,
+    NON_INSTRUMENTED_IMAGE,
+  };
+
+  static InstrumentationCheckState state = UNINITIALIZED;
+
+  if (state == UNINITIALIZED) {
+    HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
+    base::win::PEImage image(this_module);
+
+    // Check to be sure our image is structured as we'd expect.
+    DCHECK(image.VerifyMagic());
+
+    // Syzygy-instrumented binaries contain a PE image section named ".thunks",
+    // and all Syzygy-modified binaries contain the ".syzygy" image section.
+    // This is a very fast check, as it only looks at the image header.
+    if ((image.GetImageSectionHeaderByName(".thunks") != NULL) &&
+        (image.GetImageSectionHeaderByName(".syzygy") != NULL)) {
+      state = INSTRUMENTED_IMAGE;
+    } else {
+      state = NON_INSTRUMENTED_IMAGE;
+    }
+  }
+  DCHECK(state != UNINITIALIZED);
+
+  return state == INSTRUMENTED_IMAGE;
+}
+
+// Callback function to PEImage::EnumImportChunks.
+static bool FindResolutionFunctionInImports(
+    const base::win::PEImage &image, const char* module_name,
+    PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table,
+    PVOID cookie) {
+  // Our import address table contains pointers to the functions we import
+  // at this point. Let's retrieve the first such function and use it to
+  // find the module this import was resolved to by the loader.
+  const wchar_t* function_in_module =
+      reinterpret_cast<const wchar_t*>(import_address_table->u1.Function);
+
+  // Retrieve the module by a function in the module.
+  const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                       GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
+  HMODULE module = NULL;
+  if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) {
+    // This can happen if someone IAT patches us to a thunk.
+    return true;
+  }
+
+  // See whether this module exports the function we're looking for.
+  ReturnAddressLocationResolver exported_func =
+      reinterpret_cast<ReturnAddressLocationResolver>(
+          ::GetProcAddress(module, "ResolveReturnAddressLocation"));
+
+  if (exported_func != NULL) {
+    ReturnAddressLocationResolver* resolver_func =
+        reinterpret_cast<ReturnAddressLocationResolver*>(cookie);
+    DCHECK(resolver_func != NULL);
+    DCHECK(*resolver_func == NULL);
+
+    // We found it, return the function and terminate the enumeration.
+    *resolver_func = exported_func;
+    return false;
+  }
+
+  // Keep going.
+  return true;
+}
+
+ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
+  if (!IsBinaryInstrumented())
+    return NULL;
+
+  HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
+  base::win::PEImage image(this_module);
+
+  ReturnAddressLocationResolver resolver_func = NULL;
+  image.EnumImportChunks(FindResolutionFunctionInImports, &resolver_func);
+
+  return resolver_func;
+}
+
+#endif  // defined(OS_WIN)
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/profiler.h b/base/debug/profiler.h
new file mode 100644
index 0000000..d703876
--- /dev/null
+++ b/base/debug/profiler.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_DEBUG_PROFILER_H
+#define BASE_DEBUG_PROFILER_H
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+// The Profiler functions allow usage of the underlying sampling based
+// profiler. If the application has not been built with the necessary
+// flags (-DENABLE_PROFILING and not -DNO_TCMALLOC) then these functions
+// are noops.
+namespace base {
+namespace debug {
+
+// Start profiling with the supplied name.
+// {pid} will be replaced by the process' pid and {count} will be replaced
+// by the count of the profile run (starts at 1 with each process).
+BASE_EXPORT void StartProfiling(const std::string& name);
+
+// Stop profiling and write out data.
+BASE_EXPORT void StopProfiling();
+
+// Force data to be written to file.
+BASE_EXPORT void FlushProfiling();
+
+// Returns true if process is being profiled.
+BASE_EXPORT bool BeingProfiled();
+
+// Reset profiling after a fork, which disables timers.
+BASE_EXPORT void RestartProfilingAfterFork();
+
+// Returns true iff this executable is instrumented with the Syzygy profiler.
+BASE_EXPORT bool IsBinaryInstrumented();
+
+// There's a class of profilers that use "return address swizzling" to get a
+// hook on function exits. This class of profilers uses some form of entry hook,
+// like e.g. binary instrumentation, or a compiler flag, that calls a hook each
+// time a function is invoked. The hook then switches the return address on the
+// stack for the address of an exit hook function, and pushes the original
+// return address to a shadow stack of some type. When in due course the CPU
+// executes a return to the exit hook, the exit hook will do whatever work it
+// does on function exit, then arrange to return to the original return address.
+// This class of profiler does not play well with programs that look at the
+// return address, as does e.g. V8. V8 uses the return address to certain
+// runtime functions to find the JIT code that called it, and from there finds
+// the V8 data structures associated to the JS function involved.
+// A return address resolution function is used to fix this. It allows such
+// programs to resolve a location on stack where a return address originally
+// resided, to the shadow stack location where the profiler stashed it.
+typedef uintptr_t (*ReturnAddressLocationResolver)(
+    uintptr_t return_addr_location);
+
+// If this binary is instrumented and the instrumentation supplies a return
+// address resolution function, finds and returns the address resolution
+// function. Otherwise returns NULL.
+BASE_EXPORT ReturnAddressLocationResolver
+    GetProfilerReturnAddrResolutionFunc();
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_DEBUGGER_H
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc
new file mode 100644
index 0000000..6fab183
--- /dev/null
+++ b/base/debug/stack_trace.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/debug/stack_trace.h"
+
+#include "base/basictypes.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <sstream>
+
+namespace base {
+namespace debug {
+
+StackTrace::StackTrace(const void* const* trace, size_t count) {
+  count = std::min(count, arraysize(trace_));
+  if (count)
+    memcpy(trace_, trace, count * sizeof(trace_[0]));
+  count_ = count;
+}
+
+StackTrace::~StackTrace() {
+}
+
+const void *const *StackTrace::Addresses(size_t* count) const {
+  *count = count_;
+  if (count_)
+    return trace_;
+  return NULL;
+}
+
+std::string StackTrace::ToString() const {
+  std::stringstream stream;
+  OutputToStream(&stream);
+  return stream.str();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
new file mode 100644
index 0000000..60d5821
--- /dev/null
+++ b/base/debug/stack_trace.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_DEBUG_STACK_TRACE_H_
+#define BASE_DEBUG_STACK_TRACE_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+struct _EXCEPTION_POINTERS;
+#endif
+
+namespace base {
+namespace debug {
+
+// Enables stack dump to console output on exception and signals.
+// When enabled, the process will quit immediately. This is meant to be used in
+// unit_tests only! This is not thread-safe: only call from main thread.
+BASE_EXPORT bool EnableInProcessStackDumping();
+
+// A 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);
+#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 a backtrace to stderr
+  void PrintBacktrace() const;
+
+  // Resolves backtrace to symbols and write to stream.
+  void OutputToStream(std::ostream* os) const;
+
+  // Resolves backtrace to symbols and returns as string.
+  std::string ToString() const;
+
+ private:
+  // From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
+  // the sum of FramesToSkip and FramesToCapture must be less than 63,
+  // so set it to 62. Even if on POSIX it could be a larger value, it usually
+  // doesn't give much more information.
+  static const int kMaxTraces = 62;
+
+  void* trace_[kMaxTraces];
+
+  // The number of valid frames in |trace_|.
+  size_t count_;
+};
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_STACK_TRACE_H_
diff --git a/base/debug/stack_trace_android.cc b/base/debug/stack_trace_android.cc
new file mode 100644
index 0000000..cc03d60
--- /dev/null
+++ b/base/debug/stack_trace_android.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/stack_trace.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace debug {
+
+bool EnableInProcessStackDumping() {
+  // When running in an application, our code typically expects SIGPIPE
+  // to be ignored.  Therefore, when testing that same code, it should run
+  // with SIGPIPE ignored as well.
+  // TODO(phajdan.jr): De-duplicate this SIGPIPE code.
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  action.sa_handler = SIG_IGN;
+  sigemptyset(&action.sa_mask);
+  return (sigaction(SIGPIPE, &action, NULL) == 0);
+}
+
+StackTrace::StackTrace() {
+}
+
+// Sends fake SIGSTKFLT signals to let the Android linker and debuggerd dump
+// stack. See inlined comments and Android bionic/linker/debugger.c and
+// system/core/debuggerd/debuggerd.c for details.
+void StackTrace::PrintBacktrace() const {
+  // Get the current handler of SIGSTKFLT for later use.
+  sighandler_t sig_handler = signal(SIGSTKFLT, SIG_DFL);
+  signal(SIGSTKFLT, sig_handler);
+
+  // The Android linker will handle this signal and send a stack dumping request
+  // to debuggerd which will ptrace_attach this process. Before returning from
+  // the signal handler, the linker sets the signal handler to SIG_IGN.
+  kill(gettid(), SIGSTKFLT);
+
+  // Because debuggerd will wait for the process to be stopped by the actual
+  // signal in crashing scenarios, signal is sent again to met the expectation.
+  // Debuggerd will dump stack into the system log and /data/tombstones/ files.
+  // NOTE: If this process runs in the interactive shell, it will be put
+  // in the background. To resume it in the foreground, use 'fg' command.
+  kill(gettid(), SIGSTKFLT);
+
+  // Restore the signal handler so that this method can work the next time.
+  signal(SIGSTKFLT, sig_handler);
+}
+
+void StackTrace::OutputToStream(std::ostream* os) const {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace_ios.mm b/base/debug/stack_trace_ios.mm
new file mode 100644
index 0000000..ab0abc4
--- /dev/null
+++ b/base/debug/stack_trace_ios.mm
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process_util.h"
+
+#import <Foundation/Foundation.h>
+#include <mach/task.h>
+#include <stdio.h>
+
+#include "base/logging.h"
+
+// This is just enough of a shim to let the support needed by test_support
+// link.
+
+namespace base {
+namespace debug {
+
+namespace {
+
+void StackDumpSignalHandler(int signal) {
+  // TODO(phajdan.jr): Fix async-signal unsafety.
+  LOG(ERROR) << "Received signal " << signal;
+  NSArray *stack_symbols = [NSThread callStackSymbols];
+  for (NSString* stack_symbol in stack_symbols) {
+    fprintf(stderr, "\t%s\n", [stack_symbol UTF8String]);
+  }
+  _exit(1);
+}
+
+}  // namespace
+
+// TODO(phajdan.jr): Deduplicate, see copy in stack_trace_posix.cc.
+bool EnableInProcessStackDumping() {
+  // When running in an application, our code typically expects SIGPIPE
+  // to be ignored.  Therefore, when testing that same code, it should run
+  // with SIGPIPE ignored as well.
+  struct sigaction action;
+  action.sa_handler = SIG_IGN;
+  action.sa_flags = 0;
+  sigemptyset(&action.sa_mask);
+  bool success = (sigaction(SIGPIPE, &action, NULL) == 0);
+
+  success &= (signal(SIGILL, &StackDumpSignalHandler) != SIG_ERR);
+  success &= (signal(SIGABRT, &StackDumpSignalHandler) != SIG_ERR);
+  success &= (signal(SIGFPE, &StackDumpSignalHandler) != SIG_ERR);
+  success &= (signal(SIGBUS, &StackDumpSignalHandler) != SIG_ERR);
+  success &= (signal(SIGSEGV, &StackDumpSignalHandler) != SIG_ERR);
+  success &= (signal(SIGSYS, &StackDumpSignalHandler) != SIG_ERR);
+
+  return success;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
new file mode 100644
index 0000000..ff756fc
--- /dev/null
+++ b/base/debug/stack_trace_posix.cc
@@ -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.
+
+#include "base/debug/stack_trace.h"
+
+#include <errno.h>
+#include <execinfo.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#if defined(__GLIBCXX__)
+#include <cxxabi.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#endif
+
+#include "base/basictypes.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/safe_strerror_posix.h"
+#include "base/string_piece.h"
+#include "base/stringprintf.h"
+
+#if defined(USE_SYMBOLIZE)
+#include "base/third_party/symbolize/symbolize.h"
+#endif
+
+namespace base {
+namespace debug {
+
+namespace {
+
+// 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_";
+
+#if !defined(USE_SYMBOLIZE)
+// Demangles C++ symbols in the given text. Example:
+//
+// "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
+// =>
+// "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
+void DemangleSymbols(std::string* text) {
+#if defined(__GLIBCXX__)
+
+  std::string::size_type search_from = 0;
+  while (search_from < text->size()) {
+    // Look for the start of a mangled symbol, from search_from.
+    std::string::size_type mangled_start =
+        text->find(kMangledSymbolPrefix, search_from);
+    if (mangled_start == std::string::npos) {
+      break;  // Mangled symbol not found.
+    }
+
+    // Look for the end of the mangled symbol.
+    std::string::size_type mangled_end =
+        text->find_first_not_of(kSymbolCharacters, mangled_start);
+    if (mangled_end == std::string::npos) {
+      mangled_end = text->size();
+    }
+    std::string mangled_symbol =
+        text->substr(mangled_start, mangled_end - mangled_start);
+
+    // Try to demangle the mangled symbol candidate.
+    int status = 0;
+    scoped_ptr_malloc<char> demangled_symbol(
+        abi::__cxa_demangle(mangled_symbol.c_str(), NULL, 0, &status));
+    if (status == 0) {  // Demangling is successful.
+      // Remove the mangled symbol.
+      text->erase(mangled_start, mangled_end - mangled_start);
+      // Insert the demangled symbol.
+      text->insert(mangled_start, demangled_symbol.get());
+      // Next time, we'll start right after the demangled symbol we inserted.
+      search_from = mangled_start + strlen(demangled_symbol.get());
+    } else {
+      // Failed to demangle.  Retry after the "_Z" we just found.
+      search_from = mangled_start + 2;
+    }
+  }
+
+#endif  // defined(__GLIBCXX__)
+}
+#endif  // !defined(USE_SYMBOLIZE)
+
+// Gets the backtrace as a vector of strings. If possible, resolve symbol
+// names and attach these. Otherwise just use raw addresses. Returns true
+// if any symbol name is resolved.  Returns false on error and *may* fill
+// in |error_message| if an error message is available.
+bool GetBacktraceStrings(void *const *trace, int size,
+                         std::vector<std::string>* trace_strings,
+                         std::string* error_message) {
+  bool symbolized = false;
+
+#if defined(USE_SYMBOLIZE)
+  for (int i = 0; i < size; ++i) {
+    char symbol[1024];
+    // Subtract by one as return address of function may be in the next
+    // function when a function is annotated as noreturn.
+    if (google::Symbolize(static_cast<char *>(trace[i]) - 1,
+                          symbol, sizeof(symbol))) {
+      // Don't call DemangleSymbols() here as the symbol is demangled by
+      // google::Symbolize().
+      trace_strings->push_back(
+          base::StringPrintf("%s [%p]", symbol, trace[i]));
+      symbolized = true;
+    } else {
+      trace_strings->push_back(base::StringPrintf("%p", trace[i]));
+    }
+  }
+#else
+  scoped_ptr_malloc<char*> trace_symbols(backtrace_symbols(trace, size));
+  if (trace_symbols.get()) {
+    for (int i = 0; i < size; ++i) {
+      std::string trace_symbol = trace_symbols.get()[i];
+      DemangleSymbols(&trace_symbol);
+      trace_strings->push_back(trace_symbol);
+    }
+    symbolized = true;
+  } else {
+    if (error_message)
+      *error_message = safe_strerror(errno);
+    for (int i = 0; i < size; ++i) {
+      trace_strings->push_back(base::StringPrintf("%p", trace[i]));
+    }
+  }
+#endif  // defined(USE_SYMBOLIZE)
+
+  return symbolized;
+}
+
+void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) {
+  if (BeingDebugged())
+    BreakDebugger();
+
+#if defined(OS_MACOSX)
+  // TODO(phajdan.jr): Fix async-signal non-safety (http://crbug.com/101155).
+  DLOG(ERROR) << "Received signal " << signal;
+  StackTrace().PrintBacktrace();
+#endif
+
+  // TODO(shess): Port to Linux.
+#if defined(OS_MACOSX)
+  // TODO(shess): Port to 64-bit.
+#if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS
+  char buf[1024];
+  size_t len;
+
+  // NOTE: Even |snprintf()| is not on the approved list for signal
+  // handlers, but buffered I/O is definitely not on the list due to
+  // potential for |malloc()|.
+  len = static_cast<size_t>(
+      snprintf(buf, sizeof(buf),
+               "ax: %x, bx: %x, cx: %x, dx: %x\n",
+               context->uc_mcontext->__ss.__eax,
+               context->uc_mcontext->__ss.__ebx,
+               context->uc_mcontext->__ss.__ecx,
+               context->uc_mcontext->__ss.__edx));
+  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+
+  len = static_cast<size_t>(
+      snprintf(buf, sizeof(buf),
+               "di: %x, si: %x, bp: %x, sp: %x, ss: %x, flags: %x\n",
+               context->uc_mcontext->__ss.__edi,
+               context->uc_mcontext->__ss.__esi,
+               context->uc_mcontext->__ss.__ebp,
+               context->uc_mcontext->__ss.__esp,
+               context->uc_mcontext->__ss.__ss,
+               context->uc_mcontext->__ss.__eflags));
+  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+
+  len = static_cast<size_t>(
+      snprintf(buf, sizeof(buf),
+               "ip: %x, cs: %x, ds: %x, es: %x, fs: %x, gs: %x\n",
+               context->uc_mcontext->__ss.__eip,
+               context->uc_mcontext->__ss.__cs,
+               context->uc_mcontext->__ss.__ds,
+               context->uc_mcontext->__ss.__es,
+               context->uc_mcontext->__ss.__fs,
+               context->uc_mcontext->__ss.__gs));
+  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+#endif  // ARCH_CPU_32_BITS
+#endif  // defined(OS_MACOSX)
+  _exit(1);
+}
+
+}  // namespace
+
+#if !defined(OS_IOS)
+bool EnableInProcessStackDumping() {
+  // When running in an application, our code typically expects SIGPIPE
+  // to be ignored.  Therefore, when testing that same code, it should run
+  // with SIGPIPE ignored as well.
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  action.sa_handler = SIG_IGN;
+  sigemptyset(&action.sa_mask);
+  bool success = (sigaction(SIGPIPE, &action, NULL) == 0);
+
+  sig_t handler = reinterpret_cast<sig_t>(&StackDumpSignalHandler);
+  success &= (signal(SIGILL, handler) != SIG_ERR);
+  success &= (signal(SIGABRT, handler) != SIG_ERR);
+  success &= (signal(SIGFPE, handler) != SIG_ERR);
+  success &= (signal(SIGBUS, handler) != SIG_ERR);
+  success &= (signal(SIGSEGV, handler) != SIG_ERR);
+  success &= (signal(SIGSYS, handler) != SIG_ERR);
+
+  return success;
+}
+#endif  // !defined(OS_IOS)
+
+StackTrace::StackTrace() {
+  // Though the backtrace API man page does not list any possible negative
+  // return values, we take no chance.
+  count_ = std::max(backtrace(trace_, arraysize(trace_)), 0);
+}
+
+void StackTrace::PrintBacktrace() const {
+  fflush(stderr);
+  std::vector<std::string> trace_strings;
+  GetBacktraceStrings(trace_, count_, &trace_strings, NULL);
+  for (size_t i = 0; i < trace_strings.size(); ++i) {
+    fprintf(stderr, "\t%s\n", trace_strings[i].c_str());
+  }
+}
+
+void StackTrace::OutputToStream(std::ostream* os) const {
+  std::vector<std::string> trace_strings;
+  std::string error_message;
+  if (GetBacktraceStrings(trace_, count_, &trace_strings, &error_message)) {
+    (*os) << "Backtrace:\n";
+  } else {
+    if (!error_message.empty())
+      error_message = " (" + error_message + ")";
+    (*os) << "Unable to get symbols for backtrace" << error_message << ". "
+          << "Dumping raw addresses in trace:\n";
+  }
+
+  for (size_t i = 0; i < trace_strings.size(); ++i) {
+    (*os) << "\t" << trace_strings[i] << "\n";
+  }
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace_unittest.cc b/base/debug/stack_trace_unittest.cc
new file mode 100644
index 0000000..6a35dac
--- /dev/null
+++ b/base/debug/stack_trace_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2011 The Chromium Authors. 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 <string>
+
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace debug {
+
+// Note: On Linux, this test currently only fully works on Debug builds.
+// See comments in the #ifdef soup if you intend to change this.
+#if defined(OS_WIN)
+// Always fails on Windows: crbug.com/32070
+#define MAYBE_OutputToStream DISABLED_OutputToStream
+#else
+#define MAYBE_OutputToStream OutputToStream
+#endif
+TEST(StackTrace, MAYBE_OutputToStream) {
+  StackTrace trace;
+
+  // Dump the trace into a string.
+  std::ostringstream os;
+  trace.OutputToStream(&os);
+  std::string backtrace_message = os.str();
+
+  // ToString() should produce the same output.
+  EXPECT_EQ(backtrace_message, trace.ToString());
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG
+  // Stack traces require an extra data table that bloats our binaries,
+  // so they're turned off for release builds.  We stop the test here,
+  // at least letting us verify that the calls don't crash.
+  return;
+#endif  // defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG
+
+  size_t frames_found = 0;
+  trace.Addresses(&frames_found);
+  ASSERT_GE(frames_found, 5u) <<
+      "No stack frames found.  Skipping rest of test.";
+
+  // Check if the output has symbol initialization warning.  If it does, fail.
+  ASSERT_EQ(backtrace_message.find("Dumping unresolved backtrace"),
+            std::string::npos) <<
+      "Unable to resolve symbols.  Skipping rest of test.";
+
+#if defined(OS_MACOSX)
+#if 0
+  // Disabled due to -fvisibility=hidden in build config.
+
+  // Symbol resolution via the backtrace_symbol function does not work well
+  // in OS X.
+  // See this thread:
+  //
+  //    http://lists.apple.com/archives/darwin-dev/2009/Mar/msg00111.html
+  //
+  // Just check instead that we find our way back to the "start" symbol
+  // which should be the first symbol in the trace.
+  //
+  // TODO(port): Find a more reliable way to resolve symbols.
+
+  // Expect to at least find main.
+  EXPECT_TRUE(backtrace_message.find("start") != std::string::npos)
+      << "Expected to find start in backtrace:\n"
+      << backtrace_message;
+
+#endif
+#elif defined(__GLIBCXX__)
+  // This branch is for gcc-compiled code, but not Mac due to the
+  // above #if.
+  // Expect a demangled symbol.
+  EXPECT_TRUE(backtrace_message.find("testing::Test::Run()") !=
+              std::string::npos)
+      << "Expected a demangled symbol in backtrace:\n"
+      << backtrace_message;
+
+#elif 0
+  // This is the fall-through case; it used to cover Windows.
+  // But it's disabled because of varying buildbot configs;
+  // some lack symbols.
+
+  // Expect to at least find main.
+  EXPECT_TRUE(backtrace_message.find("main") != std::string::npos)
+      << "Expected to find main in backtrace:\n"
+      << backtrace_message;
+
+#if defined(OS_WIN)
+// MSVC doesn't allow the use of C99's __func__ within C++, so we fake it with
+// MSVC's __FUNCTION__ macro.
+#define __func__ __FUNCTION__
+#endif
+
+  // Expect to find this function as well.
+  // Note: This will fail if not linked with -rdynamic (aka -export_dynamic)
+  EXPECT_TRUE(backtrace_message.find(__func__) != std::string::npos)
+      << "Expected to find " << __func__ << " in backtrace:\n"
+      << backtrace_message;
+
+#endif  // define(OS_MACOSX)
+}
+
+// The test is used for manual testing, e.g., to see the raw output.
+TEST(StackTrace, DebugOutputToStream) {
+  StackTrace trace;
+  std::ostringstream os;
+  trace.OutputToStream(&os);
+  VLOG(1) << os.str();
+}
+
+// The test is used for manual testing, e.g., to see the raw output.
+TEST(StackTrace, DebugPrintBacktrace) {
+  StackTrace().PrintBacktrace();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc
new file mode 100644
index 0000000..da75b0b
--- /dev/null
+++ b/base/debug/stack_trace_win.cc
@@ -0,0 +1,235 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/stack_trace.h"
+
+#include <windows.h>
+#include <dbghelp.h>
+
+#include <iostream>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/process_util.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+// Previous unhandled filter. Will be called if not NULL when we intercept an
+// exception. Only used in unit tests.
+LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
+
+// Prints the exception call stack.
+// This is the unit tests exception filter.
+long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) {
+  debug::StackTrace(info).PrintBacktrace();
+  if (g_previous_filter)
+    return g_previous_filter(info);
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+
+// SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family
+// of functions.  The Sym* family of functions may only be invoked by one
+// thread at a time.  SymbolContext code may access a symbol server over the
+// network while holding the lock for this singleton.  In the case of high
+// latency, this code will adversely affect performance.
+//
+// There is also a known issue where this backtrace code can interact
+// badly with breakpad if breakpad is invoked in a separate thread while
+// we are using the Sym* functions.  This is because breakpad does now
+// share a lock with this function.  See this related bug:
+//
+//   http://code.google.com/p/google-breakpad/issues/detail?id=311
+//
+// This is a very unlikely edge case, and the current solution is to
+// just ignore it.
+class SymbolContext {
+ public:
+  static SymbolContext* GetInstance() {
+    // We use a leaky singleton because code may call this during process
+    // termination.
+    return
+      Singleton<SymbolContext, LeakySingletonTraits<SymbolContext> >::get();
+  }
+
+  // Returns the error code of a failed initialization.
+  DWORD init_error() const {
+    return init_error_;
+  }
+
+  // For the given trace, attempts to resolve the symbols, and output a trace
+  // to the ostream os.  The format for each line of the backtrace is:
+  //
+  //    <tab>SymbolName[0xAddress+Offset] (FileName:LineNo)
+  //
+  // This function should only be called if Init() has been called.  We do not
+  // LOG(FATAL) here because this code is called might be triggered by a
+  // LOG(FATAL) itself.
+  void OutputTraceToStream(const void* const* trace,
+                           size_t count,
+                           std::ostream* os) {
+    base::AutoLock lock(lock_);
+
+    for (size_t i = 0; (i < count) && os->good(); ++i) {
+      const int kMaxNameLength = 256;
+      DWORD_PTR frame = reinterpret_cast<DWORD_PTR>(trace[i]);
+
+      // Code adapted from MSDN example:
+      // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
+      ULONG64 buffer[
+        (sizeof(SYMBOL_INFO) +
+          kMaxNameLength * sizeof(wchar_t) +
+          sizeof(ULONG64) - 1) /
+        sizeof(ULONG64)];
+      memset(buffer, 0, sizeof(buffer));
+
+      // Initialize symbol information retrieval structures.
+      DWORD64 sym_displacement = 0;
+      PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(&buffer[0]);
+      symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+      symbol->MaxNameLen = kMaxNameLength - 1;
+      BOOL has_symbol = SymFromAddr(GetCurrentProcess(), frame,
+                                    &sym_displacement, symbol);
+
+      // Attempt to retrieve line number information.
+      DWORD line_displacement = 0;
+      IMAGEHLP_LINE64 line = {};
+      line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+      BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame,
+                                           &line_displacement, &line);
+
+      // Output the backtrace line.
+      (*os) << "\t";
+      if (has_symbol) {
+        (*os) << symbol->Name << " [0x" << trace[i] << "+"
+              << sym_displacement << "]";
+      } else {
+        // If there is no symbol information, add a spacer.
+        (*os) << "(No symbol) [0x" << trace[i] << "]";
+      }
+      if (has_line) {
+        (*os) << " (" << line.FileName << ":" << line.LineNumber << ")";
+      }
+      (*os) << "\n";
+    }
+  }
+
+ private:
+  friend struct DefaultSingletonTraits<SymbolContext>;
+
+  SymbolContext() : init_error_(ERROR_SUCCESS) {
+    // Initializes the symbols for the process.
+    // Defer symbol load until they're needed, use undecorated names, and
+    // get line numbers.
+    SymSetOptions(SYMOPT_DEFERRED_LOADS |
+                  SYMOPT_UNDNAME |
+                  SYMOPT_LOAD_LINES);
+    if (SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
+      init_error_ = ERROR_SUCCESS;
+    } else {
+      init_error_ = GetLastError();
+      // TODO(awong): Handle error: SymInitialize can fail with
+      // ERROR_INVALID_PARAMETER.
+      // When it fails, we should not call debugbreak since it kills the current
+      // process (prevents future tests from running or kills the browser
+      // process).
+      DLOG(ERROR) << "SymInitialize failed: " << init_error_;
+    }
+  }
+
+  DWORD init_error_;
+  base::Lock lock_;
+  DISALLOW_COPY_AND_ASSIGN(SymbolContext);
+};
+
+}  // namespace
+
+bool EnableInProcessStackDumping() {
+  // Add stack dumping support on exception on windows. Similar to OS_POSIX
+  // signal() handling in process_util_posix.cc.
+  g_previous_filter = SetUnhandledExceptionFilter(&StackDumpExceptionFilter);
+  RouteStdioToConsole();
+  return true;
+}
+
+// Disable optimizations for the StackTrace::StackTrace function. It is
+// important to disable at least frame pointer optimization ("y"), since
+// that breaks CaptureStackBackTrace() and prevents StackTrace from working
+// in Release builds (it may still be janky if other frames are using FPO,
+// but at least it will make it further).
+#if defined(COMPILER_MSVC)
+#pragma optimize("", off)
+#endif
+
+StackTrace::StackTrace() {
+  // When walking our own stack, use CaptureStackBackTrace().
+  count_ = CaptureStackBackTrace(0, arraysize(trace_), trace_, NULL);
+}
+
+#if defined(COMPILER_MSVC)
+#pragma optimize("", on)
+#endif
+
+StackTrace::StackTrace(EXCEPTION_POINTERS* exception_pointers) {
+  // When walking an exception stack, we need to use StackWalk64().
+  count_ = 0;
+  // Initialize stack walking.
+  STACKFRAME64 stack_frame;
+  memset(&stack_frame, 0, sizeof(stack_frame));
+#if defined(_WIN64)
+  int machine_type = IMAGE_FILE_MACHINE_AMD64;
+  stack_frame.AddrPC.Offset = exception_pointers->ContextRecord->Rip;
+  stack_frame.AddrFrame.Offset = exception_pointers->ContextRecord->Rbp;
+  stack_frame.AddrStack.Offset = exception_pointers->ContextRecord->Rsp;
+#else
+  int machine_type = IMAGE_FILE_MACHINE_I386;
+  stack_frame.AddrPC.Offset = exception_pointers->ContextRecord->Eip;
+  stack_frame.AddrFrame.Offset = exception_pointers->ContextRecord->Ebp;
+  stack_frame.AddrStack.Offset = exception_pointers->ContextRecord->Esp;
+#endif
+  stack_frame.AddrPC.Mode = AddrModeFlat;
+  stack_frame.AddrFrame.Mode = AddrModeFlat;
+  stack_frame.AddrStack.Mode = AddrModeFlat;
+  while (StackWalk64(machine_type,
+                     GetCurrentProcess(),
+                     GetCurrentThread(),
+                     &stack_frame,
+                     exception_pointers->ContextRecord,
+                     NULL,
+                     &SymFunctionTableAccess64,
+                     &SymGetModuleBase64,
+                     NULL) &&
+         count_ < arraysize(trace_)) {
+    trace_[count_++] = reinterpret_cast<void*>(stack_frame.AddrPC.Offset);
+  }
+
+  for (size_t i = count_; i < arraysize(trace_); ++i)
+    trace_[i] = NULL;
+}
+
+void StackTrace::PrintBacktrace() const {
+  OutputToStream(&std::cerr);
+}
+
+void StackTrace::OutputToStream(std::ostream* os) const {
+  SymbolContext* context = SymbolContext::GetInstance();
+  DWORD error = context->init_error();
+  if (error != ERROR_SUCCESS) {
+    (*os) << "Error initializing symbols (" << error
+          << ").  Dumping unresolved backtrace:\n";
+    for (int i = 0; (i < count_) && os->good(); ++i) {
+      (*os) << "\t" << trace_[i] << "\n";
+    }
+  } else {
+    (*os) << "Backtrace:\n";
+    context->OutputTraceToStream(trace_, count_, os);
+  }
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/trace_event.cc b/base/debug/trace_event.cc
new file mode 100644
index 0000000..4298bba
--- /dev/null
+++ b/base/debug/trace_event.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/trace_event.h"
+
+namespace trace_event_internal {
+
+void TraceEndOnScopeClose::Initialize(const unsigned char* category_enabled,
+                                      const char* name) {
+  data_.category_enabled = category_enabled;
+  data_.name = name;
+  p_data_ = &data_;
+}
+
+void TraceEndOnScopeClose::AddEventIfEnabled() {
+  // Only called when p_data_ is non-null.
+  if (TRACE_EVENT_API_IS_ATRACE_ENABLED() || *p_data_->category_enabled) {
+    TRACE_EVENT_API_ADD_TRACE_EVENT(
+        TRACE_EVENT_PHASE_END,
+        p_data_->category_enabled,
+        p_data_->name, kNoEventId,
+        kZeroNumArgs, NULL, NULL, NULL,
+        kNoThreshholdBeginId, kNoThresholdValue, TRACE_EVENT_FLAG_NONE);
+  }
+}
+
+void TraceEndOnScopeCloseThreshold::Initialize(
+                                      const unsigned char* category_enabled,
+                                      const char* name,
+                                      int threshold_begin_id,
+                                      long long threshold) {
+  data_.category_enabled = category_enabled;
+  data_.name = name;
+  data_.threshold_begin_id = threshold_begin_id;
+  data_.threshold = threshold;
+  p_data_ = &data_;
+}
+
+void TraceEndOnScopeCloseThreshold::AddEventIfEnabled() {
+  // Only called when p_data_ is non-null.
+  if (TRACE_EVENT_API_IS_ATRACE_ENABLED() || *p_data_->category_enabled) {
+    TRACE_EVENT_API_ADD_TRACE_EVENT(
+        TRACE_EVENT_PHASE_END,
+        p_data_->category_enabled,
+        p_data_->name, kNoEventId,
+        kZeroNumArgs, NULL, NULL, NULL,
+        p_data_->threshold_begin_id, p_data_->threshold,
+        TRACE_EVENT_FLAG_NONE);
+  }
+}
+
+}  // namespace trace_event_internal
diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h
new file mode 100644
index 0000000..f78bb3c
--- /dev/null
+++ b/base/debug/trace_event.h
@@ -0,0 +1,1014 @@
+// Copyright (c) 2012 The Chromium 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 is designed to give you trace_event macros without specifying
+// how the events actually get collected and stored. If you need to expose trace
+// event to some other universe, you can copy-and-paste this file,
+// implement the TRACE_EVENT_API macros, and do any other necessary fixup for
+// the target platform. The end result is that multiple libraries can funnel
+// events through to a shared trace event collector.
+
+// Trace events are for tracking application performance and resource usage.
+// Macros are provided to track:
+//    Begin and end of function calls
+//    Counters
+//
+// Events are issued against categories. Whereas LOG's
+// categories are statically defined, TRACE categories are created
+// implicitly with a string. For example:
+//   TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent")
+//
+// 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 disembiguate 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, name, and arg_names.  Thus, the following code will
+// cause problems:
+//     char* str = strdup("impprtantName");
+//     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"));
+//
+//
+// 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_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 aquiring a lock
+// and resolving the category.
+
+
+#ifndef BASE_DEBUG_TRACE_EVENT_H_
+#define BASE_DEBUG_TRACE_EVENT_H_
+
+#include <string>
+
+#include "base/atomicops.h"
+#include "base/debug/trace_event_impl.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 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)
+
+// 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, name) \
+    INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name)
+#define TRACE_EVENT1(category, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val)
+#define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+
+// Same as TRACE_EVENT except that they are not included in official builds.
+#ifdef OFFICIAL_BUILD
+#define UNSHIPPED_TRACE_EVENT0(category, name) (void)0
+#define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) (void)0
+#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, \
+                               arg2_name, arg2_val) (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
+    (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
+                                       arg2_name, arg2_val) (void)0
+#else
+#define UNSHIPPED_TRACE_EVENT0(category, name) \
+    TRACE_EVENT0(category, name)
+#define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) \
+    TRACE_EVENT1(category, name, arg1_name, arg1_val)
+#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, \
+                               arg2_name, arg2_val) \
+    TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val)
+#define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) \
+    TRACE_EVENT_INSTANT0(category, name)
+#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
+    TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val)
+#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
+                                       arg2_name, arg2_val) \
+    TRACE_EVENT_INSTANT2(category, name, 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, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category, name, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_INSTANT0(category, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category, name, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+
+// 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, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category, name, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_BEGIN0(category, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category, name, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category, name, 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, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category, name, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_END0(category, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category, name, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+
+// Time threshold event:
+// Only record the event if the duration is greater than the specified
+// threshold_us (time in microseconds).
+// 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_EVENT_IF_LONGER_THAN0(threshold_us, category, name) \
+    INTERNAL_TRACE_EVENT_ADD_SCOPED_IF_LONGER_THAN(threshold_us, category, name)
+#define TRACE_EVENT_IF_LONGER_THAN1( \
+    threshold_us, category, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_SCOPED_IF_LONGER_THAN( \
+        threshold_us, category, name, arg1_name, arg1_val)
+#define TRACE_EVENT_IF_LONGER_THAN2( \
+    threshold_us, category, name, arg1_name, arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_SCOPED_IF_LONGER_THAN( \
+        threshold_us, category, name, 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, name, value) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category, name, TRACE_EVENT_FLAG_NONE, \
+        "value", static_cast<int>(value))
+#define TRACE_COPY_COUNTER1(category, name, value) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category, 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, name, value1_name, value1_val, \
+        value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category, name, TRACE_EVENT_FLAG_NONE, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \
+        value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category, name, TRACE_EVENT_FLAG_COPY, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+
+// Records the value of a counter called "name" immediately. Value
+// must be representable as a 32 bit integer.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to disambiguate counters with the same name. It must either
+//   be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
+//   will be xored with a hash of the process ID so that the same pointer on
+//   two different processes will not collide.
+#define TRACE_COUNTER_ID1(category, name, id, value) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, \
+        "value", static_cast<int>(value))
+#define TRACE_COPY_COUNTER_ID1(category, name, id, value) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category, 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, name, id, value1_name, value1_val, \
+        value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category, 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, name, id, value1_name, value1_val, \
+        value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+
+
+// 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, 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 macros. When the operation completes, call ASYNC_END.
+// An ASYNC trace typically occur 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 event can have its own
+// args.
+#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single ASYNC_STEP 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.
+#define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, \
+                                      arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, "step", step)
+#define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, \
+        arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, "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, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, \
+        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, 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, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category, 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, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_FLOW_STEP1(category, name, id, step, \
+        arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, "step", step)
+#define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, \
+        arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category, 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, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_END0(category, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+
+////////////////////////////////////////////////////////////////////////////////
+// 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 name. 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_ENABLED(const char* category_name)
+#define TRACE_EVENT_API_GET_CATEGORY_ENABLED \
+    base::debug::TraceLog::GetCategoryEnabled
+
+// Add a trace event to the platform tracing system. Returns thresholdBeginId
+// for use in a corresponding end TRACE_EVENT_API_ADD_TRACE_EVENT call.
+// int TRACE_EVENT_API_ADD_TRACE_EVENT(
+//                    char phase,
+//                    const unsigned char* category_enabled,
+//                    const char* name,
+//                    unsigned long long id,
+//                    int num_args,
+//                    const char** arg_names,
+//                    const unsigned char* arg_types,
+//                    const unsigned long long* arg_values,
+//                    int threshold_begin_id,
+//                    long long threshold,
+//                    unsigned char flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT \
+    base::debug::TraceLog::GetInstance()->AddTraceEvent
+
+// Checks if Android ATrace is enabled.
+#if defined(OS_ANDROID)
+#define TRACE_EVENT_API_IS_ATRACE_ENABLED() \
+    base::debug::TraceLog::IsATraceEnabled()
+#else
+#define TRACE_EVENT_API_IS_ATRACE_ENABLED() false
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+// 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 collissions.
+#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(category) \
+    static base::subtle::AtomicWord INTERNAL_TRACE_EVENT_UID(atomic) = 0; \
+    const uint8* INTERNAL_TRACE_EVENT_UID(catstatic) = \
+        reinterpret_cast<const uint8*>( \
+            base::subtle::NoBarrier_Load(&INTERNAL_TRACE_EVENT_UID(atomic))); \
+    if (!INTERNAL_TRACE_EVENT_UID(catstatic)) { \
+      INTERNAL_TRACE_EVENT_UID(catstatic) = \
+          TRACE_EVENT_API_GET_CATEGORY_ENABLED(category); \
+      base::subtle::NoBarrier_Store(&INTERNAL_TRACE_EVENT_UID(atomic), \
+          reinterpret_cast<base::subtle::AtomicWord>( \
+              INTERNAL_TRACE_EVENT_UID(catstatic))); \
+    }
+
+// Implementation detail: internal macro to check if Android ATrace or the
+// current category (using the current static category variable) is enabled.
+#define INTERNAL_TRACE_EVENT_IS_ATRACE_OR_CATEGORY_ENABLED() \
+    TRACE_EVENT_API_IS_ATRACE_ENABLED() || *INTERNAL_TRACE_EVENT_UID(catstatic)
+
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \
+    do { \
+      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
+      if (INTERNAL_TRACE_EVENT_IS_ATRACE_OR_CATEGORY_ENABLED()) { \
+        trace_event_internal::AddTraceEvent( \
+            phase, INTERNAL_TRACE_EVENT_UID(catstatic), name, \
+            trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \
+      } \
+    } while (0)
+
+// Implementation detail: internal macro to create static category and add begin
+// event if the category is enabled. Also adds the end event when the scope
+// ends.
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
+    trace_event_internal::TraceEndOnScopeClose \
+        INTERNAL_TRACE_EVENT_UID(profileScope); \
+    if (INTERNAL_TRACE_EVENT_IS_ATRACE_OR_CATEGORY_ENABLED()) { \
+      trace_event_internal::AddTraceEvent( \
+          TRACE_EVENT_PHASE_BEGIN, \
+          INTERNAL_TRACE_EVENT_UID(catstatic), \
+          name, trace_event_internal::kNoEventId, \
+          TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \
+      INTERNAL_TRACE_EVENT_UID(profileScope).Initialize( \
+          INTERNAL_TRACE_EVENT_UID(catstatic), name); \
+    }
+
+// 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. If the elapsed time is < threshold time, the begin/end pair is erased.
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED_IF_LONGER_THAN(threshold, \
+        category, name, ...) \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
+    trace_event_internal::TraceEndOnScopeCloseThreshold \
+        INTERNAL_TRACE_EVENT_UID(profileScope); \
+    if (INTERNAL_TRACE_EVENT_IS_ATRACE_OR_CATEGORY_ENABLED()) { \
+      int INTERNAL_TRACE_EVENT_UID(begin_event_id) = \
+        trace_event_internal::AddTraceEvent( \
+            TRACE_EVENT_PHASE_BEGIN, \
+            INTERNAL_TRACE_EVENT_UID(catstatic), \
+            name, trace_event_internal::kNoEventId, \
+            TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \
+      INTERNAL_TRACE_EVENT_UID(profileScope).Initialize( \
+          INTERNAL_TRACE_EVENT_UID(catstatic), name, \
+          INTERNAL_TRACE_EVENT_UID(begin_event_id), threshold); \
+    }
+
+// 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, name, id, flags, \
+                                         ...) \
+    do { \
+      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
+      if (INTERNAL_TRACE_EVENT_IS_ATRACE_OR_CATEGORY_ENABLED()) { \
+        unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+        trace_event_internal::TraceID trace_event_trace_id( \
+            id, &trace_event_flags); \
+        trace_event_internal::AddTraceEvent( \
+            phase, INTERNAL_TRACE_EVENT_UID(catstatic), \
+            name, trace_event_trace_id.data(), trace_event_flags, \
+            ##__VA_ARGS__); \
+      } \
+    } while (0)
+
+// Notes regarding the following definitions:
+// New values can be added and propagated to third party libraries, but existing
+// definitions must never be changed, because third party libraries may use old
+// definitions.
+
+// Phase indicates the nature of an event entry. E.g. part of a begin/end pair.
+#define TRACE_EVENT_PHASE_BEGIN    ('B')
+#define TRACE_EVENT_PHASE_END      ('E')
+#define TRACE_EVENT_PHASE_INSTANT  ('I')
+#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S')
+#define TRACE_EVENT_PHASE_ASYNC_STEP  ('T')
+#define TRACE_EVENT_PHASE_ASYNC_END   ('F')
+#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')
+
+// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
+#define TRACE_EVENT_FLAG_NONE        (static_cast<unsigned char>(0))
+#define TRACE_EVENT_FLAG_COPY        (static_cast<unsigned char>(1 << 0))
+#define TRACE_EVENT_FLAG_HAS_ID      (static_cast<unsigned char>(1 << 1))
+#define TRACE_EVENT_FLAG_MANGLE_ID   (static_cast<unsigned char>(1 << 2))
+
+// 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))
+
+namespace trace_event_internal {
+
+// Specify these values when the corresponding argument of AddTraceEvent is not
+// used.
+const int kZeroNumArgs = 0;
+const int kNoThreshholdBeginId = -1;
+const long long kNoThresholdValue = 0;
+const unsigned long long kNoEventId = 0;
+
+// TraceID encapsulates an ID that can either be an integer or pointer. Pointers
+// are 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 ForceMangle {
+    public:
+     explicit ForceMangle(unsigned long long id) : data_(id) {}
+     explicit ForceMangle(unsigned long id) : data_(id) {}
+     explicit ForceMangle(unsigned int id) : data_(id) {}
+     explicit ForceMangle(unsigned short id) : data_(id) {}
+     explicit ForceMangle(unsigned char id) : data_(id) {}
+     explicit ForceMangle(long long id)
+         : data_(static_cast<unsigned long long>(id)) {}
+     explicit ForceMangle(long id)
+         : data_(static_cast<unsigned long long>(id)) {}
+     explicit ForceMangle(int id)
+         : data_(static_cast<unsigned long long>(id)) {}
+     explicit ForceMangle(short id)
+         : data_(static_cast<unsigned long long>(id)) {}
+     explicit ForceMangle(signed char id)
+         : data_(static_cast<unsigned long long>(id)) {}
+
+     unsigned long long data() const { return data_; }
+
+    private:
+     unsigned long long data_;
+  };
+
+  explicit TraceID(const void* id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(
+              reinterpret_cast<unsigned long>(id))) {
+    *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+  }
+  explicit TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) {
+    *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+  }
+  explicit TraceID(unsigned long long id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  explicit TraceID(unsigned long id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  explicit TraceID(unsigned int id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  explicit TraceID(unsigned short id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  explicit TraceID(unsigned char id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  explicit TraceID(long long id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  explicit TraceID(long id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  explicit TraceID(int id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  explicit TraceID(short id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  explicit TraceID(signed char id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+
+  unsigned long long data() const { return data_; }
+
+ private:
+  unsigned long long data_;
+};
+
+// Simple union to store various types as unsigned long long.
+union TraceValueUnion {
+  bool as_bool;
+  unsigned long long as_uint;
+  long long as_int;
+  double as_double;
+  const void* as_pointer;
+  const char* as_string;
+};
+
+// Simple container for const char* that should be copied instead of retained.
+class TraceStringWithCopy {
+ public:
+  explicit TraceStringWithCopy(const char* str) : str_(str) {}
+  operator const char* () 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, \
+                                         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; \
+      *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, as_bool, TRACE_VALUE_TYPE_BOOL)
+INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer,
+                                 TRACE_VALUE_TYPE_POINTER)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string,
+                                 TRACE_VALUE_TYPE_STRING)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, 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;
+}
+
+// These AddTraceEvent template functions are defined here instead of in the
+// macro, because the arg_values could be temporary objects, such as
+// std::string. In order to store pointers to the internal c_str and pass
+// through to the tracing API, the arg_values must live throughout
+// these procedures.
+
+static inline int AddTraceEvent(char phase,
+                                const unsigned char* category_enabled,
+                                const char* name,
+                                unsigned long long id,
+                                unsigned char flags) {
+  return TRACE_EVENT_API_ADD_TRACE_EVENT(
+      phase, category_enabled, name, id,
+      kZeroNumArgs, NULL, NULL, NULL,
+      kNoThreshholdBeginId, kNoThresholdValue, flags);
+}
+
+template<class ARG1_TYPE>
+static inline int AddTraceEvent(char phase,
+                                const unsigned char* category_enabled,
+                                const char* name,
+                                unsigned long long id,
+                                unsigned char flags,
+                                const char* arg1_name,
+                                const ARG1_TYPE& arg1_val) {
+  const int num_args = 1;
+  unsigned char arg_types[1];
+  unsigned long long arg_values[1];
+  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+  return TRACE_EVENT_API_ADD_TRACE_EVENT(
+      phase, category_enabled, name, id,
+      num_args, &arg1_name, arg_types, arg_values,
+      kNoThreshholdBeginId, kNoThresholdValue, flags);
+}
+
+template<class ARG1_TYPE, class ARG2_TYPE>
+static inline int AddTraceEvent(char phase,
+                                const unsigned char* category_enabled,
+                                const char* name,
+                                unsigned long long id,
+                                unsigned char flags,
+                                const char* arg1_name,
+                                const ARG1_TYPE& arg1_val,
+                                const char* arg2_name,
+                                const ARG2_TYPE& arg2_val) {
+  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(
+      phase, category_enabled, name, id,
+      num_args, arg_names, arg_types, arg_values,
+      kNoThreshholdBeginId, kNoThresholdValue, flags);
+}
+
+// Used by TRACE_EVENTx macro. Do not use directly.
+class BASE_EXPORT TraceEndOnScopeClose {
+ public:
+  // Note: members of data_ intentionally left uninitialized. See Initialize.
+  TraceEndOnScopeClose() : p_data_(NULL) {}
+  ~TraceEndOnScopeClose() {
+    if (p_data_)
+      AddEventIfEnabled();
+  }
+
+  void Initialize(const unsigned char* category_enabled,
+                  const char* name);
+
+ private:
+  // Add the end event if the category is still enabled.
+  void AddEventIfEnabled();
+
+  // 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_enabled;
+    const char* name;
+  };
+  Data* p_data_;
+  Data data_;
+};
+
+// Used by TRACE_EVENTx macro. Do not use directly.
+class BASE_EXPORT TraceEndOnScopeCloseThreshold {
+ public:
+  // Note: members of data_ intentionally left uninitialized. See Initialize.
+  TraceEndOnScopeCloseThreshold() : p_data_(NULL) {}
+  ~TraceEndOnScopeCloseThreshold() {
+    if (p_data_)
+      AddEventIfEnabled();
+  }
+
+  // Called by macros only when tracing is enabled at the point when the begin
+  // event is added.
+  void Initialize(const unsigned char* category_enabled,
+                  const char* name,
+                  int threshold_begin_id,
+                  long long threshold);
+
+ private:
+  // Add the end event if the category is still enabled.
+  void AddEventIfEnabled();
+
+  // 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 {
+    long long threshold;
+    const unsigned char* category_enabled;
+    const char* name;
+    int threshold_begin_id;
+  };
+  Data* p_data_;
+  Data data_;
+};
+
+}  // namespace trace_event_internal
+
+#endif  // BASE_DEBUG_TRACE_EVENT_H_
diff --git a/base/debug/trace_event_android.cc b/base/debug/trace_event_android.cc
new file mode 100644
index 0000000..2fbbc44
--- /dev/null
+++ b/base/debug/trace_event_android.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/trace_event_impl.h"
+
+#include <fcntl.h>
+
+#include "base/debug/trace_event.h"
+#include "base/file_util.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/stringprintf.h"
+
+namespace {
+
+int g_atrace_fd = -1;
+const char* kATraceMarkerFile = "/sys/kernel/debug/tracing/trace_marker";
+
+}  // namespace
+
+namespace base {
+namespace debug {
+
+// static
+void TraceLog::InitATrace() {
+  DCHECK(g_atrace_fd == -1);
+  g_atrace_fd = open(kATraceMarkerFile, O_WRONLY | O_APPEND);
+  if (g_atrace_fd == -1)
+    LOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
+}
+
+// static
+bool TraceLog::IsATraceEnabled() {
+  return g_atrace_fd != -1;
+}
+
+void TraceLog::SendToATrace(char phase,
+                            const char* category,
+                            const char* name,
+                            int num_args,
+                            const char** arg_names,
+                            const unsigned char* arg_types,
+                            const unsigned long long* arg_values) {
+  if (!IsATraceEnabled())
+    return;
+
+  switch (phase) {
+    case TRACE_EVENT_PHASE_BEGIN:
+    case TRACE_EVENT_PHASE_INSTANT: {
+      std::string out = StringPrintf("B|%d|%s-%s", getpid(), category, name);
+      for (int i = 0; i < num_args; ++i) {
+        out += (i == 0 ? '|' : ';');
+        out += arg_names[i];
+        out += '=';
+        TraceEvent::TraceValue value;
+        value.as_uint = arg_values[i];
+        std::string::size_type value_start = out.length();
+        TraceEvent::AppendValueAsJSON(arg_types[i], value, &out);
+        // Remove the quotes which may confuse the atrace script.
+        ReplaceSubstringsAfterOffset(&out, value_start, "\\\"", "'");
+        ReplaceSubstringsAfterOffset(&out, value_start, "\"", "");
+        // Replace chars used for separators with similar chars in the value.
+        std::replace(out.begin() + value_start, out.end(), ';', ',');
+        std::replace(out.begin() + value_start, out.end(), '|', '!');
+      }
+      write(g_atrace_fd, out.c_str(), out.size());
+
+      if (phase != TRACE_EVENT_PHASE_INSTANT)
+        break;
+      // Fall through. Simulate an instance event with a pair of begin/end.
+    }
+    case TRACE_EVENT_PHASE_END: {
+      // Though a single 'E' is enough, here append pid and name so that
+      // unpaired events can be found easily.
+      std::string out = StringPrintf("E|%d|%s-%s", getpid(), category, name);
+      write(g_atrace_fd, out.c_str(), out.size());
+      break;
+    }
+    case TRACE_EVENT_PHASE_COUNTER:
+      for (int i = 0; i < num_args; ++i) {
+        DCHECK(arg_types[i] == TRACE_VALUE_TYPE_INT);
+        std::string out = StringPrintf(
+            "C|%d|%s-%s-%s|%d",
+            getpid(), category, name,
+            arg_names[i], static_cast<int>(arg_values[i]));
+        write(g_atrace_fd, out.c_str(), out.size());
+      }
+      break;
+
+    default:
+      // Do nothing.
+      break;
+  }
+}
+
+void TraceLog::AddClockSyncMetadataEvents() {
+  // Since Android does not support sched_setaffinity, we cannot establish clock
+  // sync unless the scheduler clock is set to global. If the trace_clock file
+  // can't be read, we will assume the kernel doesn't support tracing and do
+  // nothing.
+  std::string clock_mode;
+  if (!file_util::ReadFileToString(
+      FilePath("/sys/kernel/debug/tracing/trace_clock"), &clock_mode))
+    return;
+
+  if (clock_mode != "local [global]\n") {
+    DLOG(WARNING) <<
+        "The kernel's tracing clock must be set to global in order for " <<
+        "trace_event to be synchronized with . Do this by\n" <<
+        "  echo global > /sys/kerel/debug/tracing/trace_clock";
+    return;
+  }
+
+  int atrace_fd = g_atrace_fd;
+  if (atrace_fd == -1) {
+    // This function may be called when atrace is not enabled.
+    atrace_fd = open(kATraceMarkerFile, O_WRONLY | O_APPEND);
+    if (atrace_fd == -1) {
+      LOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
+      return;
+    }
+  }
+
+  // Android's kernel trace system has a trace_marker feature: this is a file on
+  // debugfs that takes the written data and pushes it onto the trace
+  // buffer. So, to establish clock sync, we write our monotonic clock into that
+  // trace buffer.
+  TimeTicks now = TimeTicks::NowFromSystemTraceTime();
+  double now_in_seconds = now.ToInternalValue() / 1000000.0;
+  std::string marker = StringPrintf(
+      "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
+  if (write(atrace_fd, marker.c_str(), marker.size()) != 0) {
+    DLOG(WARNING) << "Couldn't write to " << kATraceMarkerFile << ": "
+                  << strerror(errno);
+  }
+
+  if (g_atrace_fd == -1)
+    close(atrace_fd);
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
new file mode 100644
index 0000000..fa23def
--- /dev/null
+++ b/base/debug/trace_event_impl.cc
@@ -0,0 +1,793 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/trace_event_impl.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/debug/trace_event.h"
+#include "base/format_macros.h"
+#include "base/lazy_instance.h"
+#include "base/memory/singleton.h"
+#include "base/process_util.h"
+#include "base/stl_util.h"
+#include "base/stringprintf.h"
+#include "base/string_tokenizer.h"
+#include "base/string_util.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_local.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+
+#if defined(OS_WIN)
+#include "base/debug/trace_event_win.h"
+#endif
+
+class DeleteTraceLogForTesting {
+ public:
+  static void Delete() {
+    Singleton<base::debug::TraceLog,
+              StaticMemorySingletonTraits<base::debug::TraceLog> >::OnExit(0);
+  }
+};
+
+namespace base {
+namespace debug {
+
+// Controls the number of trace events we will buffer in-memory
+// before throwing them away.
+const size_t kTraceEventBufferSize = 500000;
+const size_t kTraceEventBatchSize = 1000;
+
+#define TRACE_EVENT_MAX_CATEGORIES 100
+
+namespace {
+
+// Parallel arrays g_categories and g_category_enabled are separate so that
+// a pointer to a member of g_category_enabled can be easily converted to an
+// index into g_categories. This allows macros to deal only with char enabled
+// pointers from g_category_enabled, and we can convert internally to determine
+// the category name from the char enabled pointer.
+const char* g_categories[TRACE_EVENT_MAX_CATEGORIES] = {
+  "tracing already shutdown",
+  "tracing categories exhausted; must increase TRACE_EVENT_MAX_CATEGORIES",
+  "__metadata",
+};
+// The enabled flag is char instead of bool so that the API can be used from C.
+unsigned char g_category_enabled[TRACE_EVENT_MAX_CATEGORIES] = { 0 };
+const int g_category_already_shutdown = 0;
+const int g_category_categories_exhausted = 1;
+const int g_category_metadata = 2;
+int g_category_index = 3; // skip initial 3 categories
+
+// The most-recently captured name of the current thread
+LazyInstance<ThreadLocalPointer<const char> >::Leaky
+    g_current_thread_name = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceEvent
+//
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+size_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; }
+
+// Copies |*member| into |*buffer|, sets |*member| to point to this new
+// location, and then advances |*buffer| by the amount written.
+void CopyTraceEventParameter(char** buffer,
+                             const char** member,
+                             const char* end) {
+  if (*member) {
+    size_t written = strlcpy(*buffer, *member, end - *buffer) + 1;
+    DCHECK_LE(static_cast<int>(written), end - *buffer);
+    *member = *buffer;
+    *buffer += written;
+  }
+}
+
+}  // namespace
+
+TraceEvent::TraceEvent()
+    : id_(0u),
+      category_enabled_(NULL),
+      name_(NULL),
+      thread_id_(0),
+      phase_(TRACE_EVENT_PHASE_BEGIN),
+      flags_(0) {
+  arg_names_[0] = NULL;
+  arg_names_[1] = NULL;
+  memset(arg_values_, 0, sizeof(arg_values_));
+}
+
+TraceEvent::TraceEvent(int thread_id,
+                       TimeTicks timestamp,
+                       char phase,
+                       const unsigned char* category_enabled,
+                       const char* name,
+                       unsigned long long id,
+                       int num_args,
+                       const char** arg_names,
+                       const unsigned char* arg_types,
+                       const unsigned long long* arg_values,
+                       unsigned char flags)
+    : timestamp_(timestamp),
+      id_(id),
+      category_enabled_(category_enabled),
+      name_(name),
+      thread_id_(thread_id),
+      phase_(phase),
+      flags_(flags) {
+  // Clamp num_args since it may have been set by a third_party library.
+  num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args;
+  int i = 0;
+  for (; i < num_args; ++i) {
+    arg_names_[i] = arg_names[i];
+    arg_values_[i].as_uint = arg_values[i];
+    arg_types_[i] = arg_types[i];
+  }
+  for (; i < kTraceMaxNumArgs; ++i) {
+    arg_names_[i] = NULL;
+    arg_values_[i].as_uint = 0u;
+    arg_types_[i] = TRACE_VALUE_TYPE_UINT;
+  }
+
+  bool copy = !!(flags & TRACE_EVENT_FLAG_COPY);
+  size_t alloc_size = 0;
+  if (copy) {
+    alloc_size += GetAllocLength(name);
+    for (i = 0; i < num_args; ++i) {
+      alloc_size += GetAllocLength(arg_names_[i]);
+      if (arg_types_[i] == TRACE_VALUE_TYPE_STRING)
+        arg_types_[i] = TRACE_VALUE_TYPE_COPY_STRING;
+    }
+  }
+
+  bool arg_is_copy[kTraceMaxNumArgs];
+  for (i = 0; i < num_args; ++i) {
+    // We only take a copy of arg_vals if they are of type COPY_STRING.
+    arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING);
+    if (arg_is_copy[i])
+      alloc_size += GetAllocLength(arg_values_[i].as_string);
+  }
+
+  if (alloc_size) {
+    parameter_copy_storage_ = new base::RefCountedString;
+    parameter_copy_storage_->data().resize(alloc_size);
+    char* ptr = string_as_array(&parameter_copy_storage_->data());
+    const char* end = ptr + alloc_size;
+    if (copy) {
+      CopyTraceEventParameter(&ptr, &name_, end);
+      for (i = 0; i < num_args; ++i)
+        CopyTraceEventParameter(&ptr, &arg_names_[i], end);
+    }
+    for (i = 0; i < num_args; ++i) {
+      if (arg_is_copy[i])
+        CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end);
+    }
+    DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end;
+  }
+}
+
+TraceEvent::~TraceEvent() {
+}
+
+// static
+void TraceEvent::AppendValueAsJSON(unsigned char type,
+                                   TraceEvent::TraceValue value,
+                                   std::string* out) {
+  std::string::size_type start_pos;
+  switch (type) {
+    case TRACE_VALUE_TYPE_BOOL:
+      *out += value.as_bool ? "true" : "false";
+      break;
+    case TRACE_VALUE_TYPE_UINT:
+      StringAppendF(out, "%" PRIu64, static_cast<uint64>(value.as_uint));
+      break;
+    case TRACE_VALUE_TYPE_INT:
+      StringAppendF(out, "%" PRId64, static_cast<int64>(value.as_int));
+      break;
+    case TRACE_VALUE_TYPE_DOUBLE:
+      StringAppendF(out, "%f", value.as_double);
+      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, "\"%" PRIx64 "\"", static_cast<uint64>(
+                                     reinterpret_cast<intptr_t>(
+                                     value.as_pointer)));
+      break;
+    case TRACE_VALUE_TYPE_STRING:
+    case TRACE_VALUE_TYPE_COPY_STRING:
+      *out += "\"";
+      start_pos = out->size();
+      *out += value.as_string ? value.as_string : "NULL";
+      // insert backslash before special characters for proper json format.
+      while ((start_pos = out->find_first_of("\\\"", start_pos)) !=
+             std::string::npos) {
+        out->insert(start_pos, 1, '\\');
+        // skip inserted escape character and following character.
+        start_pos += 2;
+      }
+      *out += "\"";
+      break;
+    default:
+      NOTREACHED() << "Don't know how to print this value";
+      break;
+  }
+}
+
+void TraceEvent::AppendEventsAsJSON(const std::vector<TraceEvent>& events,
+                                    size_t start,
+                                    size_t count,
+                                    std::string* out) {
+  for (size_t i = 0; i < count && start + i < events.size(); ++i) {
+    if (i > 0)
+      *out += ",";
+    events[i + start].AppendAsJSON(out);
+  }
+}
+
+void TraceEvent::AppendAsJSON(std::string* out) const {
+  int64 time_int64 = timestamp_.ToInternalValue();
+  int process_id = TraceLog::GetInstance()->process_id();
+  // Category name checked at category creation time.
+  DCHECK(!strchr(name_, '"'));
+  StringAppendF(out,
+      "{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ","
+      "\"ph\":\"%c\",\"name\":\"%s\",\"args\":{",
+      TraceLog::GetCategoryName(category_enabled_),
+      process_id,
+      thread_id_,
+      time_int64,
+      phase_,
+      name_);
+
+  // Output argument names and values, stop at first NULL argument name.
+  for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+    if (i > 0)
+      *out += ",";
+    *out += "\"";
+    *out += arg_names_[i];
+    *out += "\":";
+    AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+  }
+  *out += "}";
+
+  // If id_ is set, print it out as a hex string so we don't loose any
+  // bits (it might be a 64-bit pointer).
+  if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
+    StringAppendF(out, ",\"id\":\"%" PRIx64 "\"", static_cast<uint64>(id_));
+  *out += "}";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceResultBuffer
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TraceResultBuffer::OutputCallback
+    TraceResultBuffer::SimpleOutput::GetCallback() {
+  return base::Bind(&SimpleOutput::Append, base::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("]");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceLog
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TraceLog::NotificationHelper::NotificationHelper(TraceLog* trace_log)
+    : trace_log_(trace_log),
+      notification_(0) {
+}
+
+TraceLog::NotificationHelper::~NotificationHelper() {
+}
+
+void TraceLog::NotificationHelper::AddNotificationWhileLocked(
+    int notification) {
+  if (trace_log_->notification_callback_.is_null())
+    return;
+  if (notification_ == 0)
+    callback_copy_ = trace_log_->notification_callback_;
+  notification_ |= notification;
+}
+
+void TraceLog::NotificationHelper::SendNotificationIfAny() {
+  if (notification_)
+    callback_copy_.Run(notification_);
+}
+
+// static
+TraceLog* TraceLog::GetInstance() {
+  return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get();
+}
+
+TraceLog::TraceLog()
+    : enabled_(false),
+      dispatching_to_observer_list_(false),
+      watch_category_(NULL) {
+  // 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_enabled, sizeof(g_category_enabled),
+  //                            "trace_event category enabled");
+  for (int i = 0; i < TRACE_EVENT_MAX_CATEGORIES; ++i) {
+    ANNOTATE_BENIGN_RACE(&g_category_enabled[i],
+                         "trace_event category enabled");
+  }
+#if defined(OS_NACL)  // NaCl shouldn't expose the process id.
+  SetProcessID(0);
+#else
+  SetProcessID(static_cast<int>(base::GetCurrentProcId()));
+#endif
+}
+
+TraceLog::~TraceLog() {
+}
+
+const unsigned char* TraceLog::GetCategoryEnabled(const char* name) {
+  TraceLog* tracelog = GetInstance();
+  if (!tracelog) {
+    DCHECK(!g_category_enabled[g_category_already_shutdown]);
+    return &g_category_enabled[g_category_already_shutdown];
+  }
+  return tracelog->GetCategoryEnabledInternal(name);
+}
+
+const char* TraceLog::GetCategoryName(const unsigned char* category_enabled) {
+  // Calculate the index of the category by finding category_enabled in
+  // g_category_enabled array.
+  uintptr_t category_begin = reinterpret_cast<uintptr_t>(g_category_enabled);
+  uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_enabled);
+  DCHECK(category_ptr >= category_begin &&
+         category_ptr < reinterpret_cast<uintptr_t>(g_category_enabled +
+                                               TRACE_EVENT_MAX_CATEGORIES)) <<
+      "out of bounds category pointer";
+  uintptr_t category_index =
+      (category_ptr - category_begin) / sizeof(g_category_enabled[0]);
+  return g_categories[category_index];
+}
+
+static void EnableMatchingCategory(int category_index,
+                                   const std::vector<std::string>& patterns,
+                                   unsigned char is_included) {
+  std::vector<std::string>::const_iterator ci = patterns.begin();
+  bool is_match = false;
+  for (; ci != patterns.end(); ++ci) {
+    is_match = MatchPattern(g_categories[category_index], ci->c_str());
+    if (is_match)
+      break;
+  }
+  g_category_enabled[category_index] = is_match ?
+      is_included : (is_included ^ 1);
+}
+
+// Enable/disable each category based on the category filters in |patterns|.
+// If the category name matches one of the patterns, its enabled status is set
+// to |is_included|. Otherwise its enabled status is set to !|is_included|.
+static void EnableMatchingCategories(const std::vector<std::string>& patterns,
+                                     unsigned char is_included) {
+  for (int i = 0; i < g_category_index; i++)
+    EnableMatchingCategory(i, patterns, is_included);
+}
+
+const unsigned char* TraceLog::GetCategoryEnabledInternal(const char* name) {
+  AutoLock lock(lock_);
+  DCHECK(!strchr(name, '"')) << "Category names may not contain double quote";
+
+  // Search for pre-existing category matching this name
+  for (int i = 0; i < g_category_index; i++) {
+    if (strcmp(g_categories[i], name) == 0)
+      return &g_category_enabled[i];
+  }
+
+  // Create a new category
+  DCHECK(g_category_index < TRACE_EVENT_MAX_CATEGORIES) <<
+      "must increase TRACE_EVENT_MAX_CATEGORIES";
+  if (g_category_index < TRACE_EVENT_MAX_CATEGORIES) {
+    int new_index = g_category_index++;
+    // Don't hold on to the name pointer, so that we can create categories with
+    // strings not known at compile time (this is required by SetWatchEvent).
+    const char* new_name = base::strdup(name);
+    ANNOTATE_LEAKING_OBJECT_PTR(new_name);
+    g_categories[new_index] = new_name;
+    DCHECK(!g_category_enabled[new_index]);
+    if (enabled_) {
+      // Note that if both included and excluded_categories are empty, the else
+      // clause below excludes nothing, thereby enabling this category.
+      if (!included_categories_.empty())
+        EnableMatchingCategory(new_index, included_categories_, 1);
+      else
+        EnableMatchingCategory(new_index, excluded_categories_, 0);
+    } else {
+      g_category_enabled[new_index] = 0;
+    }
+    return &g_category_enabled[new_index];
+  } else {
+    return &g_category_enabled[g_category_categories_exhausted];
+  }
+}
+
+void TraceLog::GetKnownCategories(std::vector<std::string>* categories) {
+  AutoLock lock(lock_);
+  for (int i = 0; i < g_category_index; i++)
+    categories->push_back(g_categories[i]);
+}
+
+void TraceLog::SetEnabled(const std::vector<std::string>& included_categories,
+                          const std::vector<std::string>& excluded_categories) {
+  AutoLock lock(lock_);
+  if (enabled_)
+    return;
+
+  if (dispatching_to_observer_list_) {
+    DLOG(ERROR) <<
+        "Cannot manipulate TraceLog::Enabled state from an observer.";
+    return;
+  }
+
+  dispatching_to_observer_list_ = true;
+  FOR_EACH_OBSERVER(EnabledStateChangedObserver, enabled_state_observer_list_,
+                    OnTraceLogWillEnable());
+  dispatching_to_observer_list_ = false;
+
+  logged_events_.reserve(1024);
+  enabled_ = true;
+  included_categories_ = included_categories;
+  excluded_categories_ = excluded_categories;
+  // Note that if both included and excluded_categories are empty, the else
+  // clause below excludes nothing, thereby enabling all categories.
+  if (!included_categories_.empty())
+    EnableMatchingCategories(included_categories_, 1);
+  else
+    EnableMatchingCategories(excluded_categories_, 0);
+}
+
+void TraceLog::SetEnabled(const std::string& categories) {
+  std::vector<std::string> included, excluded;
+  // Tokenize list of categories, delimited by ','.
+  StringTokenizer tokens(categories, ",");
+  while (tokens.GetNext()) {
+    bool is_included = true;
+    std::string category = tokens.token();
+    // Excluded categories start with '-'.
+    if (category.at(0) == '-') {
+      // Remove '-' from category string.
+      category = category.substr(1);
+      is_included = false;
+    }
+    if (is_included)
+      included.push_back(category);
+    else
+      excluded.push_back(category);
+  }
+  SetEnabled(included, excluded);
+}
+
+void TraceLog::GetEnabledTraceCategories(
+    std::vector<std::string>* included_out,
+    std::vector<std::string>* excluded_out) {
+  AutoLock lock(lock_);
+  if (enabled_) {
+    *included_out = included_categories_;
+    *excluded_out = excluded_categories_;
+  }
+}
+
+void TraceLog::SetDisabled() {
+  AutoLock lock(lock_);
+  if (!enabled_)
+    return;
+
+  if (dispatching_to_observer_list_) {
+    DLOG(ERROR)
+        << "Cannot manipulate TraceLog::Enabled state from an observer.";
+    return;
+  }
+
+  dispatching_to_observer_list_ = true;
+  FOR_EACH_OBSERVER(EnabledStateChangedObserver, enabled_state_observer_list_,
+                    OnTraceLogWillDisable());
+  dispatching_to_observer_list_ = false;
+
+  enabled_ = false;
+  included_categories_.clear();
+  excluded_categories_.clear();
+  watch_category_ = NULL;
+  watch_event_name_ = "";
+  for (int i = 0; i < g_category_index; i++)
+    g_category_enabled[i] = 0;
+  AddThreadNameMetadataEvents();
+#if defined(OS_ANDROID)
+  AddClockSyncMetadataEvents();
+#endif
+}
+
+void TraceLog::SetEnabled(bool enabled) {
+  if (enabled)
+    SetEnabled(std::vector<std::string>(), std::vector<std::string>());
+  else
+    SetDisabled();
+}
+
+void TraceLog::AddEnabledStateObserver(EnabledStateChangedObserver* listener) {
+  enabled_state_observer_list_.AddObserver(listener);
+}
+
+void TraceLog::RemoveEnabledStateObserver(
+    EnabledStateChangedObserver* listener) {
+  enabled_state_observer_list_.RemoveObserver(listener);
+}
+
+float TraceLog::GetBufferPercentFull() const {
+  return (float)((double)logged_events_.size()/(double)kTraceEventBufferSize);
+}
+
+void TraceLog::SetNotificationCallback(
+    const TraceLog::NotificationCallback& cb) {
+  AutoLock lock(lock_);
+  notification_callback_ = cb;
+}
+
+void TraceLog::Flush(const TraceLog::OutputCallback& cb) {
+  std::vector<TraceEvent> previous_logged_events;
+  {
+    AutoLock lock(lock_);
+    previous_logged_events.swap(logged_events_);
+  }  // release lock
+
+  for (size_t i = 0;
+       i < previous_logged_events.size();
+       i += kTraceEventBatchSize) {
+    scoped_refptr<RefCountedString> json_events_str_ptr =
+        new RefCountedString();
+    TraceEvent::AppendEventsAsJSON(previous_logged_events,
+                                   i,
+                                   kTraceEventBatchSize,
+                                   &(json_events_str_ptr->data()));
+    cb.Run(json_events_str_ptr);
+  }
+}
+
+int TraceLog::AddTraceEvent(char phase,
+                            const unsigned char* category_enabled,
+                            const char* name,
+                            unsigned long long id,
+                            int num_args,
+                            const char** arg_names,
+                            const unsigned char* arg_types,
+                            const unsigned long long* arg_values,
+                            int threshold_begin_id,
+                            long long threshold,
+                            unsigned char flags) {
+  DCHECK(name);
+
+#if defined(OS_ANDROID)
+  SendToATrace(phase, GetCategoryName(category_enabled), name,
+               num_args, arg_names, arg_types, arg_values);
+#endif
+
+  TimeTicks now = TimeTicks::NowFromSystemTraceTime();
+  NotificationHelper notifier(this);
+  int ret_begin_id = -1;
+  {
+    AutoLock lock(lock_);
+    if (!*category_enabled)
+      return -1;
+    if (logged_events_.size() >= kTraceEventBufferSize)
+      return -1;
+
+    int thread_id = static_cast<int>(PlatformThread::CurrentId());
+
+    const char* new_name = PlatformThread::GetName();
+    // 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);
+      base::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<base::StringPiece> existing_names;
+        Tokenize(existing_name->second, ",", &existing_names);
+        bool found = std::find(existing_names.begin(),
+                               existing_names.end(),
+                               new_name) != existing_names.end();
+        if (!found) {
+          existing_name->second.push_back(',');
+          existing_name->second.append(new_name);
+        }
+      }
+    }
+
+    if (threshold_begin_id > -1) {
+      DCHECK(phase == TRACE_EVENT_PHASE_END);
+      size_t begin_i = static_cast<size_t>(threshold_begin_id);
+      // Return now if there has been a flush since the begin event was posted.
+      if (begin_i >= logged_events_.size())
+        return -1;
+      // Determine whether to drop the begin/end pair.
+      TimeDelta elapsed = now - logged_events_[begin_i].timestamp();
+      if (elapsed < TimeDelta::FromMicroseconds(threshold)) {
+        // Remove begin event and do not add end event.
+        // This will be expensive if there have been other events in the
+        // mean time (should be rare).
+        logged_events_.erase(logged_events_.begin() + begin_i);
+        return -1;
+      }
+    }
+
+    if (flags & TRACE_EVENT_FLAG_MANGLE_ID)
+      id ^= process_id_hash_;
+
+    ret_begin_id = static_cast<int>(logged_events_.size());
+    logged_events_.push_back(
+        TraceEvent(thread_id,
+                   now, phase, category_enabled, name, id,
+                   num_args, arg_names, arg_types, arg_values,
+                   flags));
+
+    if (logged_events_.size() == kTraceEventBufferSize)
+      notifier.AddNotificationWhileLocked(TRACE_BUFFER_FULL);
+
+    if (watch_category_ == category_enabled && watch_event_name_ == name)
+      notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION);
+  }  // release lock
+
+  notifier.SendNotificationIfAny();
+
+  return ret_begin_id;
+}
+
+void TraceLog::AddTraceEventEtw(char phase,
+                                const char* name,
+                                const void* id,
+                                const char* extra) {
+#if defined(OS_WIN)
+  TraceEventETWProvider::Trace(name, phase, id, extra);
+#endif
+  INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name,
+                           TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
+}
+
+void TraceLog::AddTraceEventEtw(char phase,
+                                const char* name,
+                                const void* id,
+                                const std::string& extra)
+{
+#if defined(OS_WIN)
+  TraceEventETWProvider::Trace(name, phase, id, extra);
+#endif
+  INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name,
+                           TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
+}
+
+void TraceLog::SetWatchEvent(const std::string& category_name,
+                             const std::string& event_name) {
+  const unsigned char* category = GetCategoryEnabled(category_name.c_str());
+  int notify_count = 0;
+  {
+    AutoLock lock(lock_);
+    watch_category_ = category;
+    watch_event_name_ = event_name;
+
+    // First, search existing events for watch event because we want to catch it
+    // even if it has already occurred.
+    for (size_t i = 0u; i < logged_events_.size(); ++i) {
+      if (category == logged_events_[i].category_enabled() &&
+          strcmp(event_name.c_str(), logged_events_[i].name()) == 0) {
+        ++notify_count;
+      }
+    }
+  }  // release lock
+
+  // Send notification for each event found.
+  for (int i = 0; i < notify_count; ++i) {
+    NotificationHelper notifier(this);
+    lock_.Acquire();
+    notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION);
+    lock_.Release();
+    notifier.SendNotificationIfAny();
+  }
+}
+
+void TraceLog::CancelWatchEvent() {
+  AutoLock lock(lock_);
+  watch_category_ = NULL;
+  watch_event_name_ = "";
+}
+
+void TraceLog::AddThreadNameMetadataEvents() {
+  lock_.AssertAcquired();
+  for(base::hash_map<int, std::string>::iterator it = thread_names_.begin();
+      it != thread_names_.end();
+      it++) {
+    if (!it->second.empty()) {
+      int num_args = 1;
+      const char* arg_name = "name";
+      unsigned char arg_type;
+      unsigned long long arg_value;
+      trace_event_internal::SetTraceValue(it->second, &arg_type, &arg_value);
+      logged_events_.push_back(
+          TraceEvent(it->first,
+                     TimeTicks(), TRACE_EVENT_PHASE_METADATA,
+                     &g_category_enabled[g_category_metadata],
+                     "thread_name", trace_event_internal::kNoEventId,
+                     num_args, &arg_name, &arg_type, &arg_value,
+                     TRACE_EVENT_FLAG_NONE));
+    }
+  }
+}
+
+void TraceLog::DeleteForTesting() {
+  DeleteTraceLogForTesting::Delete();
+}
+
+void TraceLog::Resurrect() {
+  StaticMemorySingletonTraits<TraceLog>::Resurrect();
+}
+
+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;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h
new file mode 100644
index 0000000..c186373
--- /dev/null
+++ b/base/debug/trace_event_impl.h
@@ -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.
+
+
+#ifndef BASE_DEBUG_TRACE_EVENT_IMPL_H_
+#define BASE_DEBUG_TRACE_EVENT_IMPL_H_
+
+#include "build/build_config.h"
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/hash_tables.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/observer_list.h"
+#include "base/string_util.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/timer.h"
+
+// Older style trace macros with explicit id and extra data
+// Only these macros result in publishing data to ETW as currently implemented.
+#define TRACE_EVENT_BEGIN_ETW(name, id, extra) \
+    base::debug::TraceLog::AddTraceEventEtw( \
+        TRACE_EVENT_PHASE_BEGIN, \
+        name, reinterpret_cast<const void*>(id), extra)
+
+#define TRACE_EVENT_END_ETW(name, id, extra) \
+    base::debug::TraceLog::AddTraceEventEtw( \
+        TRACE_EVENT_PHASE_END, \
+        name, reinterpret_cast<const void*>(id), extra)
+
+#define TRACE_EVENT_INSTANT_ETW(name, id, extra) \
+    base::debug::TraceLog::AddTraceEventEtw( \
+        TRACE_EVENT_PHASE_INSTANT, \
+        name, reinterpret_cast<const void*>(id), extra)
+
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace base {
+
+namespace debug {
+
+const int kTraceMaxNumArgs = 2;
+
+// Output records are "Events" and can be obtained via the
+// OutputCallback whenever the tracing system decides to flush. This
+// can happen at any time, on any thread, or you can programatically
+// force it to happen.
+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(int thread_id,
+             TimeTicks timestamp,
+             char phase,
+             const unsigned char* category_enabled,
+             const char* name,
+             unsigned long long id,
+             int num_args,
+             const char** arg_names,
+             const unsigned char* arg_types,
+             const unsigned long long* arg_values,
+             unsigned char flags);
+  ~TraceEvent();
+
+  // Serialize event data to JSON
+  static void AppendEventsAsJSON(const std::vector<TraceEvent>& events,
+                                 size_t start,
+                                 size_t count,
+                                 std::string* out);
+  void AppendAsJSON(std::string* out) const;
+
+  static void AppendValueAsJSON(unsigned char type,
+                                TraceValue value,
+                                std::string* out);
+
+  TimeTicks timestamp() const { return timestamp_; }
+
+  // Exposed for unittesting:
+
+  const base::RefCountedString* parameter_copy_storage() const {
+    return parameter_copy_storage_.get();
+  }
+
+  const unsigned char* category_enabled() const { return category_enabled_; }
+  const char* name() const { return name_; }
+
+ private:
+  // Note: these are ordered by size (largest first) for optimal packing.
+  TimeTicks timestamp_;
+  // id_ can be used to store phase-specific data.
+  unsigned long long id_;
+  TraceValue arg_values_[kTraceMaxNumArgs];
+  const char* arg_names_[kTraceMaxNumArgs];
+  const unsigned char* category_enabled_;
+  const char* name_;
+  scoped_refptr<base::RefCountedString> parameter_copy_storage_;
+  int thread_id_;
+  char phase_;
+  unsigned char flags_;
+  unsigned char arg_types_[kTraceMaxNumArgs];
+};
+
+
+// TraceResultBuffer collects and converts trace fragments returned by TraceLog
+// to JSON output.
+class BASE_EXPORT TraceResultBuffer {
+ public:
+  typedef base::Callback<void(const std::string&)> OutputCallback;
+
+  // If you don't need to stream JSON chunks out efficiently, and just want to
+  // get a complete JSON string after calling Finish, use this struct to collect
+  // JSON trace output.
+  struct BASE_EXPORT SimpleOutput {
+    OutputCallback GetCallback();
+    void Append(const std::string& json_string);
+
+    // Do what you want with the json_output_ string after calling
+    // TraceResultBuffer::Finish.
+    std::string json_output;
+  };
+
+  TraceResultBuffer();
+  ~TraceResultBuffer();
+
+  // Set callback. The callback will be called during Start with the initial
+  // JSON output and during AddFragment and Finish with following JSON output
+  // chunks. The callback target must live past the last calls to
+  // TraceResultBuffer::Start/AddFragment/Finish.
+  void SetOutputCallback(const OutputCallback& json_chunk_callback);
+
+  // Start JSON output. This resets all internal state, so you can reuse
+  // the TraceResultBuffer by calling Start.
+  void Start();
+
+  // Call AddFragment 0 or more times to add trace fragments from TraceLog.
+  void AddFragment(const std::string& trace_fragment);
+
+  // When all fragments have been added, call Finish to complete the JSON
+  // formatted output.
+  void Finish();
+
+ private:
+  OutputCallback output_callback_;
+  bool append_comma_;
+};
+
+
+class BASE_EXPORT TraceLog {
+ public:
+  // Notification is a mask of one or more of the following events.
+  enum Notification {
+    // The trace buffer does not flush dynamically, so when it fills up,
+    // subsequent trace events will be dropped. This callback is generated when
+    // the trace buffer is full. The callback must be thread safe.
+    TRACE_BUFFER_FULL = 1 << 0,
+    // A subscribed trace-event occurred.
+    EVENT_WATCH_NOTIFICATION = 1 << 1
+  };
+
+  static TraceLog* GetInstance();
+
+  // Get set of known categories. This can change as new code paths are reached.
+  // The known categories are inserted into |categories|.
+  void GetKnownCategories(std::vector<std::string>* categories);
+
+  // Enable tracing for provided list of categories. If tracing is already
+  // enabled, this method does nothing -- changing categories during trace is
+  // not supported.
+  // If both included_categories and excluded_categories are empty,
+  //   all categories are traced.
+  // Else if included_categories is non-empty, only those are traced.
+  // Else if excluded_categories is non-empty, everything but those are traced.
+  // Wildcards * and ? are supported (see MatchPattern in string_util.h).
+  void SetEnabled(const std::vector<std::string>& included_categories,
+                  const std::vector<std::string>& excluded_categories);
+
+  // |categories| 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.
+  //
+  // Example: SetEnabled("test_MyTest*");
+  // Example: SetEnabled("test_MyTest*,test_OtherStuff");
+  // Example: SetEnabled("-excluded_category1,-excluded_category2");
+  void SetEnabled(const std::string& categories);
+
+  // Retieves the categories set via a prior call to SetEnabled(). Only
+  // meaningful if |IsEnabled()| is true.
+  void GetEnabledTraceCategories(std::vector<std::string>* included_out,
+                                 std::vector<std::string>* excluded_out);
+
+  // Disable tracing for all categories.
+  void SetDisabled();
+  // Helper method to enable/disable tracing for all categories.
+  void SetEnabled(bool enabled);
+  bool IsEnabled() { return enabled_; }
+
+#if defined(OS_ANDROID)
+  static void InitATrace();
+  static bool IsATraceEnabled();
+#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 EnabledStateChangedObserver {
+   public:
+    // Called just before the tracing system becomes
+    // enabled. TraceLog::IsEnabled will return false at this point and trace
+    // macros and methods called within the observer will deadlock.
+    virtual void OnTraceLogWillEnable() { }
+
+    // Called just before the tracing system disables. TraceLog::IsEnabled is
+    // still false at this point TRACE macros will still be capturing
+    // data. However, trace macros and methods called within the observer will
+    // deadlock.
+    virtual void OnTraceLogWillDisable() { }
+  };
+  void AddEnabledStateObserver(EnabledStateChangedObserver* listener);
+  void RemoveEnabledStateObserver(EnabledStateChangedObserver* listener);
+
+  float GetBufferPercentFull() const;
+
+  // Set the thread-safe notification callback. The callback can occur at any
+  // time and from any thread. WARNING: It is possible for the previously set
+  // callback to be called during OR AFTER a call to SetNotificationCallback.
+  // Therefore, the target of the callback must either be a global function,
+  // ref-counted object or a LazyInstance with Leaky traits (or equivalent).
+  typedef base::Callback<void(int)> NotificationCallback;
+  void SetNotificationCallback(const NotificationCallback& cb);
+
+  // Flush all collected events to the given output callback. The callback will
+  // be called one or more times with IPC-bite-size chunks. The string format is
+  // undefined. Use TraceResultBuffer to convert one or more trace strings to
+  // JSON.
+  typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&)>
+      OutputCallback;
+  void Flush(const OutputCallback& cb);
+
+  // Called by TRACE_EVENT* macros, don't call this directly.
+  static const unsigned char* GetCategoryEnabled(const char* name);
+  static const char* GetCategoryName(const unsigned char* category_enabled);
+
+  // Called by TRACE_EVENT* macros, don't call this directly.
+  // Returns the index in the internal vector of the event if it was added, or
+  //         -1 if the event was not added.
+  // On end events, the return value of the begin event can be specified along
+  // with a threshold in microseconds. If the elapsed time between begin and end
+  // is less than the threshold, the begin/end event pair is dropped.
+  // 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.
+  int AddTraceEvent(char phase,
+                    const unsigned char* category_enabled,
+                    const char* name,
+                    unsigned long long id,
+                    int num_args,
+                    const char** arg_names,
+                    const unsigned char* arg_types,
+                    const unsigned long long* arg_values,
+                    int threshold_begin_id,
+                    long long threshold,
+                    unsigned char flags);
+  static void AddTraceEventEtw(char phase,
+                               const char* name,
+                               const void* id,
+                               const char* extra);
+  static void AddTraceEventEtw(char phase,
+                               const char* name,
+                               const void* id,
+                               const std::string& extra);
+
+  // For every matching event, a notification will be fired. NOTE: the
+  // notification will fire for each matching event that has already occurred
+  // since tracing was started (including before tracing if the process was
+  // started with tracing turned on).
+  void SetWatchEvent(const std::string& category_name,
+                     const std::string& event_name);
+  // 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_; }
+
+  // Exposed for unittesting:
+
+  // Allows deleting our singleton instance.
+  static void DeleteForTesting();
+
+  // Allows resurrecting our singleton instance post-AtExit processing.
+  static void Resurrect();
+
+  // Allow tests to inspect TraceEvents.
+  size_t GetEventsSize() const { return logged_events_.size(); }
+  const TraceEvent& GetEventAt(size_t index) const {
+    DCHECK(index < logged_events_.size());
+    return logged_events_[index];
+  }
+
+  void SetProcessID(int process_id);
+
+ private:
+  // This allows constructor and destructor to be private and usable only
+  // by the Singleton class.
+  friend struct StaticMemorySingletonTraits<TraceLog>;
+
+  // Helper class for managing notification_thread_count_ and running
+  // notification callbacks. This is very similar to a reader-writer lock, but
+  // shares the lock with TraceLog and manages the notification flags.
+  class NotificationHelper {
+   public:
+    inline explicit NotificationHelper(TraceLog* trace_log);
+    inline ~NotificationHelper();
+
+    // Called only while TraceLog::lock_ is held. This ORs the given
+    // notification with any existing notifcations.
+    inline void AddNotificationWhileLocked(int notification);
+
+    // Called only while TraceLog::lock_ is NOT held. If there are any pending
+    // notifications from previous calls to AddNotificationWhileLocked, this
+    // will call the NotificationCallback.
+    inline void SendNotificationIfAny();
+
+   private:
+    TraceLog* trace_log_;
+    NotificationCallback callback_copy_;
+    int notification_;
+  };
+
+  TraceLog();
+  ~TraceLog();
+  const unsigned char* GetCategoryEnabledInternal(const char* name);
+  void AddThreadNameMetadataEvents();
+
+#if defined(OS_ANDROID)
+  void SendToATrace(char phase,
+                    const char* category,
+                    const char* name,
+                    int num_args,
+                    const char** arg_names,
+                    const unsigned char* arg_types,
+                    const unsigned long long* arg_values);
+  void AddClockSyncMetadataEvents();
+#endif
+
+  // TODO(nduca): switch to per-thread trace buffers to reduce thread
+  // synchronization.
+  // This lock protects TraceLog member accesses from arbitrary threads.
+  Lock lock_;
+  bool enabled_;
+  NotificationCallback notification_callback_;
+  std::vector<TraceEvent> logged_events_;
+  std::vector<std::string> included_categories_;
+  std::vector<std::string> excluded_categories_;
+  bool dispatching_to_observer_list_;
+  ObserverList<EnabledStateChangedObserver> enabled_state_observer_list_;
+
+  base::hash_map<int, std::string> thread_names_;
+
+  // XORed with TraceID to make it unlikely to collide with other processes.
+  unsigned long long process_id_hash_;
+
+  int process_id_;
+
+  // Allow tests to wake up when certain events occur.
+  const unsigned char* watch_category_;
+  std::string watch_event_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceLog);
+};
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_TRACE_EVENT_IMPL_H_
diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc
new file mode 100644
index 0000000..75a6ce4
--- /dev/null
+++ b/base/debug/trace_event_unittest.cc
@@ -0,0 +1,1460 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/trace_event_unittest.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/process_util.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::debug::HighResSleepForTraceTest;
+
+namespace base {
+namespace debug {
+
+namespace {
+
+enum CompareOp {
+  IS_EQUAL,
+  IS_NOT_EQUAL,
+};
+
+struct JsonKeyValue {
+  const char* key;
+  const char* value;
+  CompareOp op;
+};
+
+class TraceEventTestFixture : public testing::Test {
+ public:
+  // This fixture does not use SetUp() because the fixture must be manually set
+  // up multiple times when testing AtExit. Use ManualTestSetUp for this.
+  void ManualTestSetUp();
+  void OnTraceDataCollected(
+      const scoped_refptr<base::RefCountedString>& events_str);
+  void OnTraceNotification(int notification) {
+    if (notification & TraceLog::EVENT_WATCH_NOTIFICATION)
+      ++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);
+  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() {
+    event_watch_notification_ = 0;
+    TraceLog::GetInstance()->SetEnabled("*");
+  }
+
+  void EndTraceAndFlush() {
+    TraceLog::GetInstance()->SetDisabled();
+    TraceLog::GetInstance()->Flush(
+        base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
+                   base::Unretained(this)));
+  }
+
+  virtual void SetUp() OVERRIDE {
+    old_thread_name_ = PlatformThread::GetName();
+  }
+  virtual void TearDown() OVERRIDE {
+    if (TraceLog::GetInstance())
+      EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
+    PlatformThread::SetName(old_thread_name_ ? old_thread_name_  : "");
+  }
+
+  const char* old_thread_name_;
+  ListValue trace_parsed_;
+  base::debug::TraceResultBuffer trace_buffer_;
+  base::debug::TraceResultBuffer::SimpleOutput json_output_;
+  int event_watch_notification_;
+
+ private:
+  // We want our singleton torn down after each test.
+  ShadowingAtExitManager at_exit_manager_;
+  Lock lock_;
+};
+
+void TraceEventTestFixture::ManualTestSetUp() {
+  TraceLog::DeleteForTesting();
+  TraceLog::Resurrect();
+  TraceLog* tracelog = TraceLog::GetInstance();
+  ASSERT_TRUE(tracelog);
+  ASSERT_FALSE(tracelog->IsEnabled());
+  tracelog->SetNotificationCallback(
+      base::Bind(&TraceEventTestFixture::OnTraceNotification,
+                 base::Unretained(this)));
+  trace_buffer_.SetOutputCallback(json_output_.GetCallback());
+}
+
+void TraceEventTestFixture::OnTraceDataCollected(
+    const scoped_refptr<base::RefCountedString>& events_str) {
+  AutoLock lock(lock_);
+  json_output_.json_output.clear();
+  trace_buffer_.Start();
+  trace_buffer_.AddFragment(events_str->data());
+  trace_buffer_.Finish();
+
+  scoped_ptr<Value> root;
+  root.reset(base::JSONReader::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()) {
+    Value* item = NULL;
+    root_list->Remove(0, &item);
+    trace_parsed_.Append(item);
+  }
+}
+
+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;
+}
+
+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::key_iterator ikey = dict->begin_keys();
+       ikey != dict->end_keys(); ++ikey) {
+    const Value* child = NULL;
+    if (!dict->GetWithoutPathExpansion(*ikey, &child))
+      continue;
+
+    if ((*ikey).find(string_to_match) != std::string::npos)
+      return true;
+
+    std::string value_str;
+    child->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;
+}
+
+void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
+  {
+    TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW call", 0x1122, "extrastring1");
+    TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW call", 0x3344, "extrastring2");
+    TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW call",
+                            0x5566, "extrastring3");
+
+    TRACE_EVENT0("all", "TRACE_EVENT0 call");
+    TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1");
+    TRACE_EVENT2("all", "TRACE_EVENT2 call",
+                 "name1", "\"value1\"",
+                 "name2", "value\\2");
+
+    TRACE_EVENT_INSTANT0("all", "TRACE_EVENT_INSTANT0 call");
+    TRACE_EVENT_INSTANT1("all", "TRACE_EVENT_INSTANT1 call", "name1", "value1");
+    TRACE_EVENT_INSTANT2("all", "TRACE_EVENT_INSTANT2 call",
+                         "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_IF_LONGER_THAN0(0, "all", "TRACE_EVENT_IF_LONGER_THAN0 call");
+    TRACE_EVENT_IF_LONGER_THAN1(0, "all", "TRACE_EVENT_IF_LONGER_THAN1 call",
+                                "name1", "value1");
+    TRACE_EVENT_IF_LONGER_THAN2(0, "all", "TRACE_EVENT_IF_LONGER_THAN2 call",
+                                "name1", "value1",
+                                "name2", "value2");
+
+    TRACE_EVENT_ASYNC_BEGIN0("all", "TRACE_EVENT_ASYNC_BEGIN0 call", 5);
+    TRACE_EVENT_ASYNC_BEGIN1("all", "TRACE_EVENT_ASYNC_BEGIN1 call", 5,
+                             "name1", "value1");
+    TRACE_EVENT_ASYNC_BEGIN2("all", "TRACE_EVENT_ASYNC_BEGIN2 call", 5,
+                             "name1", "value1",
+                             "name2", "value2");
+
+    TRACE_EVENT_ASYNC_STEP0("all", "TRACE_EVENT_ASYNC_STEP0 call",
+                                  5, "step1");
+    TRACE_EVENT_ASYNC_STEP1("all", "TRACE_EVENT_ASYNC_STEP1 call",
+                                  5, "step2", "name1", "value1");
+
+    TRACE_EVENT_ASYNC_END0("all", "TRACE_EVENT_ASYNC_END0 call", 5);
+    TRACE_EVENT_ASYNC_END1("all", "TRACE_EVENT_ASYNC_END1 call", 5,
+                           "name1", "value1");
+    TRACE_EVENT_ASYNC_END2("all", "TRACE_EVENT_ASYNC_END2 call", 5,
+                           "name1", "value1",
+                           "name2", "value2");
+
+    TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW0 call", 5, NULL);
+    TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW1 call", 5, "value");
+    TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW0 call", 5, NULL);
+    TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW1 call", 5, "value");
+    TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW0 call", 5, NULL);
+    TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW1 call", 5, "value");
+
+    TRACE_COUNTER1("all", "TRACE_COUNTER1 call", 31415);
+    TRACE_COUNTER2("all", "TRACE_COUNTER2 call",
+                   "a", 30000,
+                   "b", 1415);
+
+    TRACE_COUNTER_ID1("all", "TRACE_COUNTER_ID1 call", 0x319009, 31415);
+    TRACE_COUNTER_ID2("all", "TRACE_COUNTER_ID2 call", 0x319009,
+                      "a", 30000, "b", 1415);
+  } // 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) \
+    EXPECT_TRUE((item = FindTraceEntry(trace_parsed, string)));
+#define EXPECT_NOT_FIND_(string) \
+    EXPECT_FALSE((item = FindTraceEntry(trace_parsed, string)));
+#define EXPECT_SUB_FIND_(string) \
+    if (item) EXPECT_TRUE((IsStringInDict(string, item)));
+
+  EXPECT_FIND_("ETW Trace Event");
+  EXPECT_FIND_("all");
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW call");
+  {
+    std::string str_val;
+    EXPECT_TRUE(item && item->GetString("args.id", &str_val));
+    EXPECT_STREQ("1122", str_val.c_str());
+  }
+  EXPECT_SUB_FIND_("extrastring1");
+  EXPECT_FIND_("TRACE_EVENT_END_ETW call");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW call");
+  EXPECT_FIND_("TRACE_EVENT0 call");
+  {
+    std::string ph_begin;
+    std::string ph_end;
+    EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call")));
+    EXPECT_TRUE((item && item->GetString("ph", &ph_begin)));
+    EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call",
+                                       item)));
+    EXPECT_TRUE((item && item->GetString("ph", &ph_end)));
+    EXPECT_EQ("B", ph_begin);
+    EXPECT_EQ("E", ph_end);
+  }
+  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");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT1 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT2 call");
+  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_IF_LONGER_THAN0 call");
+  EXPECT_FIND_("TRACE_EVENT_IF_LONGER_THAN1 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_IF_LONGER_THAN2 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_("5");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN2 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("step1");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("step2");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_END0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_END1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_END2 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("NULL");
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("value");
+  EXPECT_FIND_("TRACE_EVENT_END_ETW0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("NULL");
+  EXPECT_FIND_("TRACE_EVENT_END_ETW1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("value");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("NULL");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_("5");
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("value");
+
+  EXPECT_FIND_("TRACE_COUNTER1 call");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.value", &value)));
+    EXPECT_EQ(31415, value);
+  }
+
+  EXPECT_FIND_("TRACE_COUNTER2 call");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.a", &value)));
+    EXPECT_EQ(30000, value);
+
+    EXPECT_TRUE((item && item->GetInteger("args.b", &value)));
+    EXPECT_EQ(1415, value);
+  }
+
+  EXPECT_FIND_("TRACE_COUNTER_ID1 call");
+  {
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("319009", 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("319009", 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);
+  }
+}
+
+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",
+                         "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 TraceCallsWithCachedCategoryPointersPointers(const char* name_str) {
+  TRACE_EVENT0("category name1", name_str);
+  TRACE_EVENT_INSTANT0("category name2", name_str);
+  TRACE_EVENT_BEGIN0("category name3", name_str);
+  TRACE_EVENT_END0("category name4", name_str);
+}
+
+}  // namespace
+
+void HighResSleepForTraceTest(base::TimeDelta elapsed) {
+  base::TimeTicks end_time = base::TimeTicks::HighResNow() + elapsed;
+  do {
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
+  } while (base::TimeTicks::HighResNow() < end_time);
+}
+
+// Simple Test for emitting data and validating it was received.
+TEST_F(TraceEventTestFixture, DataCaptured) {
+  ManualTestSetUp();
+  TraceLog::GetInstance()->SetEnabled(true);
+
+  TraceWithAllMacroVariants(NULL);
+
+  EndTraceAndFlush();
+
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+}
+
+class MockEnabledStateChangedObserver :
+      public base::debug::TraceLog::EnabledStateChangedObserver {
+ public:
+  MOCK_METHOD0(OnTraceLogWillEnable, void());
+  MOCK_METHOD0(OnTraceLogWillDisable, void());
+};
+
+TEST_F(TraceEventTestFixture, EnabledObserverFiresOnEnable) {
+  ManualTestSetUp();
+
+  MockEnabledStateChangedObserver observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogWillEnable())
+      .Times(1);
+  TraceLog::GetInstance()->SetEnabled(true);
+  testing::Mock::VerifyAndClear(&observer);
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+  TraceLog::GetInstance()->SetEnabled(false);
+}
+
+TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnSecondEnable) {
+  ManualTestSetUp();
+
+  TraceLog::GetInstance()->SetEnabled(true);
+
+  testing::StrictMock<MockEnabledStateChangedObserver> observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogWillEnable())
+      .Times(0);
+  EXPECT_CALL(observer, OnTraceLogWillDisable())
+      .Times(0);
+  TraceLog::GetInstance()->SetEnabled(true);
+  testing::Mock::VerifyAndClear(&observer);
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+  TraceLog::GetInstance()->SetEnabled(false);
+}
+
+TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnUselessDisable) {
+  ManualTestSetUp();
+
+
+  testing::StrictMock<MockEnabledStateChangedObserver> observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogWillEnable())
+      .Times(0);
+  EXPECT_CALL(observer, OnTraceLogWillDisable())
+      .Times(0);
+  TraceLog::GetInstance()->SetEnabled(false);
+  testing::Mock::VerifyAndClear(&observer);
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+}
+
+TEST_F(TraceEventTestFixture, EnabledObserverFiresOnDisable) {
+  ManualTestSetUp();
+
+  TraceLog::GetInstance()->SetEnabled(true);
+
+  MockEnabledStateChangedObserver observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogWillDisable())
+      .Times(1);
+  TraceLog::GetInstance()->SetEnabled(false);
+  testing::Mock::VerifyAndClear(&observer);
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+}
+
+// Test that categories work.
+TEST_F(TraceEventTestFixture, Categories) {
+  ManualTestSetUp();
+
+  // 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_INSTANT0("c2", "name");
+  BeginTrace();
+  TRACE_EVENT_INSTANT0("c3", "name");
+  TRACE_EVENT_INSTANT0("c4", "name");
+  EndTraceAndFlush();
+  std::vector<std::string> cats;
+  TraceLog::GetInstance()->GetKnownCategories(&cats);
+  EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c1") != cats.end());
+  EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c2") != cats.end());
+  EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c3") != cats.end());
+  EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c4") != cats.end());
+
+  const std::vector<std::string> empty_categories;
+  std::vector<std::string> included_categories;
+  std::vector<std::string> excluded_categories;
+
+  // Test that category filtering works.
+
+  // Include nonexistent category -> no events
+  Clear();
+  included_categories.clear();
+  included_categories.push_back("not_found823564786");
+  TraceLog::GetInstance()->SetEnabled(included_categories, empty_categories);
+  TRACE_EVENT_INSTANT0("cat1", "name");
+  TRACE_EVENT_INSTANT0("cat2", "name");
+  EndTraceAndFlush();
+  EXPECT_TRUE(trace_parsed_.empty());
+
+  // Include existent category -> only events of that category
+  Clear();
+  included_categories.clear();
+  included_categories.push_back("inc");
+  TraceLog::GetInstance()->SetEnabled(included_categories, empty_categories);
+  TRACE_EVENT_INSTANT0("inc", "name");
+  TRACE_EVENT_INSTANT0("inc2", "name");
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "inc"));
+  EXPECT_FALSE(FindNonMatchingValue("cat", "inc"));
+
+  // Include existent wildcard -> all categories matching wildcard
+  Clear();
+  included_categories.clear();
+  included_categories.push_back("inc_wildcard_*");
+  included_categories.push_back("inc_wildchar_?_end");
+  TraceLog::GetInstance()->SetEnabled(included_categories, empty_categories);
+  TRACE_EVENT_INSTANT0("inc_wildcard_abc", "included");
+  TRACE_EVENT_INSTANT0("inc_wildcard_", "included");
+  TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "included");
+  TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "not_inc");
+  TRACE_EVENT_INSTANT0("cat1", "not_inc");
+  TRACE_EVENT_INSTANT0("cat2", "not_inc");
+  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"));
+
+  included_categories.clear();
+
+  // Exclude nonexistent category -> all events
+  Clear();
+  excluded_categories.clear();
+  excluded_categories.push_back("not_found823564786");
+  TraceLog::GetInstance()->SetEnabled(empty_categories, excluded_categories);
+  TRACE_EVENT_INSTANT0("cat1", "name");
+  TRACE_EVENT_INSTANT0("cat2", "name");
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
+  EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
+
+  // Exclude existent category -> only events of other categories
+  Clear();
+  excluded_categories.clear();
+  excluded_categories.push_back("inc");
+  TraceLog::GetInstance()->SetEnabled(empty_categories, excluded_categories);
+  TRACE_EVENT_INSTANT0("inc", "name");
+  TRACE_EVENT_INSTANT0("inc2", "name");
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "inc2"));
+  EXPECT_FALSE(FindMatchingValue("cat", "inc"));
+
+  // Exclude existent wildcard -> all categories not matching wildcard
+  Clear();
+  excluded_categories.clear();
+  excluded_categories.push_back("inc_wildcard_*");
+  excluded_categories.push_back("inc_wildchar_?_end");
+  TraceLog::GetInstance()->SetEnabled(empty_categories, excluded_categories);
+  TRACE_EVENT_INSTANT0("inc_wildcard_abc", "not_inc");
+  TRACE_EVENT_INSTANT0("inc_wildcard_", "not_inc");
+  TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "not_inc");
+  TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "included");
+  TRACE_EVENT_INSTANT0("cat1", "included");
+  TRACE_EVENT_INSTANT0("cat2", "included");
+  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"));
+}
+
+// Simple Test for time threshold events.
+TEST_F(TraceEventTestFixture, DataCapturedThreshold) {
+  ManualTestSetUp();
+  BeginTrace();
+
+  // Test that events at the same level are properly filtered by threshold.
+  {
+    TRACE_EVENT_IF_LONGER_THAN0(100, "time", "threshold 100");
+    TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "threshold 1000");
+    TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "threshold 10000");
+    // 100+ seconds to avoid flakiness.
+    TRACE_EVENT_IF_LONGER_THAN0(100000000, "time", "threshold long1");
+    TRACE_EVENT_IF_LONGER_THAN0(200000000, "time", "threshold long2");
+    HighResSleepForTraceTest(base::TimeDelta::FromMilliseconds(20));
+  }
+
+  // Test that a normal nested event remains after it's parent event is dropped.
+  {
+    TRACE_EVENT_IF_LONGER_THAN0(1000000, "time", "2threshold10000");
+    {
+      TRACE_EVENT0("time", "nonthreshold1");
+    }
+  }
+
+  // Test that parent thresholded events are dropped while some nested events
+  // remain.
+  {
+    TRACE_EVENT0("time", "nonthreshold3");
+    {
+      TRACE_EVENT_IF_LONGER_THAN0(200000000, "time", "3thresholdlong2");
+      {
+        TRACE_EVENT_IF_LONGER_THAN0(100000000, "time", "3thresholdlong1");
+        {
+          TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "3threshold10000");
+          {
+            TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "3threshold1000");
+            {
+              TRACE_EVENT_IF_LONGER_THAN0(100, "time", "3threshold100");
+              HighResSleepForTraceTest(base::TimeDelta::FromMilliseconds(20));
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Test that child thresholded events are dropped while some parent events
+  // remain.
+  {
+    TRACE_EVENT0("time", "nonthreshold4");
+    {
+      TRACE_EVENT_IF_LONGER_THAN0(100, "time", "4threshold100");
+      {
+        TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "4threshold1000");
+        {
+          TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "4threshold10000");
+          {
+            TRACE_EVENT_IF_LONGER_THAN0(100000000, "time",
+                                        "4thresholdlong1");
+            {
+              TRACE_EVENT_IF_LONGER_THAN0(200000000, "time",
+                                          "4thresholdlong2");
+              HighResSleepForTraceTest(base::TimeDelta::FromMilliseconds(20));
+            }
+          }
+        }
+      }
+    }
+  }
+
+  EndTraceAndFlush();
+
+#define EXPECT_FIND_BE_(str) \
+  EXPECT_TRUE(FindNamePhase(str, "B")); \
+  EXPECT_TRUE(FindNamePhase(str, "E"))
+#define EXPECT_NOT_FIND_BE_(str) \
+  EXPECT_FALSE(FindNamePhase(str, "B")); \
+  EXPECT_FALSE(FindNamePhase(str, "E"))
+
+  EXPECT_FIND_BE_("threshold 100");
+  EXPECT_FIND_BE_("threshold 1000");
+  EXPECT_FIND_BE_("threshold 10000");
+  EXPECT_NOT_FIND_BE_("threshold long1");
+  EXPECT_NOT_FIND_BE_("threshold long2");
+
+  EXPECT_NOT_FIND_BE_("2threshold10000");
+  EXPECT_FIND_BE_("nonthreshold1");
+
+  EXPECT_FIND_BE_("nonthreshold3");
+  EXPECT_FIND_BE_("3threshold100");
+  EXPECT_FIND_BE_("3threshold1000");
+  EXPECT_FIND_BE_("3threshold10000");
+  EXPECT_NOT_FIND_BE_("3thresholdlong1");
+  EXPECT_NOT_FIND_BE_("3thresholdlong2");
+
+  EXPECT_FIND_BE_("nonthreshold4");
+  EXPECT_FIND_BE_("4threshold100");
+  EXPECT_FIND_BE_("4threshold1000");
+  EXPECT_FIND_BE_("4threshold10000");
+  EXPECT_NOT_FIND_BE_("4thresholdlong1");
+  EXPECT_NOT_FIND_BE_("4thresholdlong2");
+}
+
+// Test EVENT_WATCH_NOTIFICATION
+TEST_F(TraceEventTestFixture, EventWatchNotification) {
+  ManualTestSetUp();
+
+  // Basic one occurrence.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event");
+  TRACE_EVENT_INSTANT0("cat", "event");
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 1);
+
+  // Basic one occurrence before Set.
+  BeginTrace();
+  TRACE_EVENT_INSTANT0("cat", "event");
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event");
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 1);
+
+  // Auto-reset after end trace.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event");
+  EndTraceAndFlush();
+  BeginTrace();
+  TRACE_EVENT_INSTANT0("cat", "event");
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+
+  // Multiple occurrence.
+  BeginTrace();
+  int num_occurrences = 5;
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event");
+  for (int i = 0; i < num_occurrences; ++i)
+    TRACE_EVENT_INSTANT0("cat", "event");
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, num_occurrences);
+
+  // Wrong category.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event");
+  TRACE_EVENT_INSTANT0("wrong_cat", "event");
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+
+  // Wrong name.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event");
+  TRACE_EVENT_INSTANT0("cat", "wrong_event");
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+
+  // Canceled.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event");
+  TraceLog::GetInstance()->CancelWatchEvent();
+  TRACE_EVENT_INSTANT0("cat", "event");
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+}
+
+// Test ASYNC_BEGIN/END events
+TEST_F(TraceEventTestFixture, AsyncBeginEndEvents) {
+  ManualTestSetUp();
+  BeginTrace();
+
+  unsigned long long id = 0xfeedbeeffeedbeefull;
+  TRACE_EVENT_ASYNC_BEGIN0( "cat", "name1", id);
+  TRACE_EVENT_ASYNC_STEP0( "cat", "name1", id, "step1");
+  TRACE_EVENT_ASYNC_END0("cat", "name1", id);
+  TRACE_EVENT_BEGIN0( "cat", "name2");
+  TRACE_EVENT_ASYNC_BEGIN0( "cat", "name3", 0);
+
+  EndTraceAndFlush();
+
+  EXPECT_TRUE(FindNamePhase("name1", "S"));
+  EXPECT_TRUE(FindNamePhase("name1", "T"));
+  EXPECT_TRUE(FindNamePhase("name1", "F"));
+
+  std::string id_str;
+  StringAppendF(&id_str, "%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", "0"));
+
+  // BEGIN events should not have id
+  EXPECT_FALSE(FindNamePhaseKeyValue("name2", "B", "id", "0"));
+}
+
+// Test ASYNC_BEGIN/END events
+TEST_F(TraceEventTestFixture, AsyncBeginEndPointerMangling) {
+  ManualTestSetUp();
+
+  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) {
+  ManualTestSetUp();
+  TraceLog* tracer = TraceLog::GetInstance();
+  // Make sure old events are flushed:
+  EndTraceAndFlush();
+  EXPECT_EQ(0u, tracer->GetEventsSize());
+
+  {
+    BeginTrace();
+    // Test that string arguments are copied.
+    TRACE_EVENT2("cat", "name1",
+                 "arg1", std::string("argval"), "arg2", std::string("argval"));
+    // Test that static TRACE_STR_COPY string arguments are copied.
+    TRACE_EVENT2("cat", "name2",
+                 "arg1", TRACE_STR_COPY("argval"),
+                 "arg2", TRACE_STR_COPY("argval"));
+    size_t num_events = tracer->GetEventsSize();
+    EXPECT_GT(num_events, 1u);
+    const TraceEvent& event1 = tracer->GetEventAt(num_events - 2);
+    const TraceEvent& event2 = tracer->GetEventAt(num_events - 1);
+    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.
+    TRACE_EVENT2("cat", "name1",
+                 "arg1", "argval", "arg2", "argval");
+    // Test that static TRACE_STR_COPY NULL string arguments are not copied.
+    const char* str1 = NULL;
+    const char* str2 = NULL;
+    TRACE_EVENT2("cat", "name2",
+                 "arg1", TRACE_STR_COPY(str1),
+                 "arg2", TRACE_STR_COPY(str2));
+    size_t num_events = tracer->GetEventsSize();
+    EXPECT_GT(num_events, 1u);
+    const TraceEvent& event1 = tracer->GetEventAt(num_events - 2);
+    const TraceEvent& event2 = tracer->GetEventAt(num_events - 1);
+    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) {
+  ManualTestSetUp();
+  BeginTrace();
+
+  Thread thread("1");
+  WaitableEvent task_complete_event(false, false);
+  thread.Start();
+
+  thread.message_loop()->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) {
+  ManualTestSetUp();
+  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).c_str());
+    task_complete_events[i] = new WaitableEvent(false, false);
+    threads[i]->Start();
+    threads[i]->message_loop()->PostTask(
+        FROM_HERE, base::Bind(&TraceManyInstantEvents,
+                              i, num_events, task_complete_events[i]));
+  }
+
+  for (int i = 0; i < num_threads; i++) {
+    task_complete_events[i]->Wait();
+  }
+
+  for (int i = 0; i < num_threads; i++) {
+    threads[i]->Stop();
+    delete threads[i];
+    delete task_complete_events[i];
+  }
+
+  EndTraceAndFlush();
+
+  ValidateInstantEventPresentOnEveryThread(trace_parsed_,
+                                           num_threads, num_events);
+}
+
+// Test that thread and process names show up in the trace
+TEST_F(TraceEventTestFixture, ThreadNames) {
+  ManualTestSetUp();
+
+  // Create threads before we enable tracing to make sure
+  // that tracelog still captures them.
+  const int num_threads = 4;
+  const int num_events = 10;
+  Thread* threads[num_threads];
+  PlatformThreadId thread_ids[num_threads];
+  for (int i = 0; i < num_threads; i++)
+    threads[i] = new Thread(StringPrintf("Thread %d", i).c_str());
+
+  // Enable tracing.
+  BeginTrace();
+
+  // Now run some trace code on these threads.
+  WaitableEvent* task_complete_events[num_threads];
+  for (int i = 0; i < num_threads; i++) {
+    task_complete_events[i] = new WaitableEvent(false, false);
+    threads[i]->Start();
+    thread_ids[i] = threads[i]->thread_id();
+    threads[i]->message_loop()->PostTask(
+        FROM_HERE, base::Bind(&TraceManyInstantEvents,
+                              i, num_events, task_complete_events[i]));
+  }
+  for (int i = 0; i < num_threads; i++) {
+    task_complete_events[i]->Wait();
+  }
+
+  // Shut things down.
+  for (int i = 0; i < num_threads; 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 < num_threads; 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) {
+  ManualTestSetUp();
+
+  BeginTrace();
+
+  PlatformThread::SetName("");
+  TRACE_EVENT_INSTANT0("drink", "water");
+
+  PlatformThread::SetName("cafe");
+  TRACE_EVENT_INSTANT0("drink", "coffee");
+
+  PlatformThread::SetName("shop");
+  // No event here, so won't appear in combined name.
+
+  PlatformThread::SetName("pub");
+  TRACE_EVENT_INSTANT0("drink", "beer");
+  TRACE_EVENT_INSTANT0("drink", "wine");
+
+  PlatformThread::SetName(" bar");
+  TRACE_EVENT_INSTANT0("drink", "whisky");
+
+  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 trace calls made after tracing singleton shut down.
+//
+// The singleton is destroyed by our base::AtExitManager, but there can be
+// code still executing as the C++ static objects are destroyed. This test
+// forces the singleton to destroy early, and intentinally makes trace calls
+// afterwards.
+TEST_F(TraceEventTestFixture, AtExit) {
+  // Repeat this test a few times. Besides just showing robustness, it also
+  // allows us to test that events at shutdown do not appear with valid events
+  // recorded after the system is started again.
+  for (int i = 0; i < 4; i++) {
+    // Scope to contain the then destroy the TraceLog singleton.
+    {
+      base::ShadowingAtExitManager exit_manager_will_destroy_singletons;
+
+      // Setup TraceLog singleton inside this test's exit manager scope
+      // so that it will be destroyed when this scope closes.
+      ManualTestSetUp();
+
+      TRACE_EVENT_INSTANT0("all", "not recorded; system not enabled");
+
+      BeginTrace();
+
+      TRACE_EVENT_INSTANT0("all", "is recorded 1; system has been enabled");
+      // Trace calls that will cache pointers to categories; they're valid here
+      TraceCallsWithCachedCategoryPointersPointers(
+          "is recorded 2; system has been enabled");
+
+      EndTraceAndFlush();
+    } // scope to destroy singleton
+    ASSERT_FALSE(TraceLog::GetInstance());
+
+    // Now that singleton is destroyed, check what trace events were recorded
+    const DictionaryValue* item = NULL;
+    ListValue& trace_parsed = trace_parsed_;
+    EXPECT_FIND_("is recorded 1");
+    EXPECT_FIND_("is recorded 2");
+    EXPECT_NOT_FIND_("not recorded");
+
+    // Make additional trace event calls on the shutdown system. They should
+    // all pass cleanly, but the data not be recorded. We'll verify that next
+    // time around the loop (the only way to flush the trace buffers).
+    TRACE_EVENT_BEGIN_ETW("not recorded; system shutdown", 0, NULL);
+    TRACE_EVENT_END_ETW("not recorded; system shutdown", 0, NULL);
+    TRACE_EVENT_INSTANT_ETW("not recorded; system shutdown", 0, NULL);
+    TRACE_EVENT0("all", "not recorded; system shutdown");
+    TRACE_EVENT_INSTANT0("all", "not recorded; system shutdown");
+    TRACE_EVENT_BEGIN0("all", "not recorded; system shutdown");
+    TRACE_EVENT_END0("all", "not recorded; system shutdown");
+
+    TRACE_EVENT0("new category 0!", "not recorded; system shutdown");
+    TRACE_EVENT_INSTANT0("new category 1!", "not recorded; system shutdown");
+    TRACE_EVENT_BEGIN0("new category 2!", "not recorded; system shutdown");
+    TRACE_EVENT_END0("new category 3!", "not recorded; system shutdown");
+
+    // Cached categories should be safe to check, and still disable traces
+    TraceCallsWithCachedCategoryPointersPointers(
+        "not recorded; system shutdown");
+  }
+}
+
+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.
+  ManualTestSetUp();
+
+  std::string name_string("event name");
+
+  BeginTrace();
+  TRACE_EVENT_INSTANT0("category", name_string.c_str());
+
+  // 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) {
+  ManualTestSetUp();
+
+  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_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) {
+  ManualTestSetUp();
+
+  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]");
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/trace_event_unittest.h b/base/debug/trace_event_unittest.h
new file mode 100644
index 0000000..3b570e1
--- /dev/null
+++ b/base/debug/trace_event_unittest.h
@@ -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/time.h"
+
+namespace base {
+namespace debug {
+
+// Sleep until HighResNow has advanced by at least |elapsed|.
+void HighResSleepForTraceTest(base::TimeDelta elapsed);
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/trace_event_win.cc b/base/debug/trace_event_win.cc
new file mode 100644
index 0000000..d5a21f4
--- /dev/null
+++ b/base/debug/trace_event_win.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/debug/trace_event_win.h"
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include <initguid.h>  // NOLINT
+
+namespace base {
+namespace debug {
+
+using base::win::EtwEventType;
+using base::win::EtwMofEvent;
+
+// {3DADA31D-19EF-4dc1-B345-037927193422}
+const GUID kChromeTraceProviderName = {
+    0x3dada31d, 0x19ef, 0x4dc1, 0xb3, 0x45, 0x3, 0x79, 0x27, 0x19, 0x34, 0x22 };
+
+// {B967AE67-BB22-49d7-9406-55D91EE1D560}
+const GUID kTraceEventClass32 = {
+    0xb967ae67, 0xbb22, 0x49d7, 0x94, 0x6, 0x55, 0xd9, 0x1e, 0xe1, 0xd5, 0x60 };
+
+// {97BE602D-2930-4ac3-8046-B6763B631DFE}
+const GUID kTraceEventClass64 = {
+    0x97be602d, 0x2930, 0x4ac3, 0x80, 0x46, 0xb6, 0x76, 0x3b, 0x63, 0x1d, 0xfe};
+
+
+TraceEventETWProvider::TraceEventETWProvider() :
+    EtwTraceProvider(kChromeTraceProviderName) {
+  Register();
+}
+
+TraceEventETWProvider* TraceEventETWProvider::GetInstance() {
+  return Singleton<TraceEventETWProvider,
+      StaticMemorySingletonTraits<TraceEventETWProvider> >::get();
+}
+
+bool TraceEventETWProvider::StartTracing() {
+  return true;
+}
+
+void TraceEventETWProvider::TraceEvent(const char* name,
+                                       size_t name_len,
+                                       char type,
+                                       const void* id,
+                                       const char* extra,
+                                       size_t extra_len) {
+  // Make sure we don't touch NULL.
+  if (name == NULL)
+    name = "";
+  if (extra == NULL)
+    extra = "";
+
+  EtwEventType etw_type = 0;
+  switch (type) {
+    case TRACE_EVENT_PHASE_BEGIN:
+      etw_type = kTraceEventTypeBegin;
+      break;
+    case TRACE_EVENT_PHASE_END:
+      etw_type = kTraceEventTypeEnd;
+      break;
+
+    case TRACE_EVENT_PHASE_INSTANT:
+      etw_type = kTraceEventTypeInstant;
+      break;
+
+    default:
+      NOTREACHED() << "Unknown event type";
+      etw_type = kTraceEventTypeInstant;
+      break;
+  }
+
+  EtwMofEvent<5> event(kTraceEventClass32,
+                       etw_type,
+                       TRACE_LEVEL_INFORMATION);
+  event.SetField(0, name_len + 1, name);
+  event.SetField(1, sizeof(id), &id);
+  event.SetField(2, extra_len + 1, extra);
+
+  // See whether we're to capture a backtrace.
+  void* backtrace[32];
+  if (enable_flags() & CAPTURE_STACK_TRACE) {
+    DWORD hash = 0;
+    DWORD depth = CaptureStackBackTrace(0,
+                                        arraysize(backtrace),
+                                        backtrace,
+                                        &hash);
+    event.SetField(3, sizeof(depth), &depth);
+    event.SetField(4, sizeof(backtrace[0]) * depth, backtrace);
+  }
+
+  // Trace the event.
+  Log(event.get());
+}
+
+void TraceEventETWProvider::Trace(const char* name,
+                                  size_t name_len,
+                                  char type,
+                                  const void* id,
+                                  const char* extra,
+                                  size_t extra_len) {
+  TraceEventETWProvider* provider = TraceEventETWProvider::GetInstance();
+  if (provider && provider->IsTracing()) {
+    // Compute the name & extra lengths if not supplied already.
+    if (name_len == -1)
+      name_len = (name == NULL) ? 0 : strlen(name);
+    if (extra_len == -1)
+      extra_len = (extra == NULL) ? 0 : strlen(extra);
+
+    provider->TraceEvent(name, name_len, type, id, extra, extra_len);
+  }
+}
+
+void TraceEventETWProvider::Resurrect() {
+  StaticMemorySingletonTraits<TraceEventETWProvider>::Resurrect();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/trace_event_win.h b/base/debug/trace_event_win.h
new file mode 100644
index 0000000..2a900bb
--- /dev/null
+++ b/base/debug/trace_event_win.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 file contains the Windows-specific declarations for trace_event.h.
+#ifndef BASE_DEBUG_TRACE_EVENT_WIN_H_
+#define BASE_DEBUG_TRACE_EVENT_WIN_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/debug/trace_event.h"
+#include "base/win/event_trace_provider.h"
+
+// Fwd.
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace base {
+namespace debug {
+
+// This EtwTraceProvider subclass implements ETW logging
+// for the macros above on Windows.
+class BASE_EXPORT TraceEventETWProvider : public base::win::EtwTraceProvider {
+ public:
+  // Start logging trace events.
+  // This is a noop in this implementation.
+  static bool StartTracing();
+
+  // Trace begin/end/instant events, this is the bottleneck implementation
+  // all the others defer to.
+  // Allowing the use of std::string for name or extra is a convenience,
+  // whereas passing name or extra as a const char* avoids the construction
+  // of temporary std::string instances.
+  // If -1 is passed for name_len or extra_len, the strlen of the string will
+  // be used for length.
+  static void Trace(const char* name,
+                    size_t name_len,
+                    char type,
+                    const void* id,
+                    const char* extra,
+                    size_t extra_len);
+
+  // Allows passing extra as a std::string for convenience.
+  static void Trace(const char* name,
+                    char type,
+                    const void* id,
+                    const std::string& extra) {
+    return Trace(name, -1, type, id, extra.c_str(), extra.length());
+  }
+
+  // Allows passing extra as a const char* to avoid constructing temporary
+  // std::string instances where not needed.
+  static void Trace(const char* name,
+                    char type,
+                    const void* id,
+                    const char* extra) {
+    return Trace(name, -1, type, id, extra, -1);
+  }
+
+  // Retrieves the singleton.
+  // Note that this may return NULL post-AtExit processing.
+  static TraceEventETWProvider* GetInstance();
+
+  // Returns true iff tracing is turned on.
+  bool IsTracing() {
+    return enable_level() >= TRACE_LEVEL_INFORMATION;
+  }
+
+  // Emit a trace of type |type| containing |name|, |id|, and |extra|.
+  // Note: |name| and |extra| must be NULL, or a zero-terminated string of
+  //    length |name_len| or |extra_len| respectively.
+  // Note: if name_len or extra_len are -1, the length of the corresponding
+  //    string will be used.
+  void TraceEvent(const char* name,
+                  size_t name_len,
+                  char type,
+                  const void* id,
+                  const char* extra,
+                  size_t extra_len);
+
+  // Exposed for unittesting only, allows resurrecting our
+  // singleton instance post-AtExit processing.
+  static void Resurrect();
+
+ private:
+  // Ensure only the provider can construct us.
+  friend struct StaticMemorySingletonTraits<TraceEventETWProvider>;
+  TraceEventETWProvider();
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventETWProvider);
+};
+
+// The ETW trace provider GUID.
+BASE_EXPORT extern const GUID kChromeTraceProviderName;
+
+// The ETW event class GUID for 32 bit events.
+BASE_EXPORT extern const GUID kTraceEventClass32;
+
+// The ETW event class GUID for 64 bit events.
+BASE_EXPORT extern const GUID kTraceEventClass64;
+
+// The ETW event types, IDs 0x00-0x09 are reserved, so start at 0x10.
+const base::win::EtwEventType kTraceEventTypeBegin = 0x10;
+const base::win::EtwEventType kTraceEventTypeEnd = 0x11;
+const base::win::EtwEventType kTraceEventTypeInstant = 0x12;
+
+// If this flag is set in enable flags
+enum TraceEventETWFlags {
+  CAPTURE_STACK_TRACE = 0x0001,
+};
+
+// The event format consists of:
+// The "name" string as a zero-terminated ASCII string.
+// The id pointer in the machine bitness.
+// The "extra" string as a zero-terminated ASCII string.
+// Optionally the stack trace, consisting of a DWORD "depth", followed
+//    by an array of void* (machine bitness) of length "depth".
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_TRACE_EVENT_WIN_H_
diff --git a/base/debug/trace_event_win_unittest.cc b/base/debug/trace_event_win_unittest.cc
new file mode 100644
index 0000000..786b9d5
--- /dev/null
+++ b/base/debug/trace_event_win_unittest.cc
@@ -0,0 +1,316 @@
+// Copyright (c) 2011 The Chromium Authors. All 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/trace_event.h"
+
+#include <strstream>
+
+#include "base/at_exit.h"
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/debug/trace_event.h"
+#include "base/debug/trace_event_win.h"
+#include "base/win/event_trace_consumer.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
+#include "base/win/windows_version.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include <initguid.h>  // NOLINT - must be last include.
+
+namespace base {
+namespace debug {
+
+namespace {
+
+using testing::_;
+using testing::AnyNumber;
+using testing::InSequence;
+using testing::Ge;
+using testing::Le;
+using testing::NotNull;
+
+using base::win::EtwEventType;
+using base::win::EtwTraceConsumerBase;
+using base::win::EtwTraceController;
+using base::win::EtwTraceProperties;
+
+// Data for unittests traces.
+const char kEmpty[] = "";
+const char kName[] = "unittest.trace_name";
+const char kExtra[] = "UnittestDummyExtraString";
+const void* kId = kName;
+
+const wchar_t kTestSessionName[] = L"TraceEvent unittest session";
+
+MATCHER_P(BufferStartsWith, str, "Buffer starts with") {
+  return memcmp(arg, str.c_str(), str.length()) == 0;
+}
+
+// Duplicated from <evntrace.h> to fix link problems.
+DEFINE_GUID( /* 68fdd900-4a3e-11d1-84f4-0000f80464e3 */
+    kEventTraceGuid,
+    0x68fdd900,
+    0x4a3e,
+    0x11d1,
+    0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3);
+
+class TestEventConsumer: public EtwTraceConsumerBase<TestEventConsumer> {
+ public:
+  TestEventConsumer() {
+    EXPECT_TRUE(current_ == NULL);
+    current_ = this;
+  }
+
+  ~TestEventConsumer() {
+    EXPECT_TRUE(current_ == this);
+    current_ = NULL;
+  }
+
+  MOCK_METHOD4(Event, void(REFGUID event_class,
+                      EtwEventType event_type,
+                      size_t buf_len,
+                      const void* buf));
+
+  static void ProcessEvent(EVENT_TRACE* event) {
+    ASSERT_TRUE(current_ != NULL);
+    current_->Event(event->Header.Guid,
+                    event->Header.Class.Type,
+                    event->MofLength,
+                    event->MofData);
+  }
+
+ private:
+  static TestEventConsumer* current_;
+};
+
+TestEventConsumer* TestEventConsumer::current_ = NULL;
+
+class TraceEventWinTest: public testing::Test {
+ public:
+  TraceEventWinTest() {
+  }
+
+  void SetUp() {
+    bool is_xp = win::GetVersion() < base::win::VERSION_VISTA;
+
+    if (is_xp) {
+      // Tear down any dangling session from an earlier failing test.
+      EtwTraceProperties ignore;
+      EtwTraceController::Stop(kTestSessionName, &ignore);
+    }
+
+    // Resurrect and initialize the TraceLog singleton instance.
+    // On Vista and better, we need the provider registered before we
+    // start the private, in-proc session, but on XP we need the global
+    // session created and the provider enabled before we register our
+    // provider.
+    TraceEventETWProvider* tracelog = NULL;
+    if (!is_xp) {
+      TraceEventETWProvider::Resurrect();
+      tracelog = TraceEventETWProvider::GetInstance();
+      ASSERT_TRUE(tracelog != NULL);
+      ASSERT_FALSE(tracelog->IsTracing());
+    }
+
+    // Create the log file.
+    ASSERT_TRUE(file_util::CreateTemporaryFile(&log_file_));
+
+    // Create a private log session on the file.
+    EtwTraceProperties prop;
+    ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerFileName(log_file_.value().c_str()));
+    EVENT_TRACE_PROPERTIES& p = *prop.get();
+    p.Wnode.ClientContext = 1;  // QPC timer accuracy.
+    p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;   // Sequential log.
+
+    // On Vista and later, we create a private in-process log session, because
+    // otherwise we'd need administrator privileges. Unfortunately we can't
+    // do the same on XP and better, because the semantics of a private
+    // logger session are different, and the IN_PROC flag is not supported.
+    if (!is_xp) {
+      p.LogFileMode |= EVENT_TRACE_PRIVATE_IN_PROC |  // In-proc for non-admin.
+          EVENT_TRACE_PRIVATE_LOGGER_MODE;  // Process-private log.
+    }
+
+    p.MaximumFileSize = 100;  // 100M file size.
+    p.FlushTimer = 1;  // 1 second flush lag.
+    ASSERT_HRESULT_SUCCEEDED(controller_.Start(kTestSessionName, &prop));
+
+    // Enable the TraceLog provider GUID.
+    ASSERT_HRESULT_SUCCEEDED(
+        controller_.EnableProvider(kChromeTraceProviderName,
+                                   TRACE_LEVEL_INFORMATION,
+                                   0));
+
+    if (is_xp) {
+      TraceEventETWProvider::Resurrect();
+      tracelog = TraceEventETWProvider::GetInstance();
+    }
+    ASSERT_TRUE(tracelog != NULL);
+    EXPECT_TRUE(tracelog->IsTracing());
+  }
+
+  void TearDown() {
+    EtwTraceProperties prop;
+    if (controller_.session() != 0)
+      EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop));
+
+    if (!log_file_.value().empty())
+      file_util::Delete(log_file_, false);
+  }
+
+  void ExpectEvent(REFGUID guid,
+                   EtwEventType type,
+                   const char* name,
+                   size_t name_len,
+                   const void* id,
+                   const char* extra,
+                   size_t extra_len) {
+    // Build the trace event buffer we expect will result from this.
+    std::stringbuf str;
+    str.sputn(name, name_len + 1);
+    str.sputn(reinterpret_cast<const char*>(&id), sizeof(id));
+    str.sputn(extra, extra_len + 1);
+
+    // And set up the expectation for the event callback.
+    EXPECT_CALL(consumer_, Event(guid,
+                                 type,
+                                 testing::Ge(str.str().length()),
+                                 BufferStartsWith(str.str())));
+  }
+
+  void ExpectPlayLog() {
+    // Ignore EventTraceGuid events.
+    EXPECT_CALL(consumer_, Event(kEventTraceGuid, _, _, _))
+        .Times(AnyNumber());
+  }
+
+  void PlayLog() {
+    EtwTraceProperties prop;
+    EXPECT_HRESULT_SUCCEEDED(controller_.Flush(&prop));
+    EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop));
+    ASSERT_HRESULT_SUCCEEDED(
+        consumer_.OpenFileSession(log_file_.value().c_str()));
+
+    ASSERT_HRESULT_SUCCEEDED(consumer_.Consume());
+  }
+
+ private:
+  // We want our singleton torn down after each test.
+  ShadowingAtExitManager at_exit_manager_;
+  EtwTraceController controller_;
+  FilePath log_file_;
+  TestEventConsumer consumer_;
+};
+
+}  // namespace
+
+
+TEST_F(TraceEventWinTest, TraceLog) {
+  ExpectPlayLog();
+
+  // The events should arrive in the same sequence as the expects.
+  InSequence in_sequence;
+
+  // Full argument version, passing lengths explicitly.
+  TraceEventETWProvider::Trace(kName,
+                        strlen(kName),
+                        TRACE_EVENT_PHASE_BEGIN,
+                        kId,
+                        kExtra,
+                        strlen(kExtra));
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeBegin,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  // Const char* version.
+  TraceEventETWProvider::Trace(static_cast<const char*>(kName),
+                        TRACE_EVENT_PHASE_END,
+                        kId,
+                        static_cast<const char*>(kExtra));
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeEnd,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  // std::string extra version.
+  TraceEventETWProvider::Trace(static_cast<const char*>(kName),
+                        TRACE_EVENT_PHASE_INSTANT,
+                        kId,
+                        std::string(kExtra));
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeInstant,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+
+  // Test for sanity on NULL inputs.
+  TraceEventETWProvider::Trace(NULL,
+                        0,
+                        TRACE_EVENT_PHASE_BEGIN,
+                        kId,
+                        NULL,
+                        0);
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeBegin,
+              kEmpty, 0,
+              kId,
+              kEmpty, 0);
+
+  TraceEventETWProvider::Trace(NULL,
+                        -1,
+                        TRACE_EVENT_PHASE_END,
+                        kId,
+                        NULL,
+                        -1);
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeEnd,
+              kEmpty, 0,
+              kId,
+              kEmpty, 0);
+
+  PlayLog();
+}
+
+TEST_F(TraceEventWinTest, Macros) {
+  ExpectPlayLog();
+
+  // The events should arrive in the same sequence as the expects.
+  InSequence in_sequence;
+
+  TRACE_EVENT_BEGIN_ETW(kName, kId, kExtra);
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeBegin,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  TRACE_EVENT_END_ETW(kName, kId, kExtra);
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeEnd,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  TRACE_EVENT_INSTANT_ETW(kName, kId, kExtra);
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeInstant,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  PlayLog();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug_message.cc b/base/debug_message.cc
new file mode 100644
index 0000000..10f441d
--- /dev/null
+++ b/base/debug_message.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+// Display the command line. This program is designed to be called from
+// another process to display assertions. Since the other process has
+// complete control of our command line, we assume that it did *not*
+// add the program name as the first parameter. This allows us to just
+// show the command line directly as the message.
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+                     LPSTR lpCmdLine, int nCmdShow) {
+  LPWSTR cmdline = GetCommandLineW();
+  MessageBox(NULL, cmdline, L"Kr\x00d8m", MB_TOPMOST);
+  return 0;
+}
diff --git a/base/eintr_wrapper.h b/base/eintr_wrapper.h
new file mode 100644
index 0000000..a1b7f7b
--- /dev/null
+++ b/base/eintr_wrapper.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.
+
+// This provides a wrapper around system calls which may be interrupted by a
+// signal and return EINTR. See man 7 signal.
+//
+// On Windows, this wrapper macro does nothing.
+
+#ifndef BASE_EINTR_WRAPPER_H_
+#define BASE_EINTR_WRAPPER_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+
+#include <errno.h>
+
+#define HANDLE_EINTR(x) ({ \
+  typeof(x) __eintr_result__; \
+  do { \
+    __eintr_result__ = (x); \
+  } while (__eintr_result__ == -1 && errno == EINTR); \
+  __eintr_result__;\
+})
+
+#else
+
+#define HANDLE_EINTR(x) (x)
+
+#endif  // OS_POSIX
+
+#endif  // BASE_EINTR_WRAPPER_H_
diff --git a/base/environment.cc b/base/environment.cc
new file mode 100644
index 0000000..8c61591
--- /dev/null
+++ b/base/environment.cc
@@ -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.
+
+#include "base/environment.h"
+
+#if defined(OS_POSIX)
+#include <stdlib.h>
+#elif defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include "base/string_util.h"
+
+#if defined(OS_WIN)
+#include "base/memory/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
+#endif
+
+namespace {
+
+class EnvironmentImpl : public base::Environment {
+ public:
+  virtual bool GetVar(const char* variable_name,
+                      std::string* result) OVERRIDE {
+    if (GetVarImpl(variable_name, result))
+      return true;
+
+    // Some commonly used variable names are uppercase while others
+    // are lowercase, which is inconsistent. Let's try to be helpful
+    // and look for a variable name with the reverse case.
+    // I.e. HTTP_PROXY may be http_proxy for some users/systems.
+    char first_char = variable_name[0];
+    std::string alternate_case_var;
+    if (first_char >= 'a' && first_char <= 'z')
+      alternate_case_var = StringToUpperASCII(std::string(variable_name));
+    else if (first_char >= 'A' && first_char <= 'Z')
+      alternate_case_var = StringToLowerASCII(std::string(variable_name));
+    else
+      return false;
+    return GetVarImpl(alternate_case_var.c_str(), result);
+  }
+
+  virtual bool SetVar(const char* variable_name,
+                      const std::string& new_value) OVERRIDE {
+    return SetVarImpl(variable_name, new_value);
+  }
+
+  virtual bool UnSetVar(const char* variable_name) OVERRIDE {
+    return UnSetVarImpl(variable_name);
+  }
+
+ private:
+  bool GetVarImpl(const char* variable_name, std::string* result) {
+#if defined(OS_POSIX)
+    const char* env_value = getenv(variable_name);
+    if (!env_value)
+      return false;
+    // Note that the variable may be defined but empty.
+    if (result)
+      *result = env_value;
+    return true;
+#elif defined(OS_WIN)
+    DWORD value_length = ::GetEnvironmentVariable(
+        UTF8ToWide(variable_name).c_str(), NULL, 0);
+    if (value_length == 0)
+      return false;
+    if (result) {
+      scoped_array<wchar_t> value(new wchar_t[value_length]);
+      ::GetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), value.get(),
+                               value_length);
+      *result = WideToUTF8(value.get());
+    }
+    return true;
+#else
+#error need to port
+#endif
+  }
+
+  bool SetVarImpl(const char* variable_name, const std::string& new_value) {
+#if defined(OS_POSIX)
+    // On success, zero is returned.
+    return !setenv(variable_name, new_value.c_str(), 1);
+#elif defined(OS_WIN)
+    // On success, a nonzero value is returned.
+    return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(),
+                                    UTF8ToWide(new_value).c_str());
+#endif
+  }
+
+  bool UnSetVarImpl(const char* variable_name) {
+#if defined(OS_POSIX)
+    // On success, zero is returned.
+    return !unsetenv(variable_name);
+#elif defined(OS_WIN)
+    // On success, a nonzero value is returned.
+    return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), NULL);
+#endif
+  }
+};
+
+}  // namespace
+
+namespace base {
+
+namespace env_vars {
+
+#if defined(OS_POSIX)
+// On Posix systems, this variable contains the location of the user's home
+// directory. (e.g, /home/username/).
+const char kHome[] = "HOME";
+#endif
+
+}  // namespace env_vars
+
+Environment::~Environment() {}
+
+// static
+Environment* Environment::Create() {
+  return new EnvironmentImpl();
+}
+
+bool Environment::HasVar(const char* variable_name) {
+  return GetVar(variable_name, NULL);
+}
+
+}  // namespace base
diff --git a/base/environment.h b/base/environment.h
new file mode 100644
index 0000000..5160ff2
--- /dev/null
+++ b/base/environment.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ENVIRONMENT_H_
+#define BASE_ENVIRONMENT_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace env_vars {
+
+#if defined(OS_POSIX)
+BASE_EXPORT extern const char kHome[];
+#endif
+
+}  // namespace env_vars
+
+class BASE_EXPORT Environment {
+ public:
+  virtual ~Environment();
+
+  // Static factory method that returns the implementation that provide the
+  // appropriate platform-specific instance.
+  static Environment* Create();
+
+  // Gets an environment variable's value and stores it in |result|.
+  // Returns false if the key is unset.
+  virtual bool GetVar(const char* variable_name, std::string* result) = 0;
+
+  // Syntactic sugar for GetVar(variable_name, NULL);
+  virtual bool HasVar(const char* variable_name);
+
+  // Returns true on success, otherwise returns false.
+  virtual bool SetVar(const char* variable_name,
+                      const std::string& new_value) = 0;
+
+  // Returns true on success, otherwise returns false.
+  virtual bool UnSetVar(const char* variable_name) = 0;
+};
+
+}  // namespace base
+
+#endif  // BASE_ENVIRONMENT_H_
diff --git a/base/environment_unittest.cc b/base/environment_unittest.cc
new file mode 100644
index 0000000..b6654c9
--- /dev/null
+++ b/base/environment_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/environment.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest EnvironmentTest;
+
+TEST_F(EnvironmentTest, GetVar) {
+  // Every setup should have non-empty PATH...
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  std::string env_value;
+  EXPECT_TRUE(env->GetVar("PATH", &env_value));
+  EXPECT_NE(env_value, "");
+}
+
+TEST_F(EnvironmentTest, GetVarReverse) {
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  const char* kFooUpper = "FOO";
+  const char* kFooLower = "foo";
+
+  // Set a variable in UPPER case.
+  EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+  // And then try to get this variable passing the lower case.
+  std::string env_value;
+  EXPECT_TRUE(env->GetVar(kFooLower, &env_value));
+
+  EXPECT_STREQ(env_value.c_str(), kFooLower);
+
+  EXPECT_TRUE(env->UnSetVar(kFooUpper));
+
+  const char* kBar = "bar";
+  // Now do the opposite, set the variable in the lower case.
+  EXPECT_TRUE(env->SetVar(kFooLower, kBar));
+
+  // And then try to get this variable passing the UPPER case.
+  EXPECT_TRUE(env->GetVar(kFooUpper, &env_value));
+
+  EXPECT_STREQ(env_value.c_str(), kBar);
+
+  EXPECT_TRUE(env->UnSetVar(kFooLower));
+}
+
+TEST_F(EnvironmentTest, HasVar) {
+  // Every setup should have PATH...
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  EXPECT_TRUE(env->HasVar("PATH"));
+}
+
+TEST_F(EnvironmentTest, SetVar) {
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+
+  const char* kFooUpper = "FOO";
+  const char* kFooLower = "foo";
+  EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+  // Now verify that the environment has the new variable.
+  EXPECT_TRUE(env->HasVar(kFooUpper));
+
+  std::string var_value;
+  EXPECT_TRUE(env->GetVar(kFooUpper, &var_value));
+  EXPECT_EQ(var_value, kFooLower);
+}
+
+TEST_F(EnvironmentTest, UnSetVar) {
+  scoped_ptr<base::Environment> env(base::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));
+}
diff --git a/base/event_recorder.h b/base/event_recorder.h
new file mode 100644
index 0000000..32e1124
--- /dev/null
+++ b/base/event_recorder.h
@@ -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.
+
+#ifndef BASE_EVENT_RECORDER_H_
+#define BASE_EVENT_RECORDER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <stdio.h>
+#include <string.h>
+#include <windows.h>
+#endif
+
+class FilePath;
+
+namespace base {
+
+// A class for recording and playing back keyboard and mouse input events.
+//
+// Note - if you record events, and the playback with the windows in
+//        different sizes or positions, the playback will fail.  When
+//        recording and playing, you should move the relevant windows
+//        to constant sizes and locations.
+// TODO(mbelshe) For now this is a singleton.  I believe that this class
+//        could be easily modified to:
+//             support two simultaneous recorders
+//             be playing back events while already recording events.
+//        Why?  Imagine if the product had a "record a macro" feature.
+//        You might be recording globally, while recording or playing back
+//        a macro.  I don't think two playbacks make sense.
+class BASE_EXPORT EventRecorder {
+ public:
+  // Get the singleton EventRecorder.
+  // We can only handle one recorder/player at a time.
+  static EventRecorder* current() {
+    if (!current_)
+      current_ = new EventRecorder();
+    return current_;
+  }
+
+  // Starts recording events.
+  // Will clobber the file if it already exists.
+  // Returns true on success, or false if an error occurred.
+  bool StartRecording(const FilePath& filename);
+
+  // Stops recording.
+  void StopRecording();
+
+  // Is the EventRecorder currently recording.
+  bool is_recording() const { return is_recording_; }
+
+  // Plays events previously recorded.
+  // Returns true on success, or false if an error occurred.
+  bool StartPlayback(const FilePath& filename);
+
+  // Stops playback.
+  void StopPlayback();
+
+  // Is the EventRecorder currently playing.
+  bool is_playing() const { return is_playing_; }
+
+#if defined(OS_WIN)
+  // C-style callbacks for the EventRecorder.
+  // Used for internal purposes only.
+  LRESULT RecordWndProc(int nCode, WPARAM wParam, LPARAM lParam);
+  LRESULT PlaybackWndProc(int nCode, WPARAM wParam, LPARAM lParam);
+#endif
+
+ private:
+  // Create a new EventRecorder.  Events are saved to the file filename.
+  // If the file already exists, it will be deleted before recording
+  // starts.
+  explicit EventRecorder()
+      : is_recording_(false),
+        is_playing_(false),
+#if defined(OS_WIN)
+        journal_hook_(NULL),
+        file_(NULL),
+#endif
+        playback_first_msg_time_(0),
+        playback_start_time_(0) {
+#if defined(OS_WIN)
+    memset(&playback_msg_, 0, sizeof(playback_msg_));
+#endif
+  }
+  ~EventRecorder();
+
+  static EventRecorder* current_;  // Our singleton.
+
+  bool is_recording_;
+  bool is_playing_;
+#if defined(OS_WIN)
+  HHOOK journal_hook_;
+  FILE* file_;
+  EVENTMSG playback_msg_;
+#endif
+  int playback_first_msg_time_;
+  int playback_start_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(EventRecorder);
+};
+
+}  // namespace base
+
+#endif // BASE_EVENT_RECORDER_H_
diff --git a/base/event_recorder_stubs.cc b/base/event_recorder_stubs.cc
new file mode 100644
index 0000000..91f2e07
--- /dev/null
+++ b/base/event_recorder_stubs.cc
@@ -0,0 +1,28 @@
+// 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/event_recorder.h"
+
+// This file implements a link stub for EventRecorder that can be used on
+// platforms that don't have a working EventRecorder implementation.
+
+namespace base {
+
+EventRecorder* EventRecorder::current_;  // Our singleton.
+
+bool EventRecorder::StartRecording(const FilePath& filename) {
+  return true;
+}
+
+void EventRecorder::StopRecording() {
+}
+
+bool EventRecorder::StartPlayback(const FilePath& filename) {
+  return false;
+}
+
+void EventRecorder::StopPlayback() {
+}
+
+}  // namespace
diff --git a/base/event_recorder_win.cc b/base/event_recorder_win.cc
new file mode 100644
index 0000000..11bf0f0
--- /dev/null
+++ b/base/event_recorder_win.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "base/event_recorder.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+
+// A note about time.
+// For perfect playback of events, you'd like a very accurate timer
+// so that events are played back at exactly the same time that
+// they were recorded.  However, windows has a clock which is only
+// granular to ~15ms.  We see more consistent event playback when
+// using a higher resolution timer.  To do this, we use the
+// timeGetTime API instead of the default GetTickCount() API.
+
+namespace base {
+
+EventRecorder* EventRecorder::current_ = NULL;
+
+LRESULT CALLBACK StaticRecordWndProc(int nCode, WPARAM wParam,
+                                     LPARAM lParam) {
+  DCHECK(EventRecorder::current());
+  return EventRecorder::current()->RecordWndProc(nCode, wParam, lParam);
+}
+
+LRESULT CALLBACK StaticPlaybackWndProc(int nCode, WPARAM wParam,
+                                       LPARAM lParam) {
+  DCHECK(EventRecorder::current());
+  return EventRecorder::current()->PlaybackWndProc(nCode, wParam, lParam);
+}
+
+EventRecorder::~EventRecorder() {
+  // Try to assert early if the caller deletes the recorder
+  // while it is still in use.
+  DCHECK(!journal_hook_);
+  DCHECK(!is_recording_ && !is_playing_);
+}
+
+bool EventRecorder::StartRecording(const FilePath& filename) {
+  if (journal_hook_ != NULL)
+    return false;
+  if (is_recording_ || is_playing_)
+    return false;
+
+  // Open the recording file.
+  DCHECK(!file_);
+  file_ = file_util::OpenFile(filename, "wb+");
+  if (!file_) {
+    DLOG(ERROR) << "EventRecorder could not open log file";
+    return false;
+  }
+
+  // Set the faster clock, if possible.
+  ::timeBeginPeriod(1);
+
+  // Set the recording hook.  JOURNALRECORD can only be used as a global hook.
+  journal_hook_ = ::SetWindowsHookEx(WH_JOURNALRECORD, StaticRecordWndProc,
+                                     GetModuleHandle(NULL), 0);
+  if (!journal_hook_) {
+    DLOG(ERROR) << "EventRecorder Record Hook failed";
+    file_util::CloseFile(file_);
+    return false;
+  }
+
+  is_recording_ = true;
+  return true;
+}
+
+void EventRecorder::StopRecording() {
+  if (is_recording_) {
+    DCHECK(journal_hook_ != NULL);
+
+    if (!::UnhookWindowsHookEx(journal_hook_)) {
+      DLOG(ERROR) << "EventRecorder Unhook failed";
+      // Nothing else we can really do here.
+      return;
+    }
+
+    ::timeEndPeriod(1);
+
+    DCHECK(file_ != NULL);
+    file_util::CloseFile(file_);
+    file_ = NULL;
+
+    journal_hook_ = NULL;
+    is_recording_ = false;
+  }
+}
+
+bool EventRecorder::StartPlayback(const FilePath& filename) {
+  if (journal_hook_ != NULL)
+    return false;
+  if (is_recording_ || is_playing_)
+    return false;
+
+  // Open the recording file.
+  DCHECK(!file_);
+  file_ = file_util::OpenFile(filename, "rb");
+  if (!file_) {
+    DLOG(ERROR) << "EventRecorder Playback could not open log file";
+    return false;
+  }
+  // Read the first event from the record.
+  if (fread(&playback_msg_, sizeof(EVENTMSG), 1, file_) != 1) {
+    DLOG(ERROR) << "EventRecorder Playback has no records!";
+    file_util::CloseFile(file_);
+    return false;
+  }
+
+  // Set the faster clock, if possible.
+  ::timeBeginPeriod(1);
+
+  // Playback time is tricky.  When playing back, we read a series of events,
+  // each with timeouts.  Simply subtracting the delta between two timers will
+  // lead to fast playback (about 2x speed).  The API has two events, one
+  // which advances to the next event (HC_SKIP), and another that requests the
+  // event (HC_GETNEXT).  The same event will be requested multiple times.
+  // Each time the event is requested, we must calculate the new delay.
+  // To do this, we track the start time of the playback, and constantly
+  // re-compute the delay.   I mention this only because I saw two examples
+  // of how to use this code on the net, and both were broken :-)
+  playback_start_time_ = timeGetTime();
+  playback_first_msg_time_ = playback_msg_.time;
+
+  // Set the hook.  JOURNALPLAYBACK can only be used as a global hook.
+  journal_hook_ = ::SetWindowsHookEx(WH_JOURNALPLAYBACK, StaticPlaybackWndProc,
+                                     GetModuleHandle(NULL), 0);
+  if (!journal_hook_) {
+    DLOG(ERROR) << "EventRecorder Playback Hook failed";
+    return false;
+  }
+
+  is_playing_ = true;
+
+  return true;
+}
+
+void EventRecorder::StopPlayback() {
+  if (is_playing_) {
+    DCHECK(journal_hook_ != NULL);
+
+    if (!::UnhookWindowsHookEx(journal_hook_)) {
+      DLOG(ERROR) << "EventRecorder Unhook failed";
+      // Nothing else we can really do here.
+    }
+
+    DCHECK(file_ != NULL);
+    file_util::CloseFile(file_);
+    file_ = NULL;
+
+    ::timeEndPeriod(1);
+
+    journal_hook_ = NULL;
+    is_playing_ = false;
+  }
+}
+
+// Windows callback hook for the recorder.
+LRESULT EventRecorder::RecordWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
+  static bool recording_enabled = true;
+  EVENTMSG* msg_ptr = NULL;
+
+  // The API says we have to do this.
+  // See http://msdn2.microsoft.com/en-us/library/ms644983(VS.85).aspx
+  if (nCode < 0)
+    return ::CallNextHookEx(journal_hook_, nCode, wParam, lParam);
+
+  // Check for the break key being pressed and stop recording.
+  if (::GetKeyState(VK_CANCEL) & 0x8000) {
+    StopRecording();
+    return ::CallNextHookEx(journal_hook_, nCode, wParam, lParam);
+  }
+
+  // The Journal Recorder must stop recording events when system modal
+  // dialogs are present. (see msdn link above)
+  switch (nCode) {
+    case HC_SYSMODALON:
+      recording_enabled = false;
+      break;
+    case HC_SYSMODALOFF:
+      recording_enabled = true;
+      break;
+  }
+
+  if (nCode == HC_ACTION && recording_enabled) {
+    // Aha - we have an event to record.
+    msg_ptr = reinterpret_cast<EVENTMSG*>(lParam);
+    msg_ptr->time = timeGetTime();
+    fwrite(msg_ptr, sizeof(EVENTMSG), 1, file_);
+    fflush(file_);
+  }
+
+  return CallNextHookEx(journal_hook_, nCode, wParam, lParam);
+}
+
+// Windows callback for the playback mode.
+LRESULT EventRecorder::PlaybackWndProc(int nCode, WPARAM wParam,
+                                       LPARAM lParam) {
+  static bool playback_enabled = true;
+  int delay = 0;
+
+  switch (nCode) {
+    // A system modal dialog box is being displayed.  Stop playing back
+    // messages.
+    case HC_SYSMODALON:
+      playback_enabled = false;
+      break;
+
+    // A system modal dialog box is destroyed.  We can start playing back
+    // messages again.
+    case HC_SYSMODALOFF:
+      playback_enabled = true;
+      break;
+
+    // Prepare to copy the next mouse or keyboard event to playback.
+    case HC_SKIP:
+      if (!playback_enabled)
+        break;
+
+      // Read the next event from the record.
+      if (fread(&playback_msg_, sizeof(EVENTMSG), 1, file_) != 1)
+        this->StopPlayback();
+      break;
+
+    // Copy the mouse or keyboard event to the EVENTMSG structure in lParam.
+    case HC_GETNEXT:
+      if (!playback_enabled)
+        break;
+
+      memcpy(reinterpret_cast<void*>(lParam), &playback_msg_,
+             sizeof(playback_msg_));
+
+      // The return value is the amount of time (in milliseconds) to wait
+      // before playing back the next message in the playback queue.  Each
+      // time this is called, we recalculate the delay relative to our current
+      // wall clock.
+      delay = (playback_msg_.time - playback_first_msg_time_) -
+              (timeGetTime() - playback_start_time_);
+      if (delay < 0)
+        delay = 0;
+      return delay;
+
+    // An application has called PeekMessage with wRemoveMsg set to PM_NOREMOVE
+    // indicating that the message is not removed from the message queue after
+    // PeekMessage processing.
+    case HC_NOREMOVE:
+      break;
+  }
+
+  return CallNextHookEx(journal_hook_, nCode, wParam, lParam);
+}
+
+}  // namespace base
diff --git a/base/event_types.h b/base/event_types.h
new file mode 100644
index 0000000..af586e4
--- /dev/null
+++ b/base/event_types.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_EVENT_TYPES_H
+#define BASE_EVENT_TYPES_H
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(USE_X11)
+typedef union _XEvent XEvent;
+#elif defined(OS_MACOSX)
+#if defined(__OBJC__)
+@class NSEvent;
+#else  // __OBJC__
+class NSEvent;
+#endif // __OBJC__
+#endif
+
+namespace base {
+
+// Cross platform typedefs for native event types.
+#if defined(OS_WIN)
+typedef MSG NativeEvent;
+#elif defined(USE_X11)
+typedef XEvent* NativeEvent;
+#elif defined(OS_MACOSX)
+typedef NSEvent* NativeEvent;
+#else
+typedef void* NativeEvent;
+#endif
+
+} // namespace base
+
+#endif  // BASE_EVENT_TYPES_H
diff --git a/base/file_descriptor_posix.h b/base/file_descriptor_posix.h
new file mode 100644
index 0000000..abc0789
--- /dev/null
+++ b/base/file_descriptor_posix.h
@@ -0,0 +1,45 @@
+// 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_
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// We introduct a special structure for file descriptors in order that we are
+// able to use template specialisation to special-case their handling.
+//
+// WARNING: (Chromium only) There are subtleties to consider if serialising
+// these objects over IPC. See comments in ipc/ipc_message_utils.h
+// above the template specialisation for this structure.
+// -----------------------------------------------------------------------------
+struct FileDescriptor {
+  FileDescriptor()
+      : fd(-1),
+        auto_close(false) { }
+
+  FileDescriptor(int ifd, bool iauto_close)
+      : fd(ifd),
+        auto_close(iauto_close) { }
+
+  bool operator==(const FileDescriptor& other) const {
+    return (fd == other.fd && auto_close == other.auto_close);
+  }
+
+  // A comparison operator so that we can use these as keys in a std::map.
+  bool operator<(const FileDescriptor& other) const {
+    return other.fd < fd;
+  }
+
+  int fd;
+  // If true, this file descriptor should be closed after it has been used. For
+  // example an IPC system might interpret this flag as indicating that the
+  // file descriptor it has been given should be closed after use.
+  bool auto_close;
+};
+
+}  // namespace base
+
+#endif  // BASE_FILE_DESCRIPTOR_POSIX_H_
diff --git a/base/file_path.cc b/base/file_path.cc
new file mode 100644
index 0000000..094c699
--- /dev/null
+++ b/base/file_path.cc
@@ -0,0 +1,1238 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_path.h"
+
+#include <string.h>
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/pickle.h"
+
+// These includes are just for the *Hack functions, and should be removed
+// when those functions are removed.
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_cftyperef.h"
+#include "base/third_party/icu/icu_utf.h"
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#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 FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL(".");
+const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
+
+const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.');
+
+typedef FilePath::StringType StringType;
+
+namespace {
+
+const char* kCommonDoubleExtensionSuffixes[] = { "gz", "z", "bz2" };
+const char* kCommonDoubleExtensions[] = { "user.js" };
+
+// If this FilePath contains a drive letter specification, returns the
+// position of the last character of the drive letter specification,
+// otherwise returns npos.  This can only be true on Windows, when a pathname
+// begins with a letter followed by a colon.  On other platforms, this always
+// returns npos.
+StringType::size_type FindDriveLetter(const StringType& path) {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  // This is dependent on an ASCII-based character set, but that's a
+  // reasonable assumption.  iswalpha can be too inclusive here.
+  if (path.length() >= 2 && path[1] == L':' &&
+      ((path[0] >= L'A' && path[0] <= L'Z') ||
+       (path[0] >= L'a' && path[0] <= L'z'))) {
+    return 1;
+  }
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+  return StringType::npos;
+}
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+bool EqualDriveLetterCaseInsensitive(const StringType& a,
+                                     const StringType& b) {
+  size_t a_letter_pos = FindDriveLetter(a);
+  size_t b_letter_pos = FindDriveLetter(b);
+
+  if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos)
+    return a == b;
+
+  StringType a_letter(a.substr(0, a_letter_pos + 1));
+  StringType b_letter(b.substr(0, b_letter_pos + 1));
+  if (!StartsWith(a_letter, b_letter, false))
+    return false;
+
+  StringType a_rest(a.substr(a_letter_pos + 1));
+  StringType b_rest(b.substr(b_letter_pos + 1));
+  return a_rest == b_rest;
+}
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+
+bool IsPathAbsolute(const StringType& path) {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  StringType::size_type letter = FindDriveLetter(path);
+  if (letter != StringType::npos) {
+    // Look for a separator right after the drive specification.
+    return path.length() > letter + 1 &&
+        FilePath::IsSeparator(path[letter + 1]);
+  }
+  // Look for a pair of leading separators.
+  return path.length() > 1 &&
+      FilePath::IsSeparator(path[0]) && FilePath::IsSeparator(path[1]);
+#else  // FILE_PATH_USES_DRIVE_LETTERS
+  // Look for a separator in the first position.
+  return path.length() > 0 && FilePath::IsSeparator(path[0]);
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+}
+
+bool AreAllSeparators(const StringType& input) {
+  for (StringType::const_iterator it = input.begin();
+      it != input.end(); ++it) {
+    if (!FilePath::IsSeparator(*it))
+      return false;
+  }
+
+  return true;
+}
+
+// Find the position of the '.' that separates the extension from the rest
+// of the file name. The position is relative to BaseName(), not value().
+// This allows 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. Returns npos if it can't find an
+// extension.
+StringType::size_type ExtensionSeparatorPosition(const StringType& path) {
+  // Special case "." and ".."
+  if (path == FilePath::kCurrentDirectory || path == FilePath::kParentDirectory)
+    return StringType::npos;
+
+  const StringType::size_type last_dot =
+      path.rfind(FilePath::kExtensionSeparator);
+
+  // 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,
+                        arraysize(FilePath::kSeparators) - 1);
+
+  if (penultimate_dot == StringType::npos ||
+      (last_separator != StringType::npos &&
+       penultimate_dot < last_separator)) {
+    return last_dot;
+  }
+
+  for (size_t i = 0; i < arraysize(kCommonDoubleExtensions); ++i) {
+    StringType extension(path, penultimate_dot + 1);
+    if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensions[i]))
+      return penultimate_dot;
+  }
+
+  StringType extension(path, last_dot + 1);
+  for (size_t i = 0; i < arraysize(kCommonDoubleExtensionSuffixes); ++i) {
+    if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensionSuffixes[i])) {
+      if ((last_dot - penultimate_dot) <= 5U &&
+          (last_dot - penultimate_dot) > 1U) {
+        return penultimate_dot;
+      }
+    }
+  }
+
+  return last_dot;
+}
+
+// Returns true if path is "", ".", or "..".
+bool IsEmptyOrSpecialCase(const StringType& path) {
+  // Special cases "", ".", and ".."
+  if (path.empty() || path == FilePath::kCurrentDirectory ||
+      path == FilePath::kParentDirectory) {
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+FilePath::FilePath() {
+}
+
+FilePath::FilePath(const FilePath& that) : path_(that.path_) {
+}
+
+FilePath::FilePath(const StringType& path) : path_(path) {
+}
+
+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 < arraysize(kSeparators) - 1; ++i) {
+    if (character == kSeparators[i]) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void FilePath::GetComponents(std::vector<StringType>* components) const {
+  DCHECK(components);
+  if (!components)
+    return;
+  components->clear();
+  if (value().empty())
+    return;
+
+  std::vector<StringType> ret_val;
+  FilePath current = *this;
+  FilePath base;
+
+  // Capture path components.
+  while (current != current.DirName()) {
+    base = current.BaseName();
+    if (!AreAllSeparators(base.value()))
+      ret_val.push_back(base.value());
+    current = current.DirName();
+  }
+
+  // Capture root, if any.
+  base = current.BaseName();
+  if (!base.value().empty() && base.value() != kCurrentDirectory)
+    ret_val.push_back(current.BaseName().value());
+
+  // Capture drive letter, if any.
+  FilePath dir = current.DirName();
+  StringType::size_type letter = FindDriveLetter(dir.value());
+  if (letter != StringType::npos) {
+    ret_val.push_back(StringType(dir.value(), 0, letter + 1));
+  }
+
+  *components = std::vector<StringType>(ret_val.rbegin(), ret_val.rend());
+}
+
+bool FilePath::IsParent(const FilePath& child) const {
+  return AppendRelativePath(child, NULL);
+}
+
+bool FilePath::AppendRelativePath(const FilePath& child,
+                                  FilePath* path) const {
+  std::vector<StringType> parent_components;
+  std::vector<StringType> child_components;
+  GetComponents(&parent_components);
+  child.GetComponents(&child_components);
+
+  if (parent_components.empty() ||
+      parent_components.size() >= child_components.size())
+    return false;
+
+  std::vector<StringType>::const_iterator parent_comp =
+      parent_components.begin();
+  std::vector<StringType>::const_iterator child_comp =
+      child_components.begin();
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  // Windows can access case sensitive filesystems, so component
+  // comparisions must be case sensitive, but drive letters are
+  // never case sensitive.
+  if ((FindDriveLetter(*parent_comp) != StringType::npos) &&
+      (FindDriveLetter(*child_comp) != StringType::npos)) {
+    if (!StartsWith(*parent_comp, *child_comp, false))
+      return false;
+    ++parent_comp;
+    ++child_comp;
+  }
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+
+  while (parent_comp != parent_components.end()) {
+    if (*parent_comp != *child_comp)
+      return false;
+    ++parent_comp;
+    ++child_comp;
+  }
+
+  if (path != NULL) {
+    for (; child_comp != child_components.end(); ++child_comp) {
+      *path = path->Append(*child_comp);
+    }
+  }
+  return true;
+}
+
+// libgen's dirname and basename aren't guaranteed to be thread-safe and aren't
+// guaranteed to not modify their input strings, and in fact are implemented
+// differently in this regard on different platforms.  Don't use them, but
+// adhere to their behavior.
+FilePath FilePath::DirName() const {
+  FilePath new_path(path_);
+  new_path.StripTrailingSeparatorsInternal();
+
+  // The drive letter, if any, always needs to remain in the output.  If there
+  // is no drive letter, as will always be the case on platforms which do not
+  // support drive letters, letter will be npos, or -1, so the comparisons and
+  // resizes below using letter will still be valid.
+  StringType::size_type letter = FindDriveLetter(new_path.path_);
+
+  StringType::size_type last_separator =
+      new_path.path_.find_last_of(kSeparators, StringType::npos,
+                                  arraysize(kSeparators) - 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,
+                                  arraysize(kSeparators) - 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);
+}
+
+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::InsertBeforeExtension(const StringType& suffix) const {
+  if (suffix.empty())
+    return FilePath(path_);
+
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  StringType ext = Extension();
+  StringType ret = RemoveExtension().value();
+  ret.append(suffix);
+  ret.append(ext);
+  return FilePath(ret);
+}
+
+FilePath FilePath::InsertBeforeExtensionASCII(const base::StringPiece& suffix)
+    const {
+  DCHECK(IsStringASCII(suffix));
+#if defined(OS_WIN)
+  return InsertBeforeExtension(ASCIIToUTF16(suffix.as_string()));
+#elif defined(OS_POSIX)
+  return InsertBeforeExtension(suffix.as_string());
+#endif
+}
+
+FilePath FilePath::AddExtension(const StringType& extension) const {
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  // If the new extension is "" or ".", then just return the current FilePath.
+  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+    return *this;
+
+  StringType str = path_;
+  if (extension[0] != kExtensionSeparator &&
+      *(str.end() - 1) != kExtensionSeparator) {
+    str.append(1, kExtensionSeparator);
+  }
+  str.append(extension);
+  return FilePath(str);
+}
+
+FilePath FilePath::ReplaceExtension(const StringType& extension) const {
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  FilePath no_ext = RemoveExtension();
+  // If the new extension is "" or ".", then just remove the current extension.
+  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+    return no_ext;
+
+  StringType str = no_ext.value();
+  if (extension[0] != kExtensionSeparator)
+    str.append(1, kExtensionSeparator);
+  str.append(extension);
+  return FilePath(str);
+}
+
+bool FilePath::MatchesExtension(const StringType& extension) const {
+  DCHECK(extension.empty() || extension[0] == kExtensionSeparator);
+
+  StringType current_extension = Extension();
+
+  if (current_extension.length() != extension.length())
+    return false;
+
+  return FilePath::CompareEqualIgnoreCase(extension, current_extension);
+}
+
+FilePath FilePath::Append(const StringType& component) const {
+  DCHECK(!IsPathAbsolute(component));
+  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(component);
+  }
+
+  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 (component.length() > 0 && new_path.path_.length() > 0) {
+    // Don't append a separator if the path still ends with a trailing
+    // separator after stripping (indicating the root directory).
+    if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) {
+      // Don't append a separator if the path is just a drive letter.
+      if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) {
+        new_path.path_.append(1, kSeparators[0]);
+      }
+    }
+  }
+
+  new_path.path_.append(component);
+  return new_path;
+}
+
+FilePath FilePath::Append(const FilePath& component) const {
+  return Append(component.value());
+}
+
+FilePath FilePath::AppendASCII(const base::StringPiece& component) const {
+  DCHECK(IsStringASCII(component));
+#if defined(OS_WIN)
+  return Append(ASCIIToUTF16(component.as_string()));
+#elif defined(OS_POSIX)
+  return Append(component.as_string());
+#endif
+}
+
+bool FilePath::IsAbsolute() const {
+  return IsPathAbsolute(path_);
+}
+
+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;
+    if (component == kParentDirectory)
+      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(base::SysNativeMBToWide(path_));
+}
+
+std::string FilePath::MaybeAsASCII() const {
+  if (IsStringASCII(path_))
+    return path_;
+  return "";
+}
+
+std::string FilePath::AsUTF8Unsafe() const {
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+  return value();
+#else
+  return WideToUTF8(base::SysNativeMBToWide(value()));
+#endif
+}
+
+// The *Hack functions are temporary while we fix the remainder of the code.
+// Remember to remove the #includes at the top when you remove these.
+
+// static
+FilePath FilePath::FromWStringHack(const std::wstring& wstring) {
+  return FilePath(base::SysWideToNativeMB(wstring));
+}
+
+// static
+FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) {
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+  return FilePath(utf8);
+#else
+  return FilePath(base::SysWideToNativeMB(UTF8ToWide(utf8)));
+#endif
+}
+
+#elif defined(OS_WIN)
+string16 FilePath::LossyDisplayName() const {
+  return path_;
+}
+
+std::string FilePath::MaybeAsASCII() const {
+  if (IsStringASCII(path_))
+    return WideToASCII(path_);
+  return "";
+}
+
+std::string FilePath::AsUTF8Unsafe() const {
+  return WideToUTF8(value());
+}
+
+// static
+FilePath FilePath::FromWStringHack(const std::wstring& wstring) {
+  return FilePath(wstring);
+}
+
+// static
+FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) {
+  return FilePath(UTF8ToWide(utf8));
+}
+#endif
+
+void FilePath::WriteToPickle(Pickle* pickle) {
+#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
+
+  return true;
+}
+
+#if defined(OS_WIN)
+// Windows specific implementation of file string comparisons
+
+int FilePath::CompareIgnoreCase(const StringType& string1,
+                                const StringType& string2) {
+  // Perform character-wise upper case comparison rather than using the
+  // fully Unicode-aware CompareString(). For details see:
+  // http://blogs.msdn.com/michkap/archive/2005/10/17/481600.aspx
+  StringType::const_iterator i1 = string1.begin();
+  StringType::const_iterator i2 = string2.begin();
+  StringType::const_iterator string1end = string1.end();
+  StringType::const_iterator string2end = string2.end();
+  for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) {
+    wchar_t c1 = (wchar_t)LOWORD(::CharUpperW((LPWSTR)MAKELONG(*i1, 0)));
+    wchar_t c2 = (wchar_t)LOWORD(::CharUpperW((LPWSTR)MAKELONG(*i2, 0)));
+    if (c1 < c2)
+      return -1;
+    if (c1 > c2)
+      return 1;
+  }
+  if (i1 != string1end)
+    return 1;
+  if (i2 != string2end)
+    return -1;
+  return 0;
+}
+
+#elif defined(OS_MACOSX)
+// Mac OS X specific implementation of file string comparisons
+
+// cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
+//
+// "When using CreateTextEncoding to create a text encoding, you should set
+// the TextEncodingBase to kTextEncodingUnicodeV2_0, set the
+// TextEncodingVariant to kUnicodeCanonicalDecompVariant, and set the
+// TextEncodingFormat to kUnicode16BitFormat. Using these values ensures that
+// the Unicode will be in the same form as on an HFS Plus volume, even as the
+// Unicode standard evolves."
+//
+// Another technical article for X 10.4 updates this: one should use
+// the new (unambiguous) kUnicodeHFSPlusDecompVariant.
+// cf. http://developer.apple.com/mac/library/releasenotes/TextFonts/RN-TEC/index.html
+//
+// This implementation uses CFStringGetFileSystemRepresentation() to get the
+// decomposed form, and an adapted version of the FastUnicodeCompare as
+// described in the tech note to compare the strings.
+
+// Character conversion table for FastUnicodeCompare()
+//
+// The lower case table consists of a 256-entry high-byte table followed by
+// some number of 256-entry subtables. The high-byte table contains either an
+// offset to the subtable for characters with that high byte or zero, which
+// means that there are no case mappings or ignored characters in that block.
+// Ignored characters are mapped to zero.
+//
+// cf. downloadable file linked in
+// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
+
+namespace {
+
+const UInt16 lower_case_table[] = {
+  // High-byte indices ( == 0 iff no case mapping and no ignorables )
+
+  /* 0 */ 0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 1 */ 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 2 */ 0x0700, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 3 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 4 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 5 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 6 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 7 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 9 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* E */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* F */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0900, 0x0A00,
+
+  // Table 1 (for high byte 0x00)
+
+  /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+          0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+  /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+          0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+  /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+          0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+  /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+          0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+  /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+          0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+  /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+          0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+  /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+          0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+  /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+          0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+  /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+          0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+  /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+          0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+  /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+          0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+  /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+          0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+  /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7,
+          0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+  /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+          0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
+  /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+          0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+  /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+          0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+
+  // Table 2 (for high byte 0x01)
+
+  /* 0 */ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107,
+          0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F,
+  /* 1 */ 0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117,
+          0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F,
+  /* 2 */ 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127,
+          0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F,
+  /* 3 */ 0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137,
+          0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140,
+  /* 4 */ 0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147,
+          0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F,
+  /* 5 */ 0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157,
+          0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F,
+  /* 6 */ 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167,
+          0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F,
+  /* 7 */ 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177,
+          0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F,
+  /* 8 */ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
+          0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
+  /* 9 */ 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
+          0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
+  /* A */ 0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8,
+          0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF,
+  /* B */ 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292,
+          0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
+  /* C */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9,
+          0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF,
+  /* D */ 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7,
+          0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF,
+  /* E */ 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7,
+          0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF,
+  /* F */ 0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7,
+          0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF,
+
+  // Table 3 (for high byte 0x03)
+
+  /* 0 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
+          0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
+  /* 1 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
+          0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
+  /* 2 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
+          0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
+  /* 3 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
+          0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
+  /* 4 */ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347,
+          0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
+  /* 5 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
+          0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
+  /* 6 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
+          0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
+  /* 7 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377,
+          0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
+  /* 8 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387,
+          0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,
+  /* 9 */ 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+          0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+  /* A */ 0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+          0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+  /* B */ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+          0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+  /* C */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+          0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,
+  /* D */ 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,
+          0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
+  /* E */ 0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7,
+          0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
+  /* F */ 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7,
+          0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
+
+  // Table 4 (for high byte 0x04)
+
+  /* 0 */ 0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407,
+          0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F,
+  /* 1 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+          0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+  /* 2 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+          0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+  /* 3 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+          0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+  /* 4 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+          0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+  /* 5 */ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+          0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,
+  /* 6 */ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467,
+          0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,
+  /* 7 */ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477,
+          0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,
+  /* 8 */ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
+          0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
+  /* 9 */ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497,
+          0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,
+  /* A */ 0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7,
+          0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,
+  /* B */ 0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7,
+          0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,
+  /* C */ 0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8,
+          0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
+  /* D */ 0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7,
+          0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF,
+  /* E */ 0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7,
+          0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF,
+  /* F */ 0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7,
+          0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
+
+  // Table 5 (for high byte 0x05)
+
+  /* 0 */ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507,
+          0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,
+  /* 1 */ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517,
+          0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,
+  /* 2 */ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527,
+          0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,
+  /* 3 */ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+          0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+  /* 4 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+          0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+  /* 5 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557,
+          0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,
+  /* 6 */ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+          0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+  /* 7 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+          0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+  /* 8 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587,
+          0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,
+  /* 9 */ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597,
+          0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,
+  /* A */ 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7,
+          0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,
+  /* B */ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+          0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+  /* C */ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7,
+          0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF,
+  /* D */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+          0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+  /* E */ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+          0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF,
+  /* F */ 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7,
+          0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF,
+
+  // Table 6 (for high byte 0x10)
+
+  /* 0 */ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
+          0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
+  /* 1 */ 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017,
+          0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
+  /* 2 */ 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027,
+          0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F,
+  /* 3 */ 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037,
+          0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F,
+  /* 4 */ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047,
+          0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F,
+  /* 5 */ 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057,
+          0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F,
+  /* 6 */ 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067,
+          0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
+  /* 7 */ 0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077,
+          0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F,
+  /* 8 */ 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087,
+          0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F,
+  /* 9 */ 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097,
+          0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F,
+  /* A */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
+          0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+  /* B */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
+          0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+  /* C */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7,
+          0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF,
+  /* D */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
+          0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+  /* E */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
+          0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+  /* F */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7,
+          0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF,
+
+  // Table 7 (for high byte 0x20)
+
+  /* 0 */ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007,
+          0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 1 */ 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017,
+          0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
+  /* 2 */ 0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027,
+          0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F,
+  /* 3 */ 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037,
+          0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F,
+  /* 4 */ 0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047,
+          0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
+  /* 5 */ 0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057,
+          0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F,
+  /* 6 */ 0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067,
+          0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 7 */ 0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077,
+          0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F,
+  /* 8 */ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087,
+          0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F,
+  /* 9 */ 0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097,
+          0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F,
+  /* A */ 0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7,
+          0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF,
+  /* B */ 0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7,
+          0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF,
+  /* C */ 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7,
+          0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF,
+  /* D */ 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7,
+          0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF,
+  /* E */ 0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7,
+          0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF,
+  /* F */ 0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7,
+          0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF,
+
+  // Table 8 (for high byte 0x21)
+
+  /* 0 */ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107,
+          0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F,
+  /* 1 */ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117,
+          0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F,
+  /* 2 */ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127,
+          0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F,
+  /* 3 */ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137,
+          0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F,
+  /* 4 */ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147,
+          0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,
+  /* 5 */ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157,
+          0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
+  /* 6 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+          0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+  /* 7 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+          0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+  /* 8 */ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187,
+          0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F,
+  /* 9 */ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197,
+          0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F,
+  /* A */ 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7,
+          0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF,
+  /* B */ 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7,
+          0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF,
+  /* C */ 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7,
+          0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF,
+  /* D */ 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7,
+          0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF,
+  /* E */ 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7,
+          0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF,
+  /* F */ 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7,
+          0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF,
+
+  // Table 9 (for high byte 0xFE)
+
+  /* 0 */ 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07,
+          0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F,
+  /* 1 */ 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17,
+          0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F,
+  /* 2 */ 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27,
+          0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F,
+  /* 3 */ 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37,
+          0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F,
+  /* 4 */ 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47,
+          0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
+  /* 5 */ 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57,
+          0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F,
+  /* 6 */ 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67,
+          0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F,
+  /* 7 */ 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77,
+          0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F,
+  /* 8 */ 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87,
+          0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F,
+  /* 9 */ 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97,
+          0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F,
+  /* A */ 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7,
+          0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF,
+  /* B */ 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7,
+          0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF,
+  /* C */ 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7,
+          0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF,
+  /* D */ 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7,
+          0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF,
+  /* E */ 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7,
+          0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF,
+  /* F */ 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7,
+          0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000,
+
+  // Table 10 (for high byte 0xFF)
+
+  /* 0 */ 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07,
+          0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
+  /* 1 */ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17,
+          0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
+  /* 2 */ 0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
+          0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+  /* 3 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
+          0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
+  /* 4 */ 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
+          0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+  /* 5 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
+          0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,
+  /* 6 */ 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67,
+          0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
+  /* 7 */ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77,
+          0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
+  /* 8 */ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87,
+          0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
+  /* 9 */ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97,
+          0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
+  /* A */ 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7,
+          0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF,
+  /* B */ 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7,
+          0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF,
+  /* C */ 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7,
+          0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF,
+  /* D */ 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7,
+          0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF,
+  /* E */ 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7,
+          0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF,
+  /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7,
+          0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
+};
+
+// Returns the next non-ignorable codepoint within string starting from the
+// position indicated by index, or zero if there are no more.
+// The passed-in index is automatically advanced as the characters in the input
+// HFS-decomposed UTF-8 strings are read.
+inline int HFSReadNextNonIgnorableCodepoint(const char* string,
+                                            int length,
+                                            int* index) {
+  int codepoint = 0;
+  while (*index < length && codepoint == 0) {
+    // CBU8_NEXT returns a value < 0 in error cases. For purposes of string
+    // comparison, we just use that value and flag it with DCHECK.
+    CBU8_NEXT(string, *index, length, codepoint);
+    DCHECK_GT(codepoint, 0);
+    if (codepoint > 0) {
+      // Check if there is a subtable for this upper byte.
+      int lookup_offset = lower_case_table[codepoint >> 8];
+      if (lookup_offset != 0)
+        codepoint = lower_case_table[lookup_offset + (codepoint & 0x00FF)];
+      // Note: codepoint1 may be again 0 at this point if the character was
+      // an ignorable.
+    }
+  }
+  return codepoint;
+}
+
+}  // anonymous namespace
+
+// Special UTF-8 version of FastUnicodeCompare. Cf:
+// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
+// The input strings must be in the special HFS decomposed form.
+int FilePath::HFSFastUnicodeCompare(const StringType& string1,
+                                    const StringType& string2) {
+  int length1 = string1.length();
+  int length2 = string2.length();
+  int index1 = 0;
+  int index2 = 0;
+
+  for (;;) {
+    int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.c_str(),
+                                                      length1,
+                                                      &index1);
+    int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.c_str(),
+                                                      length2,
+                                                      &index2);
+    if (codepoint1 != codepoint2)
+      return (codepoint1 < codepoint2) ? -1 : 1;
+    if (codepoint1 == 0) {
+      DCHECK_EQ(index1, length1);
+      DCHECK_EQ(index2, length2);
+      return 0;
+    }
+  }
+}
+
+StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
+  base::mac::ScopedCFTypeRef<CFStringRef> cfstring(
+      CFStringCreateWithBytesNoCopy(
+          NULL,
+          reinterpret_cast<const UInt8*>(string.c_str()),
+          string.length(),
+          kCFStringEncodingUTF8,
+          false,
+          kCFAllocatorNull));
+  // Query the maximum length needed to store the result. In most cases this
+  // will overestimate the required space. The return value also already
+  // includes the space needed for a terminating 0.
+  CFIndex length = CFStringGetMaximumSizeOfFileSystemRepresentation(cfstring);
+  DCHECK_GT(length, 0);  // should be at least 1 for the 0-terminator.
+  // Reserve enough space for CFStringGetFileSystemRepresentation to write into.
+  // Also set the length to the maximum so that we can shrink it later.
+  // (Increasing rather than decreasing it would clobber the string contents!)
+  StringType result;
+  result.reserve(length);
+  result.resize(length - 1);
+  Boolean success = CFStringGetFileSystemRepresentation(cfstring,
+                                                        &result[0],
+                                                        length);
+  if (success) {
+    // Reduce result.length() to actual string length.
+    result.resize(strlen(result.c_str()));
+  } else {
+    // An error occurred -> clear result.
+    result.clear();
+  }
+  return result;
+}
+
+int FilePath::CompareIgnoreCase(const StringType& string1,
+                                const StringType& string2) {
+  // Quick checks for empty strings - these speed things up a bit and make the
+  // following code cleaner.
+  if (string1.empty())
+    return string2.empty() ? 0 : -1;
+  if (string2.empty())
+    return 1;
+
+  StringType hfs1 = GetHFSDecomposedForm(string1);
+  StringType hfs2 = GetHFSDecomposedForm(string2);
+
+  // GetHFSDecomposedForm() returns an empty string in an error case.
+  if (hfs1.empty() || hfs2.empty()) {
+    NOTREACHED();
+    base::mac::ScopedCFTypeRef<CFStringRef> cfstring1(
+        CFStringCreateWithBytesNoCopy(
+            NULL,
+            reinterpret_cast<const UInt8*>(string1.c_str()),
+            string1.length(),
+            kCFStringEncodingUTF8,
+            false,
+            kCFAllocatorNull));
+    base::mac::ScopedCFTypeRef<CFStringRef> cfstring2(
+        CFStringCreateWithBytesNoCopy(
+            NULL,
+            reinterpret_cast<const UInt8*>(string2.c_str()),
+            string2.length(),
+            kCFStringEncodingUTF8,
+            false,
+            kCFAllocatorNull));
+    return CFStringCompare(cfstring1,
+                           cfstring2,
+                           kCFCompareCaseInsensitive);
+  }
+
+  return HFSFastUnicodeCompare(hfs1, hfs2);
+}
+
+#else  // << WIN. MACOSX | other (POSIX) >>
+
+// Generic (POSIX) implementation of file string comparison.
+// TODO(rolandsteiner) check if this is sufficient/correct.
+int FilePath::CompareIgnoreCase(const StringType& string1,
+                                const StringType& string2) {
+  int comparison = strcasecmp(string1.c_str(), string2.c_str());
+  if (comparison < 0)
+    return -1;
+  if (comparison > 0)
+    return 1;
+  return 0;
+}
+
+#endif  // OS versions of CompareIgnoreCase()
+
+
+void FilePath::StripTrailingSeparatorsInternal() {
+  // If there is no drive letter, start will be 1, which will prevent stripping
+  // the leading separator if there is only one separator.  If there is a drive
+  // letter, start will be set appropriately to prevent stripping the first
+  // separator following the drive letter, if a separator immediately follows
+  // the drive letter.
+  StringType::size_type start = FindDriveLetter(path_) + 2;
+
+  StringType::size_type last_stripped = StringType::npos;
+  for (StringType::size_type pos = path_.length();
+       pos > start && IsSeparator(path_[pos - 1]);
+       --pos) {
+    // If the string only has two separators and they're at the beginning,
+    // don't strip them, unless the string began with more than two separators.
+    if (pos != start + 1 || last_stripped == start + 2 ||
+        !IsSeparator(path_[start - 1])) {
+      path_.resize(pos - 1);
+      last_stripped = pos;
+    }
+  }
+}
+
+FilePath FilePath::NormalizePathSeparators() const {
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+  StringType copy = path_;
+  for (size_t i = 1; i < arraysize(kSeparators); ++i) {
+    std::replace(copy.begin(), copy.end(), kSeparators[i], kSeparators[0]);
+  }
+  return FilePath(copy);
+#else
+  return *this;
+#endif
+}
+
+void PrintTo(const FilePath& path, std::ostream* out) {
+  *out << path.value();
+}
diff --git a/base/file_path.h b/base/file_path.h
new file mode 100644
index 0000000..09e8269
--- /dev/null
+++ b/base/file_path.h
@@ -0,0 +1,436 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// 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.
+//
+// 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.266 ("Pathname")
+//    and 4.12 ("Pathname Resolution"), available at:
+//    http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_266
+//    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_FILE_PATH_H_
+#define BASE_FILE_PATH_H_
+
+#include <stddef.h>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/hash_tables.h"
+#include "base/string16.h"
+#include "base/string_piece.h"  // For implicit conversions.
+#include "build/build_config.h"
+
+// Windows-style drive letter support and pathname separator characters can be
+// enabled and disabled independently, to aid testing.  These #defines are
+// here so that the same setting can be used in both the implementation and
+// in the unit test.
+#if defined(OS_WIN)
+#define FILE_PATH_USES_DRIVE_LETTERS
+#define FILE_PATH_USES_WIN_SEPARATORS
+#endif  // OS_WIN
+
+class Pickle;
+class PickleIterator;
+
+// An abstraction to isolate users from the differences between native
+// pathnames on different platforms.
+class BASE_EXPORT FilePath {
+ public:
+#if defined(OS_POSIX)
+  // On most platforms, native pathnames are char arrays, and the encoding
+  // may or may not be specified.  On Mac OS X, native pathnames are encoded
+  // in UTF-8.
+  typedef std::string StringType;
+#elif defined(OS_WIN)
+  // On Windows, for Unicode-aware applications, native pathnames are wchar_t
+  // arrays encoded in UTF-16.
+  typedef std::wstring StringType;
+#endif  // OS_WIN
+
+  typedef StringType::value_type CharType;
+
+  // Null-terminated array of separators used to separate components in
+  // hierarchical paths.  Each character in this array is a valid separator,
+  // but kSeparators[0] is treated as the canonical separator and will be used
+  // when composing pathnames.
+  static const CharType kSeparators[];
+
+  // A special path component meaning "this directory."
+  static const CharType kCurrentDirectory[];
+
+  // A special path component meaning "the parent directory."
+  static const CharType kParentDirectory[];
+
+  // The character used to identify a file extension.
+  static const CharType kExtensionSeparator;
+
+  FilePath();
+  FilePath(const FilePath& that);
+  explicit FilePath(const StringType& path);
+  ~FilePath();
+  FilePath& operator=(const FilePath& that);
+
+  bool operator==(const FilePath& that) const;
+
+  bool operator!=(const FilePath& that) const;
+
+  // Required for some STL containers and operations
+  bool operator<(const FilePath& that) const {
+    return path_ < that.path_;
+  }
+
+  const StringType& value() const { return path_; }
+
+  bool empty() const { return path_.empty(); }
+
+  void clear() { path_.clear(); }
+
+  // Returns true if |character| is in kSeparators.
+  static bool IsSeparator(CharType character);
+
+  // Returns a vector of all of the components of the provided path. It is
+  // equivalent to calling DirName().value() on the path's root component,
+  // and BaseName().value() on each child component.
+  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.
+  // 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;
+
+  // 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;
+
+  // Inserts |suffix| after the file name portion of |path| but before the
+  // extension.  Returns "" if BaseName() == "." or "..".
+  // Examples:
+  // path == "C:\pics\jojo.jpg" suffix == " (1)", returns "C:\pics\jojo (1).jpg"
+  // path == "jojo.jpg"         suffix == " (1)", returns "jojo (1).jpg"
+  // path == "C:\pics\jojo"     suffix == " (1)", returns "C:\pics\jojo (1)"
+  // path == "C:\pics.old\jojo" suffix == " (1)", returns "C:\pics.old\jojo (1)"
+  FilePath InsertBeforeExtension(
+      const StringType& suffix) const WARN_UNUSED_RESULT;
+  FilePath InsertBeforeExtensionASCII(
+      const base::StringPiece& suffix) const WARN_UNUSED_RESULT;
+
+  // Adds |extension| to |file_name|. Returns the current FilePath if
+  // |extension| is empty. Returns "" if BaseName() == "." or "..".
+  FilePath AddExtension(
+      const StringType& extension) const WARN_UNUSED_RESULT;
+
+  // Replaces the extension of |file_name| with |extension|.  If |file_name|
+  // does not have an extension, then |extension| is added.  If |extension| is
+  // empty, then the extension is removed from |file_name|.
+  // Returns "" if BaseName() == "." or "..".
+  FilePath ReplaceExtension(
+      const StringType& extension) const WARN_UNUSED_RESULT;
+
+  // Returns true if the file path matches the specified extension. The test is
+  // case insensitive. Don't forget the leading period if appropriate.
+  bool MatchesExtension(const StringType& extension) const;
+
+  // Returns a FilePath by appending a separator and the supplied path
+  // component to this object's path.  Append takes care to avoid adding
+  // excessive separators if this object's path already ends with a separator.
+  // If this object's path is kCurrentDirectory, a new FilePath corresponding
+  // only to |component| is returned.  |component| must be a relative path;
+  // it is an error to pass an absolute path.
+  FilePath Append(const StringType& component) const WARN_UNUSED_RESULT;
+  FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT;
+
+  // Although Windows StringType is std::wstring, since the encoding it uses for
+  // paths is well defined, it can handle ASCII path components as well.
+  // Mac uses UTF8, and since ASCII is a subset of that, it works there as well.
+  // On Linux, although it can use any 8-bit encoding for paths, we assume that
+  // ASCII is a valid subset, regardless of the encoding, since many operating
+  // system paths will always be ASCII.
+  FilePath AppendASCII(const base::StringPiece& component)
+      const WARN_UNUSED_RESULT;
+
+  // Returns true if this FilePath contains an absolute path.  On Windows, an
+  // absolute path begins with either a drive letter specification followed by
+  // a separator character, or with two separator characters.  On POSIX
+  // platforms, an absolute path begins with a separator character.
+  bool IsAbsolute() const;
+
+  // Returns 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 any attempt to reference a parent
+  // directory (i.e. 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;
+
+  // Older Chromium code assumes that paths are always wstrings.
+  // This function converts wstrings to FilePaths, and is
+  // useful to smooth porting that old code to the FilePath API.
+  // It has "Hack" its name so people feel bad about using it.
+  // http://code.google.com/p/chromium/issues/detail?id=24672
+  //
+  // If you are trying to be a good citizen and remove these, ask yourself:
+  // - Am I interacting with other Chrome code that deals with files?  Then
+  //   try to convert the API into using FilePath.
+  // - Am I interacting with OS-native calls?  Then use value() to get at an
+  //   OS-native string format.
+  // - Am I using well-known file names, like "config.ini"?  Then use the
+  //   ASCII functions (we require paths to always be supersets of ASCII).
+  // - Am I displaying a string to the user in some UI?  Then use the
+  //   LossyDisplayName() function, but keep in mind that you can't
+  //   ever use the result of that again as a path.
+  static FilePath FromWStringHack(const std::wstring& wstring);
+
+  // Returns a FilePath object from a path name in UTF-8. This function
+  // should only be used for cases where you are sure that the input
+  // string is UTF-8.
+  //
+  // Like AsUTF8Unsafe(), this function is unsafe. This function
+  // internally calls SysWideToNativeMB() on POSIX systems other than Mac
+  // and Chrome OS, to mitigate the encoding issue. See the comment at
+  // AsUTF8Unsafe() for details.
+  static FilePath FromUTF8Unsafe(const std::string& utf8);
+
+  void WriteToPickle(Pickle* pickle);
+  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;
+
+  // Compare two strings in the same way the file system does.
+  // Note that these always ignore case, even on file systems that are case-
+  // sensitive. If case-sensitive comparison is ever needed, add corresponding
+  // methods here.
+  // The methods are written as a static method so that they can also be used
+  // on parts of a file path, e.g., just the extension.
+  // CompareIgnoreCase() returns -1, 0 or 1 for less-than, equal-to and
+  // greater-than respectively.
+  static int CompareIgnoreCase(const StringType& string1,
+                               const StringType& string2);
+  static bool CompareEqualIgnoreCase(const StringType& string1,
+                                     const StringType& string2) {
+    return CompareIgnoreCase(string1, string2) == 0;
+  }
+  static bool CompareLessIgnoreCase(const StringType& string1,
+                                    const StringType& string2) {
+    return CompareIgnoreCase(string1, string2) < 0;
+  }
+
+#if defined(OS_MACOSX)
+  // Returns the string in the special canonical decomposed form as defined for
+  // HFS, which is close to, but not quite, decomposition form D. See
+  // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
+  // for further comments.
+  // Returns the epmty string if the conversion failed.
+  static StringType GetHFSDecomposedForm(const FilePath::StringType& string);
+
+  // Special UTF-8 version of FastUnicodeCompare. Cf:
+  // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
+  // IMPORTANT: The input strings must be in the special HFS decomposed form!
+  // (cf. above GetHFSDecomposedForm method)
+  static int HFSFastUnicodeCompare(const StringType& string1,
+                                   const StringType& string2);
+#endif
+
+ 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.
+BASE_EXPORT extern void PrintTo(const FilePath& path, std::ostream* out);
+
+// 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"
+#define PRFilePathLiteral "%s"
+#elif defined(OS_WIN)
+#define FILE_PATH_LITERAL(x) L ## x
+#define PRFilePath "ls"
+#define PRFilePathLiteral L"%ls"
+#endif  // OS_WIN
+
+// Provide a hash function so that hash_sets and maps can contain FilePath
+// objects.
+namespace BASE_HASH_NAMESPACE {
+#if defined(COMPILER_GCC)
+
+template<>
+struct hash<FilePath> {
+  size_t operator()(const FilePath& f) const {
+    return hash<FilePath::StringType>()(f.value());
+  }
+};
+
+#elif defined(COMPILER_MSVC)
+
+inline size_t hash_value(const FilePath& f) {
+  return hash_value(f.value());
+}
+
+#endif  // COMPILER
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#endif  // BASE_FILE_PATH_H_
diff --git a/base/file_path_unittest.cc b/base/file_path_unittest.cc
new file mode 100644
index 0000000..ab25543
--- /dev/null
+++ b/base/file_path_unittest.cc
@@ -0,0 +1,1161 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// This macro helps avoid wrapped lines in the test structs.
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+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
+class FilePathTest : public PlatformTest {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    PlatformTest::SetUp();
+  }
+  virtual void TearDown() OVERRIDE {
+    PlatformTest::TearDown();
+  }
+};
+
+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());
+
+  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());
+}
+
+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("/foo.tar.gz"),            FPL(".tar.gz") },
+    { FPL("/foo.tar.Z"),             FPL(".tar.Z") },
+    { FPL("/foo.tar.bz2"),           FPL(".tar.bz2") },
+    { FPL("/subversion-1.6.12.zip"), FPL(".zip") },
+    { FPL("/foo.1234.gz"),           FPL(".1234.gz") },
+    { FPL("/foo.12345.gz"),          FPL(".gz") },
+    { FPL("/foo..gz"),               FPL(".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("."),                      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.user.js"),      FPL(".user.js") },
+    { FPL("foo.user.js"),            FPL(".user.js") },
+    { FPL("/foo.1234.luser.js"),     FPL(".js") },
+    { FPL("/user.js"),               FPL(".js") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].input);
+    FilePath::StringType extension = path.Extension();
+    EXPECT_STREQ(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") },
+    { FPL("foo.tar.gz"),          FPL("foo") },
+#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();
+    EXPECT_EQ(cases[i].expected, removed.value()) << "i: " << i <<
+        ", 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("a.."),      false },
+    { FPL("..a"),      false },
+    { FPL("../"),      true },
+    { FPL("/.."),      true },
+    { FPL("/../"),     true },
+    { FPL("/a../"),    false },
+    { FPL("/..a/"),    false },
+    { FPL("//.."),     true },
+    { FPL("..//"),     true },
+    { FPL("//..//"),   true },
+    { FPL("a//..//c"), true },
+    { FPL("../b/c"),   true },
+    { FPL("/../b/c"),  true },
+    { FPL("a/b/.."),   true },
+    { FPL("a/b/../"),  true },
+    { FPL("a/../c"),   true },
+    { FPL("a/b/c"),    false },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    bool observed = input.ReferencesParent();
+    EXPECT_EQ(cases[i].expected, observed) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, FromUTF8Unsafe_And_AsUTF8Unsafe) {
+  const struct UTF8TestData cases[] = {
+    { FPL("foo.txt"), "foo.txt" },
+    // "aeo" with accents. Use http://0xcc.net/jsescape/ to decode them.
+    { FPL("\u00E0\u00E8\u00F2.txt"), "\xC3\xA0\xC3\xA8\xC3\xB2.txt" },
+    // Full-width "ABC".
+    { FPL("\uFF21\uFF22\uFF23.txt"),
+      "\xEF\xBC\xA1\xEF\xBC\xA2\xEF\xBC\xA3.txt" },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    // Test FromUTF8Unsafe() works.
+    FilePath from_utf8 = FilePath::FromUTF8Unsafe(cases[i].utf8);
+    EXPECT_EQ(cases[i].native, from_utf8.value())
+        << "i: " << i << ", input: " << cases[i].native;
+    // Test AsUTF8Unsafe() works.
+    FilePath from_native = FilePath(cases[i].native);
+    EXPECT_EQ(cases[i].utf8, from_native.AsUTF8Unsafe())
+        << "i: " << i << ", input: " << cases[i].native;
+    // Test the two file paths are identical.
+    EXPECT_EQ(from_utf8.value(), from_native.value());
+  }
+}
+
+#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
diff --git a/base/file_util.cc b/base/file_util.cc
new file mode 100644
index 0000000..effee8a
--- /dev/null
+++ b/base/file_util.cc
@@ -0,0 +1,397 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_util.h"
+
+#if defined(OS_WIN)
+#include <io.h>
+#endif
+#include <stdio.h>
+
+#include <fstream>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+
+namespace {
+
+const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
+
+// 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
+
+namespace file_util {
+
+bool g_bug108724_debug = false;
+
+bool EndsWithSeparator(const FilePath& path) {
+  FilePath::StringType value = path.value();
+  if (value.empty())
+    return false;
+
+  return FilePath::IsSeparator(value[value.size() - 1]);
+}
+
+bool EnsureEndsWithSeparator(FilePath* path) {
+  if (!DirectoryExists(*path))
+    return false;
+
+  if (EndsWithSeparator(*path))
+    return true;
+
+  FilePath::StringType& path_str =
+      const_cast<FilePath::StringType&>(path->value());
+  path_str.append(&FilePath::kSeparators[0], 1);
+
+  return true;
+}
+
+void InsertBeforeExtension(FilePath* path, const FilePath::StringType& suffix) {
+  FilePath::StringType& value =
+      const_cast<FilePath::StringType&>(path->value());
+
+  const FilePath::StringType::size_type last_dot =
+      value.rfind(kExtensionSeparator);
+  const FilePath::StringType::size_type last_separator =
+      value.find_last_of(FilePath::StringType(FilePath::kSeparators));
+
+  if (last_dot == FilePath::StringType::npos ||
+      (last_separator != std::wstring::npos && last_dot < last_separator)) {
+    // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo".
+    // We should just append the suffix to the entire path.
+    value.append(suffix);
+    return;
+  }
+
+  value.insert(last_dot, suffix);
+}
+
+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, 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;
+}
+
+bool ReadFileToString(const FilePath& path, std::string* contents) {
+  FILE* file = OpenFile(path, "rb");
+  if (!file) {
+    return false;
+  }
+
+  char buf[1 << 16];
+  size_t len;
+  while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
+    if (contents)
+      contents->append(buf, len);
+  }
+  CloseFile(file);
+
+  return true;
+}
+
+bool IsDirectoryEmpty(const FilePath& dir_path) {
+  FileEnumerator files(dir_path, false,
+      FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
+  if (files.Next().value().empty())
+    return true;
+  return false;
+}
+
+FILE* CreateAndOpenTemporaryFile(FilePath* path) {
+  FilePath directory;
+  if (!GetTempDir(&directory))
+    return NULL;
+
+  return CreateAndOpenTemporaryFileInDir(directory, path);
+}
+
+bool GetFileSize(const FilePath& file_path, int64* file_size) {
+  base::PlatformFileInfo info;
+  if (!GetFileInfo(file_path, &info))
+    return false;
+  *file_size = info.size;
+  return true;
+}
+
+bool IsDot(const FilePath& path) {
+  return FILE_PATH_LITERAL(".") == path.BaseName().value();
+}
+
+bool IsDotDot(const FilePath& path) {
+  return FILE_PATH_LITERAL("..") == path.BaseName().value();
+}
+
+bool TouchFile(const FilePath& path,
+               const base::Time& last_accessed,
+               const base::Time& last_modified) {
+  int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
+
+#if defined(OS_WIN)
+  // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
+  if (DirectoryExists(path))
+    flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
+#endif  // OS_WIN
+
+  const base::PlatformFile file =
+      base::CreatePlatformFile(path, flags, NULL, NULL);
+  if (file != base::kInvalidPlatformFileValue) {
+    bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
+    base::ClosePlatformFile(file);
+    return result;
+  }
+
+  return false;
+}
+
+bool SetLastModifiedTime(const FilePath& path,
+                         const base::Time& last_modified) {
+  return TouchFile(path, last_modified, last_modified);
+}
+
+bool CloseFile(FILE* file) {
+  if (file == NULL)
+    return true;
+  return fclose(file) == 0;
+}
+
+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;
+}
+
+bool ContainsPath(const FilePath &parent, const FilePath& child) {
+  FilePath abs_parent = FilePath(parent);
+  FilePath abs_child = FilePath(child);
+
+  if (!file_util::AbsolutePath(&abs_parent) ||
+      !file_util::AbsolutePath(&abs_child))
+    return false;
+
+#if defined(OS_WIN)
+  // file_util::AbsolutePath() does not flatten case on Windows, so we must do
+  // a case-insensitive compare.
+  if (!StartsWith(abs_child.value(), abs_parent.value(), false))
+#else
+  if (!StartsWithASCII(abs_child.value(), abs_parent.value(), true))
+#endif
+    return false;
+
+  // file_util::AbsolutePath() normalizes '/' to '\' on Windows, so we only need
+  // to check kSeparators[0].
+  if (abs_child.value().length() <= abs_parent.value().length() ||
+      abs_child.value()[abs_parent.value().length()] !=
+          FilePath::kSeparators[0])
+    return false;
+
+  return true;
+}
+
+int64 ComputeDirectorySize(const FilePath& root_path) {
+  int64 running_size = 0;
+  FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
+  for (FilePath current = file_iter.Next(); !current.empty();
+       current = file_iter.Next()) {
+    FileEnumerator::FindInfo info;
+    file_iter.GetFindInfo(&info);
+#if defined(OS_WIN)
+    LARGE_INTEGER li = { info.nFileSizeLow, info.nFileSizeHigh };
+    running_size += li.QuadPart;
+#else
+    running_size += info.stat.st_size;
+#endif
+  }
+  return running_size;
+}
+
+int64 ComputeFilesSize(const FilePath& directory,
+                       const FilePath::StringType& pattern) {
+  int64 running_size = 0;
+  FileEnumerator file_iter(directory, false, FileEnumerator::FILES, pattern);
+  for (FilePath current = file_iter.Next(); !current.empty();
+       current = file_iter.Next()) {
+    FileEnumerator::FindInfo info;
+    file_iter.GetFindInfo(&info);
+#if defined(OS_WIN)
+    LARGE_INTEGER li = { info.nFileSizeLow, info.nFileSizeHigh };
+    running_size += li.QuadPart;
+#else
+    running_size += info.stat.st_size;
+#endif
+  }
+  return running_size;
+}
+
+///////////////////////////////////////////////
+// MemoryMappedFile
+
+MemoryMappedFile::~MemoryMappedFile() {
+  CloseHandles();
+}
+
+bool MemoryMappedFile::Initialize(const FilePath& file_name) {
+  if (IsValid())
+    return false;
+
+  if (!MapFileToMemory(file_name)) {
+    CloseHandles();
+    return false;
+  }
+
+  return true;
+}
+
+bool MemoryMappedFile::Initialize(base::PlatformFile file) {
+  if (IsValid())
+    return false;
+
+  file_ = file;
+
+  if (!MapFileToMemoryInternal()) {
+    CloseHandles();
+    return false;
+  }
+
+  return true;
+}
+
+bool MemoryMappedFile::IsValid() const {
+  return data_ != NULL;
+}
+
+bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) {
+  file_ = base::CreatePlatformFile(
+      file_name, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+      NULL, NULL);
+
+  if (file_ == base::kInvalidPlatformFileValue) {
+    DLOG(ERROR) << "Couldn't open " << file_name.value();
+    return false;
+  }
+
+  return MapFileToMemoryInternal();
+}
+
+///////////////////////////////////////////////
+// FileEnumerator
+//
+// Note: the main logic is in file_util_<platform>.cc
+
+bool FileEnumerator::ShouldSkip(const FilePath& path) {
+  FilePath::StringType basename = path.BaseName().value();
+  return IsDot(path) || (IsDotDot(path) && !(INCLUDE_DOT_DOT & file_type_));
+}
+
+}  // namespace
diff --git a/base/file_util.h b/base/file_util.h
new file mode 100644
index 0000000..ef67b4d
--- /dev/null
+++ b/base/file_util.h
@@ -0,0 +1,628 @@
+// Copyright (c) 2012 The Chromium 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_FILE_UTIL_H_
+#define BASE_FILE_UTIL_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#include <set>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/platform_file.h"
+#include "base/string16.h"
+
+#if defined(OS_POSIX)
+#include "base/eintr_wrapper.h"
+#include "base/file_descriptor_posix.h"
+#include "base/logging.h"
+#endif
+
+namespace base {
+class Time;
+}
+
+namespace file_util {
+
+extern bool g_bug108724_debug;
+
+//-----------------------------------------------------------------------------
+// Functions that operate purely on a path string w/o touching the filesystem:
+
+// Returns true if the given path ends with a path separator character.
+BASE_EXPORT bool EndsWithSeparator(const FilePath& path);
+
+// Makes sure that |path| ends with a separator IFF path is a directory that
+// exists. Returns true if |path| is an existing directory, false otherwise.
+BASE_EXPORT bool EnsureEndsWithSeparator(FilePath* path);
+
+// Convert provided relative path into an absolute path.  Returns false on
+// error. On POSIX, this function fails if the path does not exist.
+BASE_EXPORT bool AbsolutePath(FilePath* path);
+
+// Returns true if |parent| contains |child|. Both paths are converted to
+// absolute paths before doing the comparison.
+BASE_EXPORT bool ContainsPath(const FilePath& parent, const FilePath& child);
+
+//-----------------------------------------------------------------------------
+// Functions that involve filesystem access or modification:
+
+// Returns the number of files matching the current path that were
+// created on or after the given |file_time|.  Doesn't count ".." or ".".
+//
+// Note for POSIX environments: a file created before |file_time|
+// can be mis-detected as a newer file due to low precision of
+// timestmap of file creation time. If you need to avoid such
+// mis-detection perfectly, you should wait one second before
+// obtaining |file_time|.
+BASE_EXPORT int CountFilesCreatedAfter(const FilePath& path,
+                                       const base::Time& file_time);
+
+// Returns the total number of bytes used by all the files under |root_path|.
+// If the path does not exist the function returns 0.
+//
+// This function is implemented using the FileEnumerator class so it is not
+// particularly speedy in any platform.
+BASE_EXPORT int64 ComputeDirectorySize(const FilePath& root_path);
+
+// Returns the total number of bytes used by all files matching the provided
+// |pattern|, on this |directory| (without recursion). 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 ComputeFilesSize(const FilePath& directory,
+                                   const FilePath::StringType& pattern);
+
+// 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.
+//
+// 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 Delete(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 DeleteAfterReboot(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.
+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.
+BASE_EXPORT bool ReplaceFile(const FilePath& from_path,
+                             const FilePath& to_path);
+
+// Copies a single file. Use CopyDirectory to copy directories.
+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.
+// Don't use wildcards on the names, it may stop working without notice.
+//
+// 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);
+
+#if defined(OS_WIN)
+// Gets the creation time of the given file (expressed in the local timezone),
+// and returns it via the creation_time parameter.  Returns true if successful,
+// false otherwise.
+BASE_EXPORT bool GetFileCreationLocalTime(const std::wstring& filename,
+                                          LPSYSTEMTIME creation_time);
+
+// Same as above, but takes a previously-opened file handle instead of a name.
+BASE_EXPORT bool GetFileCreationLocalTimeFromHandle(HANDLE file_handle,
+                                                    LPSYSTEMTIME creation_time);
+#endif  // defined(OS_WIN)
+
+// 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);
+
+// Read the file at |path| into |contents|, returning true on success.
+// |contents| may be NULL, in which case this function is useful for its
+// side effect of priming the disk cache.
+// Useful for unit tests.
+BASE_EXPORT bool ReadFileToString(const FilePath& path, std::string* contents);
+
+#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 successfuly 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 ans masks of the file permission.
+enum FilePermissionBits {
+  FILE_PERMISSION_MASK              = S_IRWXU | S_IRWXG | S_IRWXO,
+  FILE_PERMISSION_USER_MASK         = S_IRWXU,
+  FILE_PERMISSION_GROUP_MASK        = S_IRWXG,
+  FILE_PERMISSION_OTHERS_MASK       = S_IRWXO,
+
+  FILE_PERMISSION_READ_BY_USER      = S_IRUSR,
+  FILE_PERMISSION_WRITE_BY_USER     = S_IWUSR,
+  FILE_PERMISSION_EXECUTE_BY_USER   = S_IXUSR,
+  FILE_PERMISSION_READ_BY_GROUP     = S_IRGRP,
+  FILE_PERMISSION_WRITE_BY_GROUP    = S_IWGRP,
+  FILE_PERMISSION_EXECUTE_BY_GROUP  = S_IXGRP,
+  FILE_PERMISSION_READ_BY_OTHERS    = S_IROTH,
+  FILE_PERMISSION_WRITE_BY_OTHERS   = S_IWOTH,
+  FILE_PERMISSION_EXECUTE_BY_OTHERS = S_IXOTH,
+};
+
+// Reads the permission of the given |path|, storing the file permission
+// bits in |mode|. If |path| is symbolic link, |mode| is the permission of
+// a file which the symlink points to.
+BASE_EXPORT bool GetPosixFilePermissions(const FilePath& path,
+                                         int* mode);
+// Sets the permission of the given |path|. If |path| is symbolic link, sets
+// the permission of a file which the symlink points to.
+BASE_EXPORT bool SetPosixFilePermissions(const FilePath& path,
+                                         int mode);
+#endif  // defined(OS_POSIX)
+
+#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 fuction is not transactional.
+BASE_EXPORT bool CopyAndDeleteDirectory(const FilePath& from_path,
+                                        const FilePath& to_path);
+#endif  // defined(OS_WIN)
+
+// Return true if the given directory is empty
+BASE_EXPORT bool IsDirectoryEmpty(const FilePath& dir_path);
+
+// Get the temporary directory provided by the system.
+// WARNING: DON'T USE THIS. If you want to create a temporary file, use one of
+// the functions below.
+BASE_EXPORT bool GetTempDir(FilePath* path);
+// Get a temporary directory for shared memory files.
+// Only useful on POSIX; redirects to GetTempDir() on Windows.
+BASE_EXPORT bool GetShmemTempDir(FilePath* path, bool executable);
+
+// Get the home directory.  This is more complicated than just getenv("HOME")
+// as it knows to fall back on getpwent() etc.
+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 occured.
+BASE_EXPORT FILE* CreateAndOpenTemporaryFile(FilePath* path);
+// Like above but for shmem files.  Only useful for POSIX.
+// The executable flag says the file needs to support using
+// mprotect with PROT_EXEC after mapping.
+BASE_EXPORT FILE* CreateAndOpenTemporaryShmemFile(FilePath* path,
+                                                  bool executable);
+// 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.
+BASE_EXPORT bool CreateDirectory(const FilePath& full_path);
+
+// Returns the file size. Returns true on success.
+BASE_EXPORT bool GetFileSize(const FilePath& file_path, int64* file_size);
+
+// Returns true if the given path's base name is ".".
+BASE_EXPORT bool IsDot(const FilePath& path);
+
+// Returns true if the given path's base name is "..".
+BASE_EXPORT bool IsDotDot(const FilePath& path);
+
+// Sets |real_path| to |path| with symbolic links and junctions expanded.
+// On windows, make sure the path starts with a lettered drive.
+// |path| must reference a file.  Function will fail if |path| points to
+// a directory or to a nonexistent path.  On windows, this function will
+// fail if |path| is a junction or symlink that points to an empty file,
+// or if |real_path| would be longer than MAX_PATH characters.
+BASE_EXPORT bool NormalizeFilePath(const FilePath& path, FilePath* real_path);
+
+#if defined(OS_WIN)
+
+// Given a path in NT native form ("\Device\HarddiskVolumeXX\..."),
+// return in |drive_letter_path| the equivalent path that starts with
+// a drive letter ("C:\...").  Return false if no such path exists.
+BASE_EXPORT bool DevicePathToDriveLetterPath(const FilePath& device_path,
+                                             FilePath* drive_letter_path);
+
+// Given an existing file in |path|, set |real_path| to the path
+// in native NT format, of the form "\Device\HarddiskVolumeXX\..".
+// Returns false if the path can not be found. Empty files cannot
+// be resolved with this function.
+BASE_EXPORT bool NormalizeToNativeFilePath(const FilePath& path,
+                                           FilePath* nt_path);
+#endif
+
+// This function will return if the given file is a symlink or not.
+BASE_EXPORT bool IsLink(const FilePath& file_path);
+
+// Returns information about the given file path.
+BASE_EXPORT bool GetFileInfo(const FilePath& file_path,
+                             base::PlatformFileInfo* info);
+
+// Sets the time of the last access and the time of the last modification.
+BASE_EXPORT bool TouchFile(const FilePath& path,
+                           const base::Time& last_accessed,
+                           const base::Time& last_modified);
+
+// Set the time of the last modification. Useful for unit tests.
+BASE_EXPORT bool SetLastModifiedTime(const FilePath& path,
+                                     const base::Time& last_modified);
+
+#if defined(OS_POSIX)
+// Store inode number of |path| in |inode|. Return true on success.
+BASE_EXPORT bool GetInode(const FilePath& path, ino_t* inode);
+#endif
+
+// 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);
+
+// 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 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 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)
+// Append the data to |fd|. Does not close |fd| when done.
+BASE_EXPORT int WriteFileDescriptor(const int fd, const char* data, int size);
+#endif
+// Append the given buffer into the file. Returns the number of bytes written,
+// or -1 on error.
+BASE_EXPORT int AppendToFile(const FilePath& filename,
+                             const char* data, int size);
+
+// Gets the current working directory for the process.
+BASE_EXPORT bool GetCurrentDirectory(FilePath* path);
+
+// Sets the current working directory for the process.
+BASE_EXPORT bool SetCurrentDirectory(const FilePath& path);
+
+// Attempts to find a number that can be appended to the |path| to make it
+// unique. If |path| does not exist, 0 is returned.  If it fails to find such
+// a number, -1 is returned. If |suffix| is not empty, also checks the
+// existence of it with the given suffix.
+BASE_EXPORT int GetUniquePathNumber(const FilePath& path,
+                                    const FilePath::StringType& suffix);
+
+#if defined(OS_POSIX)
+// Test that |path| can only be changed by a given user and members of
+// a given set of groups.
+// Specifically, test that all parts of |path| under (and including) |base|:
+// * Exist.
+// * Are owned by a specific user.
+// * Are not writable by all users.
+// * Are owned by a memeber 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 FilePath& base,
+                                            const 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 FilePath& path);
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+
+// A class to handle auto-closing of FILE*'s.
+class ScopedFILEClose {
+ public:
+  inline void operator()(FILE* x) const {
+    if (x) {
+      fclose(x);
+    }
+  }
+};
+
+typedef scoped_ptr_malloc<FILE, ScopedFILEClose> ScopedFILE;
+
+#if defined(OS_POSIX)
+// A class to handle auto-closing of FDs.
+class ScopedFDClose {
+ public:
+  inline void operator()(int* x) const {
+    if (x && *x >= 0) {
+      if (HANDLE_EINTR(close(*x)) < 0)
+        DPLOG(ERROR) << "close";
+    }
+  }
+};
+
+typedef scoped_ptr_malloc<int, ScopedFDClose> ScopedFD;
+#endif  // OS_POSIX
+
+// A class for enumerating the files in a provided path. The order of the
+// results is not guaranteed.
+//
+// DO NOT USE FROM THE MAIN THREAD of your application unless it is a test
+// program where latency does not matter. This class is blocking.
+class BASE_EXPORT FileEnumerator {
+ public:
+#if defined(OS_WIN)
+  typedef WIN32_FIND_DATA FindInfo;
+#elif defined(OS_POSIX)
+  typedef struct {
+    struct stat stat;
+    std::string filename;
+  } FindInfo;
+#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 an empty string if there are no more results.
+  FilePath Next();
+
+  // Write the file info into |info|.
+  void GetFindInfo(FindInfo* info);
+
+  // Looks inside a FindInfo and determines if it's a directory.
+  static bool IsDirectory(const FindInfo& info);
+
+  static FilePath GetFilename(const FindInfo& find_info);
+  static int64 GetFilesize(const FindInfo& find_info);
+  static base::Time GetLastModifiedTime(const FindInfo& find_info);
+
+ 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)
+  struct DirectoryEntryInfo {
+    FilePath filename;
+    struct stat stat;
+  };
+
+  // Read the filenames in source into the vector of DirectoryEntryInfo's
+  static bool ReadDirectory(std::vector<DirectoryEntryInfo>* entries,
+                            const FilePath& source, bool show_links);
+
+  // The files in the current directory
+  std::vector<DirectoryEntryInfo> 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);
+};
+
+class BASE_EXPORT MemoryMappedFile {
+ public:
+  // The default constructor sets all members to invalid/null values.
+  MemoryMappedFile();
+  ~MemoryMappedFile();
+
+  // Opens an existing file and maps it into memory. Access is restricted to
+  // read only. If this object already points to a valid memory mapped file
+  // then this method will fail and return false. If it cannot open the file,
+  // the file does not exist, or the memory mapping fails, it will return false.
+  // Later we may want to allow the user to specify access.
+  bool Initialize(const FilePath& file_name);
+  // As above, but works with an already-opened file. MemoryMappedFile will take
+  // ownership of |file| and close it when done.
+  bool Initialize(base::PlatformFile file);
+
+#if defined(OS_WIN)
+  // Opens an existing file and maps it as an image section. Please refer to
+  // the Initialize function above for additional information.
+  bool InitializeAsImageSection(const FilePath& file_name);
+#endif  // OS_WIN
+
+  const uint8* data() const { return data_; }
+  size_t length() const { return length_; }
+
+  // Is file_ a valid file handle that points to an open, memory mapped file?
+  bool IsValid() const;
+
+ private:
+  // Open the given file and pass it to MapFileToMemoryInternal().
+  bool MapFileToMemory(const FilePath& file_name);
+
+  // 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 MapFileToMemoryInternal();
+
+  // Closes all open handles. Later we may want to make this public.
+  void CloseHandles();
+
+#if defined(OS_WIN)
+  // MapFileToMemoryInternal calls this function. It provides the ability to
+  // pass in flags which control the mapped section.
+  bool MapFileToMemoryInternalEx(int flags);
+
+  HANDLE file_mapping_;
+#endif
+  base::PlatformFile file_;
+  uint8* data_;
+  size_t length_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile);
+};
+
+// Returns whether the file has been modified since a particular date.
+BASE_EXPORT bool HasFileBeenModifiedSince(
+    const FileEnumerator::FindInfo& find_info,
+    const base::Time& cutoff_time);
+
+#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
+
+}  // namespace file_util
+
+#endif  // BASE_FILE_UTIL_H_
diff --git a/base/file_util_android.cc b/base/file_util_android.cc
new file mode 100644
index 0000000..79db279
--- /dev/null
+++ b/base/file_util_android.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+
+#include "base/file_path.h"
+#include "base/path_service.h"
+
+namespace file_util {
+
+bool GetShmemTempDir(FilePath* path, bool executable) {
+  return PathService::Get(base::DIR_CACHE, path);
+}
+
+}  // namespace file_util
diff --git a/base/file_util_linux.cc b/base/file_util_linux.cc
new file mode 100644
index 0000000..f7d4f6e
--- /dev/null
+++ b/base/file_util_linux.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+
+#include "base/file_path.h"
+
+#include <errno.h>
+#include <sys/vfs.h>
+
+namespace file_util {
+
+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;
+  }
+
+  // While you would think the possible values of f_type would be available
+  // in a header somewhere, it appears that is not the case.  These values
+  // are copied from the statfs man page.
+  switch (statfs_buf.f_type) {
+    case 0:
+      *type = FILE_SYSTEM_0;
+      break;
+    case 0xEF53:  // ext2, ext3.
+    case 0x4D44:  // dos
+    case 0x5346544E:  // NFTS
+    case 0x52654973:  // reiser
+    case 0x58465342:  // XFS
+    case 0x9123683E:  // btrfs
+    case 0x3153464A:  // JFS
+      *type = FILE_SYSTEM_ORDINARY;
+      break;
+    case 0x6969:  // NFS
+      *type = FILE_SYSTEM_NFS;
+      break;
+    case 0xFF534D42:  // CIFS
+    case 0x517B:  // SMB
+      *type = FILE_SYSTEM_SMB;
+      break;
+    case 0x73757245:  // Coda
+      *type = FILE_SYSTEM_CODA;
+      break;
+    case 0x858458f6:  // ramfs
+    case 0x01021994:  // tmpfs
+      *type = FILE_SYSTEM_MEMORY;
+      break;
+    case 0x27e0eb: // CGROUP
+      *type = FILE_SYSTEM_CGROUP;
+      break;
+    default:
+      *type = FILE_SYSTEM_OTHER;
+  }
+  return true;
+}
+
+}  // namespace
diff --git a/base/file_util_mac.mm b/base/file_util_mac.mm
new file mode 100644
index 0000000..0638167
--- /dev/null
+++ b/base/file_util_mac.mm
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+
+#import <Foundation/Foundation.h>
+#include <copyfile.h>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/mac/foundation_util.h"
+#include "base/string_util.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace file_util {
+
+bool GetTempDir(FilePath* path) {
+  NSString* tmp = NSTemporaryDirectory();
+  if (tmp == nil)
+    return false;
+  *path = base::mac::NSStringToFilePath(tmp);
+  return true;
+}
+
+bool GetShmemTempDir(FilePath* path, bool executable) {
+  return GetTempDir(path);
+}
+
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return (copyfile(from_path.value().c_str(),
+                   to_path.value().c_str(), NULL, COPYFILE_ALL) == 0);
+}
+
+}  // namespace
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
new file mode 100644
index 0000000..15d2213
--- /dev/null
+++ b/base/file_util_posix.cc
@@ -0,0 +1,1161 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_util.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#include "base/mac/foundation_util.h"
+#elif !defined(OS_ANDROID)
+#include <glib.h>
+#endif
+
+#include <fstream>
+
+#include "base/basictypes.h"
+#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/sys_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#endif
+
+#if !defined(OS_IOS)
+#include <grp.h>
+#endif
+
+#if defined(OS_CHROMEOS)
+#include "base/chromeos/chromeos_version.h"
+#endif
+
+namespace file_util {
+
+namespace {
+
+#if defined(OS_BSD) || defined(OS_MACOSX)
+typedef struct stat stat_wrapper_t;
+static int CallStat(const char *path, stat_wrapper_t *sb) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return stat(path, sb);
+}
+static int CallLstat(const char *path, stat_wrapper_t *sb) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return lstat(path, sb);
+}
+#else
+typedef struct stat64 stat_wrapper_t;
+static int CallStat(const char *path, stat_wrapper_t *sb) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return stat64(path, sb);
+}
+static int CallLstat(const char *path, stat_wrapper_t *sb) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return lstat64(path, sb);
+}
+#endif
+
+// Helper for NormalizeFilePath(), defined below.
+bool RealPath(const FilePath& path, FilePath* real_path) {
+  base::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;
+}
+
+}  // namespace
+
+static 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
+}
+
+bool AbsolutePath(FilePath* path) {
+  base::ThreadRestrictions::AssertIOAllowed();  // For realpath().
+  char full_path[PATH_MAX];
+  if (realpath(path->value().c_str(), full_path) == NULL)
+    return false;
+  *path = FilePath(full_path);
+  return true;
+}
+
+int CountFilesCreatedAfter(const FilePath& path,
+                           const base::Time& comparison_time) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  int file_count = 0;
+
+  DIR* dir = opendir(path.value().c_str());
+  if (dir) {
+#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 ent_buf;
+    struct dirent* ent;
+    while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) {
+      if ((strcmp(ent->d_name, ".") == 0) ||
+          (strcmp(ent->d_name, "..") == 0))
+        continue;
+
+      stat_wrapper_t st;
+      int test = CallStat(path.Append(ent->d_name).value().c_str(), &st);
+      if (test != 0) {
+        DPLOG(ERROR) << "stat64 failed";
+        continue;
+      }
+      // Here, we use Time::TimeT(), which discards microseconds. This
+      // means that files which are newer than |comparison_time| may
+      // be considered older. If we don't discard microseconds, it
+      // introduces another issue. Suppose the following case:
+      //
+      // 1. Get |comparison_time| by Time::Now() and the value is 10.1 (secs).
+      // 2. Create a file and the current time is 10.3 (secs).
+      //
+      // As POSIX doesn't have microsecond precision for |st_ctime|,
+      // the creation time of the file created in the step 2 is 10 and
+      // the file is considered older than |comparison_time|. After
+      // all, we may have to accept either of the two issues: 1. files
+      // which are older than |comparison_time| are considered newer
+      // (current implementation) 2. files newer than
+      // |comparison_time| are considered older.
+      if (static_cast<time_t>(st.st_ctime) >= comparison_time.ToTimeT())
+        ++file_count;
+    }
+    closedir(dir);
+  }
+  return file_count;
+}
+
+// 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 Delete(const FilePath& path, bool recursive) {
+  base::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()) {
+    FileEnumerator::FindInfo info;
+    traversal.GetFindInfo(&info);
+
+    if (S_ISDIR(info.stat.st_mode))
+      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 Move(const FilePath& from_path, const FilePath& to_path) {
+  base::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;
+
+  Delete(from_path, true);
+  return true;
+}
+
+bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return (rename(from_path.value().c_str(), to_path.value().c_str()) == 0);
+}
+
+bool CopyDirectory(const FilePath& from_path,
+                   const FilePath& to_path,
+                   bool recursive) {
+  base::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.
+  // TODO(evanm): remove this once we're sure it's ok.
+  DCHECK(to_path.value().find('*') == std::string::npos);
+  DCHECK(from_path.value().find('*') == std::string::npos);
+
+  char top_dir[PATH_MAX];
+  if (base::strlcpy(top_dir, from_path.value().c_str(),
+                    arraysize(top_dir)) >= arraysize(top_dir)) {
+    return false;
+  }
+
+  // This function does not properly handle destinations within the source
+  FilePath real_to_path = to_path;
+  if (PathExists(real_to_path)) {
+    if (!AbsolutePath(&real_to_path))
+      return false;
+  } else {
+    real_to_path = real_to_path.DirName();
+    if (!AbsolutePath(&real_to_path))
+      return false;
+  }
+  FilePath real_from_path = from_path;
+  if (!AbsolutePath(&real_from_path))
+    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;
+
+  bool success = true;
+  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|.
+  FileEnumerator::FindInfo info;
+  FilePath current = from_path;
+  if (stat(from_path.value().c_str(), &info.stat) < 0) {
+    DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: "
+                << from_path.value() << " errno = " << errno;
+    success = 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.
+  DCHECK(recursive || S_ISDIR(info.stat.st_mode));
+
+  while (success && !current.empty()) {
+    // current is the source path, including from_path, so paste
+    // the suffix after from_path onto to_path to create the target_path.
+    std::string suffix(&current.value().c_str()[from_path_base.value().size()]);
+    // Strip the leading '/' (if any).
+    if (!suffix.empty()) {
+      DCHECK_EQ('/', suffix[0]);
+      suffix.erase(0, 1);
+    }
+    const FilePath target_path = to_path.Append(suffix);
+
+    if (S_ISDIR(info.stat.st_mode)) {
+      if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 &&
+          errno != EEXIST) {
+        DLOG(ERROR) << "CopyDirectory() couldn't create directory: "
+                    << target_path.value() << " errno = " << errno;
+        success = false;
+      }
+    } else if (S_ISREG(info.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();
+    traversal.GetFindInfo(&info);
+  }
+
+  return success;
+}
+
+bool PathExists(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return access(path.value().c_str(), F_OK) == 0;
+}
+
+bool PathIsWritable(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return access(path.value().c_str(), W_OK) == 0;
+}
+
+bool DirectoryExists(const FilePath& path) {
+  base::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;
+}
+
+// TODO(erikkay): implement
+#if 0
+bool GetFileCreationLocalTimeFromHandle(int fd,
+                                        LPSYSTEMTIME creation_time) {
+  if (!file_handle)
+    return false;
+
+  FILETIME utc_filetime;
+  if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
+    return false;
+
+  FILETIME local_filetime;
+  if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
+    return false;
+
+  return !!FileTimeToSystemTime(&local_filetime, creation_time);
+}
+
+bool GetFileCreationLocalTime(const std::string& filename,
+                              LPSYSTEMTIME creation_time) {
+  ScopedHandle file_handle(
+      CreateFile(filename.c_str(), GENERIC_READ,
+                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
+  return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
+}
+#endif
+
+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;
+}
+
+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) {
+  base::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) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK((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;
+}
+
+// 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) {
+  base::ThreadRestrictions::AssertIOAllowed();  // For call to mkstemp().
+  *path = directory.Append(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));
+}
+
+bool CreateTemporaryFile(FilePath* path) {
+  base::ThreadRestrictions::AssertIOAllowed();  // For call to close().
+  FilePath directory;
+  if (!GetTempDir(&directory))
+    return false;
+  int fd = CreateAndOpenFdForTemporaryFile(directory, path);
+  if (fd < 0)
+    return false;
+  ignore_result(HANDLE_EINTR(close(fd)));
+  return true;
+}
+
+FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) {
+  FilePath directory;
+  if (!GetShmemTempDir(&directory, executable))
+    return NULL;
+
+  return CreateAndOpenTemporaryFileInDir(directory, path);
+}
+
+FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
+  int fd = CreateAndOpenFdForTemporaryFile(dir, path);
+  if (fd < 0)
+    return NULL;
+
+  FILE* file = fdopen(fd, "a+");
+  if (!file)
+    ignore_result(HANDLE_EINTR(close(fd)));
+  return file;
+}
+
+bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
+  base::ThreadRestrictions::AssertIOAllowed();  // For call to close().
+  int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file);
+  return ((fd >= 0) && !HANDLE_EINTR(close(fd)));
+}
+
+static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir,
+                                        const FilePath::StringType& name_tmpl,
+                                        FilePath* new_dir) {
+  base::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 CreateDirectory(const FilePath& full_path) {
+  base::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.
+    if (!DirectoryExists(*i))
+      return false;
+  }
+  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, base::PlatformFileInfo* results) {
+  stat_wrapper_t file_info;
+  if (CallStat(file_path.value().c_str(), &file_info) != 0)
+    return false;
+  results->is_directory = S_ISDIR(file_info.st_mode);
+  results->size = file_info.st_size;
+  results->last_modified = base::Time::FromTimeT(file_info.st_mtime);
+  results->last_accessed = base::Time::FromTimeT(file_info.st_atime);
+  results->creation_time = base::Time::FromTimeT(file_info.st_ctime);
+  return true;
+}
+
+bool GetInode(const FilePath& path, ino_t* inode) {
+  base::ThreadRestrictions::AssertIOAllowed();  // For call to stat().
+  struct stat buffer;
+  int result = stat(path.value().c_str(), &buffer);
+  if (result < 0)
+    return false;
+
+  *inode = buffer.st_ino;
+  return true;
+}
+
+FILE* OpenFile(const std::string& filename, const char* mode) {
+  return OpenFile(FilePath(filename), mode);
+}
+
+FILE* OpenFile(const FilePath& filename, const char* mode) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  FILE* result = NULL;
+  do {
+    result = fopen(filename.value().c_str(), mode);
+  } while (!result && errno == EINTR);
+  return result;
+}
+
+int ReadFile(const FilePath& filename, char* data, int size) {
+  base::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, size));
+  if (int ret = HANDLE_EINTR(close(fd)) < 0)
+    return ret;
+  return bytes_read;
+}
+
+int WriteFile(const FilePath& filename, const char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0666));
+  if (fd < 0)
+    return -1;
+
+  int bytes_written = WriteFileDescriptor(fd, data, size);
+  if (int ret = HANDLE_EINTR(close(fd)) < 0)
+    return ret;
+  return bytes_written;
+}
+
+int 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 -1;
+  }
+
+  return bytes_written_total;
+}
+
+int AppendToFile(const FilePath& filename, const char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  int fd = HANDLE_EINTR(open(filename.value().c_str(), O_WRONLY | O_APPEND));
+  if (fd < 0)
+    return -1;
+
+  int bytes_written = WriteFileDescriptor(fd, data, size);
+  if (int ret = HANDLE_EINTR(close(fd)) < 0)
+    return ret;
+  return bytes_written;
+}
+
+// Gets the current working directory for the process.
+bool GetCurrentDirectory(FilePath* dir) {
+  // getcwd can return ENOENT, which implies it checks against the disk.
+  base::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) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  int ret = chdir(path.value().c_str());
+  return !ret;
+}
+
+///////////////////////////////////////////////
+// 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<DirectoryEntryInfo> entries;
+    if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS))
+      continue;
+
+    directory_entries_.clear();
+    current_directory_entry_ = 0;
+    for (std::vector<DirectoryEntryInfo>::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);
+}
+
+void FileEnumerator::GetFindInfo(FindInfo* info) {
+  DCHECK(info);
+
+  if (current_directory_entry_ >= directory_entries_.size())
+    return;
+
+  DirectoryEntryInfo* cur_entry = &directory_entries_[current_directory_entry_];
+  memcpy(&(info->stat), &(cur_entry->stat), sizeof(info->stat));
+  info->filename.assign(cur_entry->filename.value());
+}
+
+// static
+bool FileEnumerator::IsDirectory(const FindInfo& info) {
+  return S_ISDIR(info.stat.st_mode);
+}
+
+// static
+FilePath FileEnumerator::GetFilename(const FindInfo& find_info) {
+  return FilePath(find_info.filename);
+}
+
+// static
+int64 FileEnumerator::GetFilesize(const FindInfo& find_info) {
+  return find_info.stat.st_size;
+}
+
+// static
+base::Time FileEnumerator::GetLastModifiedTime(const FindInfo& find_info) {
+  return base::Time::FromTimeT(find_info.stat.st_mtime);
+}
+
+bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo>* 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) {
+    DirectoryEntryInfo 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;
+}
+
+///////////////////////////////////////////////
+// MemoryMappedFile
+
+MemoryMappedFile::MemoryMappedFile()
+    : file_(base::kInvalidPlatformFileValue),
+      data_(NULL),
+      length_(0) {
+}
+
+bool MemoryMappedFile::MapFileToMemoryInternal() {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  struct stat file_stat;
+  if (fstat(file_, &file_stat) == base::kInvalidPlatformFileValue) {
+    DLOG(ERROR) << "Couldn't fstat " << file_ << ", errno " << errno;
+    return false;
+  }
+  length_ = file_stat.st_size;
+
+  data_ = static_cast<uint8*>(
+      mmap(NULL, length_, PROT_READ, MAP_SHARED, file_, 0));
+  if (data_ == MAP_FAILED)
+    DLOG(ERROR) << "Couldn't mmap " << file_ << ", errno " << errno;
+
+  return data_ != MAP_FAILED;
+}
+
+void MemoryMappedFile::CloseHandles() {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  if (data_ != NULL)
+    munmap(data_, length_);
+  if (file_ != base::kInvalidPlatformFileValue)
+    ignore_result(HANDLE_EINTR(close(file_)));
+
+  data_ = NULL;
+  length_ = 0;
+  file_ = base::kInvalidPlatformFileValue;
+}
+
+bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info,
+                              const base::Time& cutoff_time) {
+  return static_cast<time_t>(find_info.stat.st_mtime) >= cutoff_time.ToTimeT();
+}
+
+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;
+}
+
+#if !defined(OS_MACOSX)
+bool GetTempDir(FilePath* path) {
+  const char* tmp = getenv("TMPDIR");
+  if (tmp)
+    *path = FilePath(tmp);
+  else
+#if defined(OS_ANDROID)
+    return PathService::Get(base::DIR_CACHE, path);
+#else
+    *path = FilePath("/tmp");
+#endif
+  return true;
+}
+
+#if !defined(OS_ANDROID)
+
+#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.
+
+namespace {
+
+bool DetermineDevShmExecutable() {
+  bool result = false;
+  FilePath path;
+  int fd = CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path);
+  if (fd >= 0) {
+    ScopedFD shm_fd_closer(&fd);
+    Delete(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, 0);
+    if (mapping != MAP_FAILED) {
+      if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0)
+        result = true;
+      munmap(mapping, pagesize);
+    }
+  }
+  return result;
+}
+
+};  // namespace
+#endif  // defined(OS_LINUX)
+
+bool GetShmemTempDir(FilePath* path, bool executable) {
+#if defined(OS_LINUX)
+  bool use_dev_shm = true;
+  if (executable) {
+    static const bool s_dev_shm_executable = DetermineDevShmExecutable();
+    use_dev_shm = s_dev_shm_executable;
+  }
+  if (use_dev_shm) {
+    *path = FilePath("/dev/shm");
+    return true;
+  }
+#endif
+  return GetTempDir(path);
+}
+#endif  // !defined(OS_ANDROID)
+
+FilePath GetHomeDir() {
+#if defined(OS_CHROMEOS)
+  if (base::chromeos::IsRunningOnChromeOS())
+    return FilePath("/home/chronos/user");
+#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.";
+#else
+  // g_get_home_dir calls getpwent, which can fall through to LDAP calls.
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  home_dir = g_get_home_dir();
+  if (home_dir && home_dir[0])
+    return FilePath(home_dir);
+#endif
+
+  FilePath rv;
+  if (file_util::GetTempDir(&rv))
+    return rv;
+
+  // Last resort.
+  return FilePath("/tmp");
+}
+
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  int infile = HANDLE_EINTR(open(from_path.value().c_str(), O_RDONLY));
+  if (infile < 0)
+    return false;
+
+  int outfile = HANDLE_EINTR(creat(to_path.value().c_str(), 0666));
+  if (outfile < 0) {
+    ignore_result(HANDLE_EINTR(close(infile)));
+    return false;
+  }
+
+  const size_t kBufferSize = 32768;
+  std::vector<char> buffer(kBufferSize);
+  bool result = true;
+
+  while (result) {
+    ssize_t bytes_read = HANDLE_EINTR(read(infile, &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 = HANDLE_EINTR(write(
+          outfile,
+          &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);
+  }
+
+  if (HANDLE_EINTR(close(infile)) < 0)
+    result = false;
+  if (HANDLE_EINTR(close(outfile)) < 0)
+    result = false;
+
+  return result;
+}
+#endif  // !defined(OS_MACOSX)
+
+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.
+  base::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)
+
+}  // namespace file_util
diff --git a/base/file_util_proxy.cc b/base/file_util_proxy.cc
new file mode 100644
index 0000000..290279e
--- /dev/null
+++ b/base/file_util_proxy.cc
@@ -0,0 +1,436 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util_proxy.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/file_util.h"
+#include "base/location.h"
+#include "base/message_loop_proxy.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+
+namespace base {
+
+namespace {
+
+void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback& callback,
+                                 bool value) {
+  DCHECK(!callback.is_null());
+  callback.Run(value ? PLATFORM_FILE_OK : PLATFORM_FILE_ERROR_FAILED);
+}
+
+// Helper classes or routines for individual methods.
+class CreateOrOpenHelper {
+ public:
+  CreateOrOpenHelper(TaskRunner* task_runner,
+                     const FileUtilProxy::CloseTask& close_task)
+      : task_runner_(task_runner),
+        close_task_(close_task),
+        file_handle_(kInvalidPlatformFileValue),
+        created_(false),
+        error_(PLATFORM_FILE_OK) {}
+
+  ~CreateOrOpenHelper() {
+    if (file_handle_ != kInvalidPlatformFileValue) {
+      task_runner_->PostTask(
+          FROM_HERE,
+          base::Bind(base::IgnoreResult(close_task_), file_handle_));
+    }
+  }
+
+  void RunWork(const FileUtilProxy::CreateOrOpenTask& task) {
+    error_ = task.Run(&file_handle_, &created_);
+  }
+
+  void Reply(const FileUtilProxy::CreateOrOpenCallback& callback) {
+    DCHECK(!callback.is_null());
+    callback.Run(error_, PassPlatformFile(&file_handle_), created_);
+  }
+
+ private:
+  scoped_refptr<TaskRunner> task_runner_;
+  FileUtilProxy::CloseTask close_task_;
+  PlatformFile file_handle_;
+  bool created_;
+  PlatformFileError error_;
+  DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper);
+};
+
+class CreateTemporaryHelper {
+ public:
+  explicit CreateTemporaryHelper(TaskRunner* task_runner)
+      : task_runner_(task_runner),
+        file_handle_(kInvalidPlatformFileValue),
+        error_(PLATFORM_FILE_OK) {}
+
+  ~CreateTemporaryHelper() {
+    if (file_handle_ != kInvalidPlatformFileValue) {
+      FileUtilProxy::Close(task_runner_, file_handle_,
+                           FileUtilProxy::StatusCallback());
+    }
+  }
+
+  void RunWork(int additional_file_flags) {
+    // TODO(darin): file_util should have a variant of CreateTemporaryFile
+    // that returns a FilePath and a PlatformFile.
+    file_util::CreateTemporaryFile(&file_path_);
+
+    int file_flags =
+        PLATFORM_FILE_WRITE |
+        PLATFORM_FILE_TEMPORARY |
+        PLATFORM_FILE_CREATE_ALWAYS |
+        additional_file_flags;
+
+    error_ = PLATFORM_FILE_OK;
+    file_handle_ = CreatePlatformFile(file_path_, file_flags, NULL, &error_);
+  }
+
+  void Reply(const FileUtilProxy::CreateTemporaryCallback& callback) {
+    DCHECK(!callback.is_null());
+    callback.Run(error_, PassPlatformFile(&file_handle_), file_path_);
+  }
+
+ private:
+  scoped_refptr<TaskRunner> task_runner_;
+  PlatformFile file_handle_;
+  FilePath file_path_;
+  PlatformFileError error_;
+  DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper);
+};
+
+class GetFileInfoHelper {
+ public:
+  GetFileInfoHelper()
+      : error_(PLATFORM_FILE_OK) {}
+
+  void RunWorkForFilePath(const FilePath& file_path) {
+    if (!file_util::PathExists(file_path)) {
+      error_ = PLATFORM_FILE_ERROR_NOT_FOUND;
+      return;
+    }
+    if (!file_util::GetFileInfo(file_path, &file_info_))
+      error_ = PLATFORM_FILE_ERROR_FAILED;
+  }
+
+  void RunWorkForPlatformFile(PlatformFile file) {
+    if (!GetPlatformFileInfo(file, &file_info_))
+      error_ = PLATFORM_FILE_ERROR_FAILED;
+  }
+
+  void Reply(const FileUtilProxy::GetFileInfoCallback& callback) {
+    if (!callback.is_null()) {
+      callback.Run(error_, file_info_);
+    }
+  }
+
+ private:
+  PlatformFileError error_;
+  PlatformFileInfo file_info_;
+  DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper);
+};
+
+class ReadHelper {
+ public:
+  explicit ReadHelper(int bytes_to_read)
+      : buffer_(new char[bytes_to_read]),
+        bytes_to_read_(bytes_to_read),
+        bytes_read_(0) {}
+
+  void RunWork(PlatformFile file, int64 offset) {
+    bytes_read_ = ReadPlatformFile(file, offset, buffer_.get(), bytes_to_read_);
+  }
+
+  void Reply(const FileUtilProxy::ReadCallback& callback) {
+    if (!callback.is_null()) {
+      PlatformFileError error =
+          (bytes_read_ < 0) ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK;
+      callback.Run(error, buffer_.get(), bytes_read_);
+    }
+  }
+
+ private:
+  scoped_array<char> buffer_;
+  int bytes_to_read_;
+  int bytes_read_;
+  DISALLOW_COPY_AND_ASSIGN(ReadHelper);
+};
+
+class WriteHelper {
+ public:
+  WriteHelper(const char* buffer, int bytes_to_write)
+      : buffer_(new char[bytes_to_write]),
+        bytes_to_write_(bytes_to_write),
+        bytes_written_(0) {
+    memcpy(buffer_.get(), buffer, bytes_to_write);
+  }
+
+  void RunWork(PlatformFile file, int64 offset) {
+    bytes_written_ = WritePlatformFile(file, offset, buffer_.get(),
+                                       bytes_to_write_);
+  }
+
+  void Reply(const FileUtilProxy::WriteCallback& callback) {
+    if (!callback.is_null()) {
+      PlatformFileError error =
+          (bytes_written_ < 0) ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK;
+      callback.Run(error, bytes_written_);
+    }
+  }
+
+ private:
+  scoped_array<char> buffer_;
+  int bytes_to_write_;
+  int bytes_written_;
+  DISALLOW_COPY_AND_ASSIGN(WriteHelper);
+};
+
+
+PlatformFileError CreateOrOpenAdapter(
+    const FilePath& file_path, int file_flags,
+    PlatformFile* file_handle, bool* created) {
+  DCHECK(file_handle);
+  DCHECK(created);
+  if (!file_util::DirectoryExists(file_path.DirName())) {
+    // If its parent does not exist, should return NOT_FOUND error.
+    return PLATFORM_FILE_ERROR_NOT_FOUND;
+  }
+  PlatformFileError error = PLATFORM_FILE_OK;
+  *file_handle = CreatePlatformFile(file_path, file_flags, created, &error);
+  return error;
+}
+
+PlatformFileError CloseAdapter(PlatformFile file_handle) {
+  if (!ClosePlatformFile(file_handle)) {
+    return PLATFORM_FILE_ERROR_FAILED;
+  }
+  return PLATFORM_FILE_OK;
+}
+
+PlatformFileError DeleteAdapter(const FilePath& file_path, bool recursive) {
+  if (!file_util::PathExists(file_path)) {
+    return PLATFORM_FILE_ERROR_NOT_FOUND;
+  }
+  if (!file_util::Delete(file_path, recursive)) {
+    if (!recursive && !file_util::IsDirectoryEmpty(file_path)) {
+      return PLATFORM_FILE_ERROR_NOT_EMPTY;
+    }
+    return PLATFORM_FILE_ERROR_FAILED;
+  }
+  return PLATFORM_FILE_OK;
+}
+
+}  // namespace
+
+// static
+bool FileUtilProxy::CreateOrOpen(
+    TaskRunner* task_runner,
+    const FilePath& file_path, int file_flags,
+    const CreateOrOpenCallback& callback) {
+  return RelayCreateOrOpen(
+      task_runner,
+      base::Bind(&CreateOrOpenAdapter, file_path, file_flags),
+      base::Bind(&CloseAdapter),
+      callback);
+}
+
+// static
+bool FileUtilProxy::CreateTemporary(
+    TaskRunner* task_runner,
+    int additional_file_flags,
+    const CreateTemporaryCallback& callback) {
+  CreateTemporaryHelper* helper = new CreateTemporaryHelper(task_runner);
+  return task_runner->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&CreateTemporaryHelper::RunWork, Unretained(helper),
+           additional_file_flags),
+      Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback));
+}
+
+// static
+bool FileUtilProxy::Close(
+    TaskRunner* task_runner,
+    base::PlatformFile file_handle,
+    const StatusCallback& callback) {
+  return RelayClose(
+      task_runner,
+      base::Bind(&CloseAdapter),
+      file_handle, callback);
+}
+
+// Retrieves the information about a file. It is invalid to pass NULL for the
+// callback.
+bool FileUtilProxy::GetFileInfo(
+    TaskRunner* task_runner,
+    const FilePath& file_path,
+    const GetFileInfoCallback& callback) {
+  GetFileInfoHelper* helper = new GetFileInfoHelper;
+  return task_runner->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GetFileInfoHelper::RunWorkForFilePath,
+           Unretained(helper), file_path),
+      Bind(&GetFileInfoHelper::Reply, Owned(helper), callback));
+}
+
+// static
+bool FileUtilProxy::GetFileInfoFromPlatformFile(
+    TaskRunner* task_runner,
+    PlatformFile file,
+    const GetFileInfoCallback& callback) {
+  GetFileInfoHelper* helper = new GetFileInfoHelper;
+  return task_runner->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GetFileInfoHelper::RunWorkForPlatformFile,
+           Unretained(helper), file),
+      Bind(&GetFileInfoHelper::Reply, Owned(helper), callback));
+}
+
+// static
+bool FileUtilProxy::Delete(TaskRunner* task_runner,
+                           const FilePath& file_path,
+                           bool recursive,
+                           const StatusCallback& callback) {
+  return RelayFileTask(
+      task_runner, FROM_HERE,
+      Bind(&DeleteAdapter, file_path, recursive),
+      callback);
+}
+
+// static
+bool FileUtilProxy::RecursiveDelete(
+    TaskRunner* task_runner,
+    const FilePath& file_path,
+    const StatusCallback& callback) {
+  return RelayFileTask(
+      task_runner, FROM_HERE,
+      Bind(&DeleteAdapter, file_path, true /* recursive */),
+      callback);
+}
+
+// static
+bool FileUtilProxy::Read(
+    TaskRunner* task_runner,
+    PlatformFile file,
+    int64 offset,
+    int bytes_to_read,
+    const ReadCallback& callback) {
+  if (bytes_to_read < 0) {
+    return false;
+  }
+  ReadHelper* helper = new ReadHelper(bytes_to_read);
+  return task_runner->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&ReadHelper::RunWork, Unretained(helper), file, offset),
+      Bind(&ReadHelper::Reply, Owned(helper), callback));
+}
+
+// static
+bool FileUtilProxy::Write(
+    TaskRunner* task_runner,
+    PlatformFile file,
+    int64 offset,
+    const char* buffer,
+    int bytes_to_write,
+    const WriteCallback& callback) {
+  if (bytes_to_write <= 0 || buffer == NULL) {
+    return false;
+  }
+  WriteHelper* helper = new WriteHelper(buffer, bytes_to_write);
+  return task_runner->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&WriteHelper::RunWork, Unretained(helper), file, offset),
+      Bind(&WriteHelper::Reply, Owned(helper), callback));
+}
+
+// static
+bool FileUtilProxy::Touch(
+    TaskRunner* task_runner,
+    PlatformFile file,
+    const Time& last_access_time,
+    const Time& last_modified_time,
+    const StatusCallback& callback) {
+  return base::PostTaskAndReplyWithResult(
+      task_runner,
+      FROM_HERE,
+      Bind(&TouchPlatformFile, file,
+           last_access_time, last_modified_time),
+      Bind(&CallWithTranslatedParameter, callback));
+}
+
+// static
+bool FileUtilProxy::Touch(
+    TaskRunner* task_runner,
+    const FilePath& file_path,
+    const Time& last_access_time,
+    const Time& last_modified_time,
+    const StatusCallback& callback) {
+  return base::PostTaskAndReplyWithResult(
+      task_runner,
+      FROM_HERE,
+      Bind(&file_util::TouchFile, file_path,
+           last_access_time, last_modified_time),
+      Bind(&CallWithTranslatedParameter, callback));
+}
+
+// static
+bool FileUtilProxy::Truncate(
+    TaskRunner* task_runner,
+    PlatformFile file,
+    int64 length,
+    const StatusCallback& callback) {
+  return base::PostTaskAndReplyWithResult(
+      task_runner,
+      FROM_HERE,
+      Bind(&TruncatePlatformFile, file, length),
+      Bind(&CallWithTranslatedParameter, callback));
+}
+
+// static
+bool FileUtilProxy::Flush(
+    TaskRunner* task_runner,
+    PlatformFile file,
+    const StatusCallback& callback) {
+  return base::PostTaskAndReplyWithResult(
+      task_runner,
+      FROM_HERE,
+      Bind(&FlushPlatformFile, file),
+      Bind(&CallWithTranslatedParameter, callback));
+}
+
+// static
+bool FileUtilProxy::RelayFileTask(
+    TaskRunner* task_runner,
+    const tracked_objects::Location& from_here,
+    const FileTask& file_task,
+    const StatusCallback& callback) {
+  return base::PostTaskAndReplyWithResult(
+      task_runner, from_here, file_task, callback);
+}
+
+// static
+bool FileUtilProxy::RelayCreateOrOpen(
+    TaskRunner* task_runner,
+    const CreateOrOpenTask& open_task,
+    const CloseTask& close_task,
+    const CreateOrOpenCallback& callback) {
+  CreateOrOpenHelper* helper = new CreateOrOpenHelper(
+      task_runner, close_task);
+  return task_runner->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), open_task),
+      Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback));
+}
+
+// static
+bool FileUtilProxy::RelayClose(
+    TaskRunner* task_runner,
+    const CloseTask& close_task,
+    PlatformFile file_handle,
+    const StatusCallback& callback) {
+  return base::PostTaskAndReplyWithResult(
+      task_runner, FROM_HERE, Bind(close_task, file_handle), callback);
+}
+
+}  // namespace base
diff --git a/base/file_util_proxy.h b/base/file_util_proxy.h
new file mode 100644
index 0000000..7df5145
--- /dev/null
+++ b/base/file_util_proxy.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_FILE_UTIL_PROXY_H_
+#define BASE_FILE_UTIL_PROXY_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/platform_file.h"
+
+namespace tracked_objects {
+class Location;
+};
+
+namespace base {
+
+class TaskRunner;
+class Time;
+
+// This class provides asynchronous access to common file routines.
+class BASE_EXPORT FileUtilProxy {
+ public:
+  // Holds metadata for file or directory entry.
+  struct Entry {
+    FilePath::StringType name;
+    bool is_directory;
+    int64 size;
+    base::Time last_modified_time;
+  };
+
+  // This callback is used by methods that report only an error code.  It is
+  // valid to pass a null callback to any function that takes a StatusCallback,
+  // in which case the operation will complete silently.
+  typedef Callback<void(PlatformFileError)> StatusCallback;
+
+  typedef Callback<void(PlatformFileError,
+                        PassPlatformFile,
+                        bool /* created */)> CreateOrOpenCallback;
+  typedef Callback<void(PlatformFileError,
+                        PassPlatformFile,
+                        const FilePath&)> CreateTemporaryCallback;
+  typedef Callback<void(PlatformFileError,
+                        const PlatformFileInfo&)> GetFileInfoCallback;
+  typedef Callback<void(PlatformFileError,
+                        const char* /* data */,
+                        int /* bytes read */)> ReadCallback;
+  typedef Callback<void(PlatformFileError,
+                        int /* bytes written */)> WriteCallback;
+
+  typedef Callback<PlatformFileError(PlatformFile*, bool*)> CreateOrOpenTask;
+  typedef Callback<PlatformFileError(PlatformFile)> CloseTask;
+  typedef Callback<PlatformFileError(void)> FileTask;
+
+  // Creates or opens a file with the given flags. It is invalid to pass a null
+  // callback. If PLATFORM_FILE_CREATE is set in |file_flags| it always tries to
+  // create a new file at the given |file_path| and calls back with
+  // PLATFORM_FILE_ERROR_FILE_EXISTS if the |file_path| already exists.
+  static bool CreateOrOpen(TaskRunner* task_runner,
+                           const FilePath& file_path,
+                           int file_flags,
+                           const CreateOrOpenCallback& callback);
+
+  // Creates a temporary file for writing. The path and an open file handle are
+  // returned. It is invalid to pass a null callback. The additional file flags
+  // will be added on top of the default file flags which are:
+  //   base::PLATFORM_FILE_CREATE_ALWAYS
+  //   base::PLATFORM_FILE_WRITE
+  //   base::PLATFORM_FILE_TEMPORARY.
+  // Set |additional_file_flags| to 0 for synchronous writes and set to
+  // base::PLATFORM_FILE_ASYNC to support asynchronous file operations.
+  static bool CreateTemporary(
+      TaskRunner* task_runner,
+      int additional_file_flags,
+      const CreateTemporaryCallback& callback);
+
+  // Close the given file handle.
+  static bool Close(TaskRunner* task_runner,
+                    PlatformFile,
+                    const StatusCallback& callback);
+
+  // Retrieves the information about a file. It is invalid to pass a null
+  // callback.
+  static bool GetFileInfo(
+      TaskRunner* task_runner,
+      const FilePath& file_path,
+      const GetFileInfoCallback& callback);
+
+  static bool GetFileInfoFromPlatformFile(
+      TaskRunner* task_runner,
+      PlatformFile file,
+      const GetFileInfoCallback& callback);
+
+  // Deletes a file or a directory.
+  // It is an error to delete a non-empty directory with recursive=false.
+  static bool Delete(TaskRunner* task_runner,
+                     const FilePath& file_path,
+                     bool recursive,
+                     const StatusCallback& callback);
+
+  // Deletes a directory and all of its contents.
+  static bool RecursiveDelete(
+      TaskRunner* task_runner,
+      const FilePath& file_path,
+      const StatusCallback& callback);
+
+  // Reads from a file. On success, the file pointer is moved to position
+  // |offset + bytes_to_read| in the file. The callback can be null.
+  static bool Read(
+      TaskRunner* task_runner,
+      PlatformFile file,
+      int64 offset,
+      int bytes_to_read,
+      const ReadCallback& callback);
+
+  // Writes to a file. If |offset| is greater than the length of the file,
+  // |false| is returned. On success, the file pointer is moved to position
+  // |offset + bytes_to_write| in the file. The callback can be null.
+  // |bytes_to_write| must be greater than zero.
+  static bool Write(
+      TaskRunner* task_runner,
+      PlatformFile file,
+      int64 offset,
+      const char* buffer,
+      int bytes_to_write,
+      const WriteCallback& callback);
+
+  // Touches a file. The callback can be null.
+  static bool Touch(
+      TaskRunner* task_runner,
+      PlatformFile file,
+      const Time& last_access_time,
+      const Time& last_modified_time,
+      const StatusCallback& callback);
+
+  // Touches a file. The callback can be null.
+  static bool Touch(
+      TaskRunner* task_runner,
+      const FilePath& file_path,
+      const Time& last_access_time,
+      const Time& last_modified_time,
+      const StatusCallback& callback);
+
+  // Truncates a file to the given length. If |length| is greater than the
+  // current length of the file, the file will be extended with zeroes.
+  // The callback can be null.
+  static bool Truncate(
+      TaskRunner* task_runner,
+      PlatformFile file,
+      int64 length,
+      const StatusCallback& callback);
+
+  // Truncates a file to the given length. If |length| is greater than the
+  // current length of the file, the file will be extended with zeroes.
+  // The callback can be null.
+  static bool Truncate(
+      TaskRunner* task_runner,
+      const FilePath& path,
+      int64 length,
+      const StatusCallback& callback);
+
+  // Flushes a file. The callback can be null.
+  static bool Flush(
+      TaskRunner* task_runner,
+      PlatformFile file,
+      const StatusCallback& callback);
+
+  // Relay helpers.
+  static bool RelayFileTask(
+      TaskRunner* task_runner,
+      const tracked_objects::Location& from_here,
+      const FileTask& task,
+      const StatusCallback& callback);
+
+  static bool RelayCreateOrOpen(
+      TaskRunner* task_runner,
+      const CreateOrOpenTask& open_task,
+      const CloseTask& close_task,
+      const CreateOrOpenCallback& callback);
+
+  static bool RelayClose(
+      TaskRunner* task_runner,
+      const CloseTask& close_task,
+      PlatformFile,
+      const StatusCallback& callback);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtilProxy);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILE_UTIL_PROXY_H_
diff --git a/base/file_util_proxy_unittest.cc b/base/file_util_proxy_unittest.cc
new file mode 100644
index 0000000..42856c4
--- /dev/null
+++ b/base/file_util_proxy_unittest.cc
@@ -0,0 +1,410 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_util_proxy.h"
+
+#include <map>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop.h"
+#include "base/platform_file.h"
+#include "base/scoped_temp_dir.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class FileUtilProxyTest : public testing::Test {
+ public:
+  FileUtilProxyTest()
+      : message_loop_(MessageLoop::TYPE_IO),
+        file_thread_("FileUtilProxyTestFileThread"),
+        error_(PLATFORM_FILE_OK),
+        created_(false),
+        file_(kInvalidPlatformFileValue),
+        bytes_written_(-1),
+        weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
+
+  virtual void SetUp() OVERRIDE {
+    ASSERT_TRUE(dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(file_thread_.Start());
+  }
+
+  virtual void TearDown() OVERRIDE {
+    if (file_ != kInvalidPlatformFileValue)
+      ClosePlatformFile(file_);
+  }
+
+  void DidFinish(PlatformFileError error) {
+    error_ = error;
+    MessageLoop::current()->Quit();
+  }
+
+  void DidCreateOrOpen(PlatformFileError error,
+                       PassPlatformFile file,
+                       bool created) {
+    error_ = error;
+    file_ = file.ReleaseValue();
+    created_ = created;
+    MessageLoop::current()->Quit();
+  }
+
+  void DidCreateTemporary(PlatformFileError error,
+                          PassPlatformFile file,
+                          const FilePath& path) {
+    error_ = error;
+    file_ = file.ReleaseValue();
+    path_ = path;
+    MessageLoop::current()->Quit();
+  }
+
+  void DidGetFileInfo(PlatformFileError error,
+                      const PlatformFileInfo& file_info) {
+    error_ = error;
+    file_info_ = file_info;
+    MessageLoop::current()->Quit();
+  }
+
+  void DidRead(PlatformFileError error,
+               const char* data,
+               int bytes_read) {
+    error_ = error;
+    buffer_.resize(bytes_read);
+    memcpy(&buffer_[0], data, bytes_read);
+    MessageLoop::current()->Quit();
+  }
+
+  void DidWrite(PlatformFileError error,
+                int bytes_written) {
+    error_ = error;
+    bytes_written_ = bytes_written;
+    MessageLoop::current()->Quit();
+  }
+
+ protected:
+  PlatformFile GetTestPlatformFile(int flags) {
+    if (file_ != kInvalidPlatformFileValue)
+      return file_;
+    bool created;
+    PlatformFileError error;
+    file_ = CreatePlatformFile(test_path(), flags, &created, &error);
+    EXPECT_EQ(PLATFORM_FILE_OK, error);
+    EXPECT_NE(kInvalidPlatformFileValue, file_);
+    return file_;
+  }
+
+  TaskRunner* file_task_runner() const {
+    return file_thread_.message_loop_proxy().get();
+  }
+  const FilePath& test_dir_path() const { return dir_.path(); }
+  const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
+
+  MessageLoop message_loop_;
+  Thread file_thread_;
+
+  ScopedTempDir dir_;
+  PlatformFileError error_;
+  bool created_;
+  PlatformFile file_;
+  FilePath path_;
+  PlatformFileInfo file_info_;
+  std::vector<char> buffer_;
+  int bytes_written_;
+  WeakPtrFactory<FileUtilProxyTest> weak_factory_;
+};
+
+TEST_F(FileUtilProxyTest, CreateOrOpen_Create) {
+  FileUtilProxy::CreateOrOpen(
+      file_task_runner(),
+      test_path(),
+      PLATFORM_FILE_CREATE | PLATFORM_FILE_READ,
+      Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(PLATFORM_FILE_OK, error_);
+  EXPECT_TRUE(created_);
+  EXPECT_NE(kInvalidPlatformFileValue, file_);
+  EXPECT_TRUE(file_util::PathExists(test_path()));
+}
+
+TEST_F(FileUtilProxyTest, CreateOrOpen_Open) {
+  // Creates a file.
+  file_util::WriteFile(test_path(), NULL, 0);
+  ASSERT_TRUE(file_util::PathExists(test_path()));
+
+  // Opens the created file.
+  FileUtilProxy::CreateOrOpen(
+      file_task_runner(),
+      test_path(),
+      PLATFORM_FILE_OPEN | PLATFORM_FILE_READ,
+      Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(PLATFORM_FILE_OK, error_);
+  EXPECT_FALSE(created_);
+  EXPECT_NE(kInvalidPlatformFileValue, file_);
+}
+
+TEST_F(FileUtilProxyTest, CreateOrOpen_OpenNonExistent) {
+  FileUtilProxy::CreateOrOpen(
+      file_task_runner(),
+      test_path(),
+      PLATFORM_FILE_OPEN | PLATFORM_FILE_READ,
+      Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(PLATFORM_FILE_ERROR_NOT_FOUND, error_);
+  EXPECT_FALSE(created_);
+  EXPECT_EQ(kInvalidPlatformFileValue, file_);
+  EXPECT_FALSE(file_util::PathExists(test_path()));
+}
+
+TEST_F(FileUtilProxyTest, Close) {
+  // Creates a file.
+  PlatformFile file = GetTestPlatformFile(
+      PLATFORM_FILE_CREATE | PLATFORM_FILE_WRITE);
+
+#if defined(OS_WIN)
+  // This fails on Windows if the file is not closed.
+  EXPECT_FALSE(file_util::Move(test_path(),
+                               test_dir_path().AppendASCII("new")));
+#endif
+
+  FileUtilProxy::Close(
+      file_task_runner(),
+      file,
+      Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(PLATFORM_FILE_OK, error_);
+
+  // Now it should pass on all platforms.
+  EXPECT_TRUE(file_util::Move(test_path(), test_dir_path().AppendASCII("new")));
+}
+
+TEST_F(FileUtilProxyTest, CreateTemporary) {
+  FileUtilProxy::CreateTemporary(
+      file_task_runner(), 0 /* additional_file_flags */,
+      Bind(&FileUtilProxyTest::DidCreateTemporary, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(PLATFORM_FILE_OK, error_);
+  EXPECT_TRUE(file_util::PathExists(path_));
+  EXPECT_NE(kInvalidPlatformFileValue, file_);
+
+  // The file should be writable.
+#if defined(OS_WIN)
+   HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+   OVERLAPPED overlapped = {0};
+   overlapped.hEvent = hEvent;
+   DWORD bytes_written;
+   if (!::WriteFile(file_, "test", 4, &bytes_written, &overlapped)) {
+     // Temporary file is created with ASYNC flag, so WriteFile may return 0
+     // with ERROR_IO_PENDING.
+     EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
+     GetOverlappedResult(file_, &overlapped, &bytes_written, TRUE);
+   }
+   EXPECT_EQ(4, bytes_written);
+#else
+  // On POSIX ASYNC flag does not affect synchronous read/write behavior.
+  EXPECT_EQ(4, WritePlatformFile(file_, 0, "test", 4));
+#endif
+  EXPECT_TRUE(ClosePlatformFile(file_));
+  file_ = kInvalidPlatformFileValue;
+
+  // Make sure the written data can be read from the returned path.
+  std::string data;
+  EXPECT_TRUE(file_util::ReadFileToString(path_, &data));
+  EXPECT_EQ("test", data);
+
+  // Make sure we can & do delete the created file to prevent leaks on the bots.
+  EXPECT_TRUE(file_util::Delete(path_, false));
+}
+
+TEST_F(FileUtilProxyTest, GetFileInfo_File) {
+  // Setup.
+  ASSERT_EQ(4, file_util::WriteFile(test_path(), "test", 4));
+  PlatformFileInfo expected_info;
+  file_util::GetFileInfo(test_path(), &expected_info);
+
+  // Run.
+  FileUtilProxy::GetFileInfo(
+      file_task_runner(),
+      test_path(),
+      Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(PLATFORM_FILE_OK, error_);
+  EXPECT_EQ(expected_info.size, file_info_.size);
+  EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
+  EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
+  EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
+  EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed);
+  EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
+}
+
+TEST_F(FileUtilProxyTest, GetFileInfo_Directory) {
+  // Setup.
+  ASSERT_TRUE(file_util::CreateDirectory(test_path()));
+  PlatformFileInfo expected_info;
+  file_util::GetFileInfo(test_path(), &expected_info);
+
+  // Run.
+  FileUtilProxy::GetFileInfo(
+      file_task_runner(),
+      test_path(),
+      Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(PLATFORM_FILE_OK, error_);
+  EXPECT_EQ(expected_info.size, file_info_.size);
+  EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
+  EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
+  EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
+  EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed);
+  EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
+}
+
+TEST_F(FileUtilProxyTest, Read) {
+  // Setup.
+  const char expected_data[] = "bleh";
+  int expected_bytes = arraysize(expected_data);
+  ASSERT_EQ(expected_bytes,
+            file_util::WriteFile(test_path(), expected_data, expected_bytes));
+
+  // Run.
+  FileUtilProxy::Read(
+      file_task_runner(),
+      GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_READ),
+      0,  // offset
+      128,
+      Bind(&FileUtilProxyTest::DidRead, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(PLATFORM_FILE_OK, error_);
+  EXPECT_EQ(expected_bytes, static_cast<int>(buffer_.size()));
+  for (size_t i = 0; i < buffer_.size(); ++i) {
+    EXPECT_EQ(expected_data[i], buffer_[i]);
+  }
+}
+
+TEST_F(FileUtilProxyTest, WriteAndFlush) {
+  const char data[] = "foo!";
+  int data_bytes = ARRAYSIZE_UNSAFE(data);
+  PlatformFile file = GetTestPlatformFile(
+      PLATFORM_FILE_CREATE | PLATFORM_FILE_WRITE);
+
+  FileUtilProxy::Write(
+      file_task_runner(),
+      file,
+      0,  // offset
+      data,
+      data_bytes,
+      Bind(&FileUtilProxyTest::DidWrite, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(PLATFORM_FILE_OK, error_);
+  EXPECT_EQ(data_bytes, bytes_written_);
+
+  // Flush the written data.  (So that the following read should always
+  // succeed.  On some platforms it may work with or without this flush.)
+  FileUtilProxy::Flush(
+      file_task_runner(),
+      file,
+      Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(PLATFORM_FILE_OK, error_);
+
+  // Verify the written data.
+  char buffer[10];
+  EXPECT_EQ(data_bytes, file_util::ReadFile(test_path(), buffer, data_bytes));
+  for (int i = 0; i < data_bytes; ++i) {
+    EXPECT_EQ(data[i], buffer[i]);
+  }
+}
+
+TEST_F(FileUtilProxyTest, Touch) {
+  Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345);
+  Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765);
+
+  FileUtilProxy::Touch(
+      file_task_runner(),
+      GetTestPlatformFile(PLATFORM_FILE_CREATE |
+                          PLATFORM_FILE_WRITE |
+                          PLATFORM_FILE_WRITE_ATTRIBUTES),
+      last_accessed_time,
+      last_modified_time,
+      Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(PLATFORM_FILE_OK, error_);
+
+  PlatformFileInfo info;
+  file_util::GetFileInfo(test_path(), &info);
+
+  // The returned values may only have the seconds precision, so we cast
+  // the double values to int here.
+  EXPECT_EQ(static_cast<int>(last_modified_time.ToDoubleT()),
+            static_cast<int>(info.last_modified.ToDoubleT()));
+  EXPECT_EQ(static_cast<int>(last_accessed_time.ToDoubleT()),
+            static_cast<int>(info.last_accessed.ToDoubleT()));
+}
+
+TEST_F(FileUtilProxyTest, Truncate_Shrink) {
+  // Setup.
+  const char kTestData[] = "0123456789";
+  ASSERT_EQ(10, file_util::WriteFile(test_path(), kTestData, 10));
+  PlatformFileInfo info;
+  file_util::GetFileInfo(test_path(), &info);
+  ASSERT_EQ(10, info.size);
+
+  // Run.
+  FileUtilProxy::Truncate(
+      file_task_runner(),
+      GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE),
+      7,
+      Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  file_util::GetFileInfo(test_path(), &info);
+  ASSERT_EQ(7, info.size);
+
+  char buffer[7];
+  EXPECT_EQ(7, file_util::ReadFile(test_path(), buffer, 7));
+  int i = 0;
+  for (; i < 7; ++i)
+    EXPECT_EQ(kTestData[i], buffer[i]);
+}
+
+TEST_F(FileUtilProxyTest, Truncate_Expand) {
+  // Setup.
+  const char kTestData[] = "9876543210";
+  ASSERT_EQ(10, file_util::WriteFile(test_path(), kTestData, 10));
+  PlatformFileInfo info;
+  file_util::GetFileInfo(test_path(), &info);
+  ASSERT_EQ(10, info.size);
+
+  // Run.
+  FileUtilProxy::Truncate(
+      file_task_runner(),
+      GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE),
+      53,
+      Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  file_util::GetFileInfo(test_path(), &info);
+  ASSERT_EQ(53, info.size);
+
+  char buffer[53];
+  EXPECT_EQ(53, file_util::ReadFile(test_path(), buffer, 53));
+  int i = 0;
+  for (; i < 10; ++i)
+    EXPECT_EQ(kTestData[i], buffer[i]);
+  for (; i < 53; ++i)
+    EXPECT_EQ(0, buffer[i]);
+}
+
+}  // namespace base
diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc
new file mode 100644
index 0000000..04de367
--- /dev/null
+++ b/base/file_util_unittest.cc
@@ -0,0 +1,2398 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <tchar.h>
+#include <winioctl.h>
+#endif
+
+#include <algorithm>
+#include <fstream>
+#include <set>
+
+#include "base/base_paths.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/scoped_temp_dir.h"
+#include "base/threading/platform_thread.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+// This macro helps avoid wrapped lines in the test structs.
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+namespace {
+
+// To test that file_util::Normalize FilePath() deals with NTFS reparse points
+// correctly, we need functions to create and delete reparse points.
+#if defined(OS_WIN)
+typedef struct _REPARSE_DATA_BUFFER {
+  ULONG  ReparseTag;
+  USHORT  ReparseDataLength;
+  USHORT  Reserved;
+  union {
+    struct {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      ULONG Flags;
+      WCHAR PathBuffer[1];
+    } SymbolicLinkReparseBuffer;
+    struct {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      WCHAR PathBuffer[1];
+    } MountPointReparseBuffer;
+    struct {
+      UCHAR DataBuffer[1];
+    } GenericReparseBuffer;
+  };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
+// Sets a reparse point. |source| will now point to |target|. Returns true if
+// the call succeeds, false otherwise.
+bool SetReparsePoint(HANDLE source, const FilePath& target_path) {
+  std::wstring kPathPrefix = L"\\??\\";
+  std::wstring target_str;
+  // The juction will not work if the target path does not start with \??\ .
+  if (kPathPrefix != target_path.value().substr(0, kPathPrefix.size()))
+    target_str += kPathPrefix;
+  target_str += target_path.value();
+  const wchar_t* target = target_str.c_str();
+  USHORT size_target = static_cast<USHORT>(wcslen(target)) * sizeof(target[0]);
+  char buffer[2000] = {0};
+  DWORD returned;
+
+  REPARSE_DATA_BUFFER* data = reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer);
+
+  data->ReparseTag = 0xa0000003;
+  memcpy(data->MountPointReparseBuffer.PathBuffer, target, size_target + 2);
+
+  data->MountPointReparseBuffer.SubstituteNameLength = size_target;
+  data->MountPointReparseBuffer.PrintNameOffset = size_target + 2;
+  data->ReparseDataLength = size_target + 4 + 8;
+
+  int data_size = data->ReparseDataLength + 8;
+
+  if (!DeviceIoControl(source, FSCTL_SET_REPARSE_POINT, &buffer, data_size,
+                       NULL, 0, &returned, NULL)) {
+    return false;
+  }
+  return true;
+}
+
+// Delete the reparse point referenced by |source|. Returns true if the call
+// succeeds, false otherwise.
+bool DeleteReparsePoint(HANDLE source) {
+  DWORD returned;
+  REPARSE_DATA_BUFFER data = {0};
+  data.ReparseTag = 0xa0000003;
+  if (!DeviceIoControl(source, FSCTL_DELETE_REPARSE_POINT, &data, 8, NULL, 0,
+                       &returned, NULL)) {
+    return false;
+  }
+  return true;
+}
+#endif
+
+#if defined(OS_POSIX)
+// Provide a simple way to change the permissions bits on |path| in tests.
+// ASSERT failures will return, but not stop the test.  Caller should wrap
+// calls to this function in ASSERT_NO_FATAL_FAILURE().
+void ChangePosixFilePermissions(const FilePath& path,
+                                int mode_bits_to_set,
+                                int mode_bits_to_clear) {
+  ASSERT_FALSE(mode_bits_to_set & mode_bits_to_clear)
+      << "Can't set and clear the same bits.";
+
+  int mode = 0;
+  ASSERT_TRUE(file_util::GetPosixFilePermissions(path, &mode));
+  mode |= mode_bits_to_set;
+  mode &= ~mode_bits_to_clear;
+  ASSERT_TRUE(file_util::SetPosixFilePermissions(path, mode));
+}
+#endif  // defined(OS_POSIX)
+
+const wchar_t bogus_content[] = L"I'm cannon fodder.";
+
+const int FILES_AND_DIRECTORIES =
+    file_util::FileEnumerator::FILES | file_util::FileEnumerator::DIRECTORIES;
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest
+class FileUtilTest : public PlatformTest {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    PlatformTest::SetUp();
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  }
+
+  ScopedTempDir temp_dir_;
+};
+
+// Collects all the results from the given file enumerator, and provides an
+// interface to query whether a given file is present.
+class FindResultCollector {
+ public:
+  explicit FindResultCollector(file_util::FileEnumerator& enumerator) {
+    FilePath cur_file;
+    while (!(cur_file = enumerator.Next()).value().empty()) {
+      FilePath::StringType path = cur_file.value();
+      // The file should not be returned twice.
+      EXPECT_TRUE(files_.end() == files_.find(path))
+          << "Same file returned twice";
+
+      // Save for later.
+      files_.insert(path);
+    }
+  }
+
+  // Returns true if the enumerator found the file.
+  bool HasFile(const FilePath& file) const {
+    return files_.find(file.value()) != files_.end();
+  }
+
+  int size() {
+    return static_cast<int>(files_.size());
+  }
+
+ private:
+  std::set<FilePath::StringType> files_;
+};
+
+// Simple function to dump some text into a new file.
+void CreateTextFile(const FilePath& filename,
+                    const std::wstring& contents) {
+  std::wofstream file;
+  file.open(filename.value().c_str());
+  ASSERT_TRUE(file.is_open());
+  file << contents;
+  file.close();
+}
+
+// Simple function to take out some text from a file.
+std::wstring ReadTextFile(const FilePath& filename) {
+  wchar_t contents[64];
+  std::wifstream file;
+  file.open(filename.value().c_str());
+  EXPECT_TRUE(file.is_open());
+  file.getline(contents, arraysize(contents));
+  file.close();
+  return std::wstring(contents);
+}
+
+#if defined(OS_WIN)
+uint64 FileTimeAsUint64(const FILETIME& ft) {
+  ULARGE_INTEGER u;
+  u.LowPart = ft.dwLowDateTime;
+  u.HighPart = ft.dwHighDateTime;
+  return u.QuadPart;
+}
+#endif
+
+const struct append_case {
+  const wchar_t* path;
+  const wchar_t* ending;
+  const wchar_t* result;
+} append_cases[] = {
+#if defined(OS_WIN)
+  {L"c:\\colon\\backslash", L"path", L"c:\\colon\\backslash\\path"},
+  {L"c:\\colon\\backslash\\", L"path", L"c:\\colon\\backslash\\path"},
+  {L"c:\\colon\\backslash\\\\", L"path", L"c:\\colon\\backslash\\\\path"},
+  {L"c:\\colon\\backslash\\", L"", L"c:\\colon\\backslash\\"},
+  {L"c:\\colon\\backslash", L"", L"c:\\colon\\backslash\\"},
+  {L"", L"path", L"\\path"},
+  {L"", L"", L"\\"},
+#elif defined(OS_POSIX)
+  {L"/foo/bar", L"path", L"/foo/bar/path"},
+  {L"/foo/bar/", L"path", L"/foo/bar/path"},
+  {L"/foo/bar//", L"path", L"/foo/bar//path"},
+  {L"/foo/bar/", L"", L"/foo/bar/"},
+  {L"/foo/bar", L"", L"/foo/bar/"},
+  {L"", L"path", L"/path"},
+  {L"", L"", L"/"},
+#endif
+};
+
+static const struct filename_case {
+  const wchar_t* path;
+  const wchar_t* filename;
+} filename_cases[] = {
+#if defined(OS_WIN)
+  {L"c:\\colon\\backslash", L"backslash"},
+  {L"c:\\colon\\backslash\\", L""},
+  {L"\\\\filename.exe", L"filename.exe"},
+  {L"filename.exe", L"filename.exe"},
+  {L"", L""},
+  {L"\\\\\\", L""},
+  {L"c:/colon/backslash", L"backslash"},
+  {L"c:/colon/backslash/", L""},
+  {L"//////", L""},
+  {L"///filename.exe", L"filename.exe"},
+#elif defined(OS_POSIX)
+  {L"/foo/bar", L"bar"},
+  {L"/foo/bar/", L""},
+  {L"/filename.exe", L"filename.exe"},
+  {L"filename.exe", L"filename.exe"},
+  {L"", L""},
+  {L"/", L""},
+#endif
+};
+
+// Test finding the file type from a path name
+static const struct extension_case {
+  const wchar_t* path;
+  const wchar_t* extension;
+} extension_cases[] = {
+#if defined(OS_WIN)
+  {L"C:\\colon\\backslash\\filename.extension", L"extension"},
+  {L"C:\\colon\\backslash\\filename.", L""},
+  {L"C:\\colon\\backslash\\filename", L""},
+  {L"C:\\colon\\backslash\\", L""},
+  {L"C:\\colon\\backslash.\\", L""},
+  {L"C:\\colon\\backslash\filename.extension.extension2", L"extension2"},
+#elif defined(OS_POSIX)
+  {L"/foo/bar/filename.extension", L"extension"},
+  {L"/foo/bar/filename.", L""},
+  {L"/foo/bar/filename", L""},
+  {L"/foo/bar/", L""},
+  {L"/foo/bar./", L""},
+  {L"/foo/bar/filename.extension.extension2", L"extension2"},
+  {L".", L""},
+  {L"..", L""},
+  {L"./foo", L""},
+  {L"./foo.extension", L"extension"},
+  {L"/foo.extension1/bar.extension2", L"extension2"},
+#endif
+};
+
+// Test finding the directory component of a path
+static const struct dir_case {
+  const wchar_t* full_path;
+  const wchar_t* directory;
+} dir_cases[] = {
+#if defined(OS_WIN)
+  {L"C:\\WINDOWS\\system32\\gdi32.dll", L"C:\\WINDOWS\\system32"},
+  {L"C:\\WINDOWS\\system32\\not_exist_thx_1138", L"C:\\WINDOWS\\system32"},
+  {L"C:\\WINDOWS\\system32\\", L"C:\\WINDOWS\\system32"},
+  {L"C:\\WINDOWS\\system32\\\\", L"C:\\WINDOWS\\system32"},
+  {L"C:\\WINDOWS\\system32", L"C:\\WINDOWS"},
+  {L"C:\\WINDOWS\\system32.\\", L"C:\\WINDOWS\\system32."},
+  {L"C:\\", L"C:\\"},
+#elif defined(OS_POSIX)
+  {L"/foo/bar/gdi32.dll", L"/foo/bar"},
+  {L"/foo/bar/not_exist_thx_1138", L"/foo/bar"},
+  {L"/foo/bar/", L"/foo/bar"},
+  {L"/foo/bar//", L"/foo/bar"},
+  {L"/foo/bar", L"/foo"},
+  {L"/foo/bar./", L"/foo/bar."},
+  {L"/", L"/"},
+  {L".", L"."},
+  {L"..", L"."},  // yes, ".." technically lives in "."
+#endif
+};
+
+TEST_F(FileUtilTest, CountFilesCreatedAfter) {
+  FilePath file_name =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("f.txt"));
+  CreateTextFile(file_name, L"test");
+
+  base::PlatformFileInfo info;
+  file_util::GetFileInfo(file_name, &info);
+  base::Time file_time = info.creation_time;
+
+  base::TimeDelta two_secs = base::TimeDelta::FromSeconds(2);
+  base::Time after = file_time + two_secs;
+  EXPECT_EQ(0, file_util::CountFilesCreatedAfter(temp_dir_.path(), after));
+
+  base::Time before = file_time - two_secs;
+  EXPECT_EQ(1, file_util::CountFilesCreatedAfter(temp_dir_.path(), before));
+
+  // After deleting the file, shouldn't find it any more.
+  EXPECT_TRUE(file_util::Delete(file_name, false));
+  EXPECT_EQ(0, file_util::CountFilesCreatedAfter(temp_dir_.path(), before));
+  EXPECT_EQ(0, file_util::CountFilesCreatedAfter(temp_dir_.path(), after));
+}
+
+TEST_F(FileUtilTest, FileAndDirectorySize) {
+  // Create three files of 20, 30 and 3 chars (utf8). ComputeDirectorySize
+  // should return 53 bytes.
+  FilePath file_01 = temp_dir_.path().Append(FPL("The file 01.txt"));
+  CreateTextFile(file_01, L"12345678901234567890");
+  int64 size_f1 = 0;
+  ASSERT_TRUE(file_util::GetFileSize(file_01, &size_f1));
+  EXPECT_EQ(20ll, size_f1);
+
+  FilePath subdir_path = temp_dir_.path().Append(FPL("Level2"));
+  file_util::CreateDirectory(subdir_path);
+
+  FilePath file_02 = subdir_path.Append(FPL("The file 02.txt"));
+  CreateTextFile(file_02, L"123456789012345678901234567890");
+  int64 size_f2 = 0;
+  ASSERT_TRUE(file_util::GetFileSize(file_02, &size_f2));
+  EXPECT_EQ(30ll, size_f2);
+
+  FilePath subsubdir_path = subdir_path.Append(FPL("Level3"));
+  file_util::CreateDirectory(subsubdir_path);
+
+  FilePath file_03 = subsubdir_path.Append(FPL("The file 03.txt"));
+  CreateTextFile(file_03, L"123");
+
+  int64 computed_size = file_util::ComputeDirectorySize(temp_dir_.path());
+  EXPECT_EQ(size_f1 + size_f2 + 3, computed_size);
+
+  computed_size =
+      file_util::ComputeFilesSize(temp_dir_.path(), FPL("The file*"));
+  EXPECT_EQ(size_f1, computed_size);
+
+  computed_size = file_util::ComputeFilesSize(temp_dir_.path(), FPL("bla*"));
+  EXPECT_EQ(0, computed_size);
+}
+
+TEST_F(FileUtilTest, NormalizeFilePathBasic) {
+  // Create a directory under the test dir.  Because we create it,
+  // we know it is not a link.
+  FilePath file_a_path = temp_dir_.path().Append(FPL("file_a"));
+  FilePath dir_path = temp_dir_.path().Append(FPL("dir"));
+  FilePath file_b_path = dir_path.Append(FPL("file_b"));
+  file_util::CreateDirectory(dir_path);
+
+  FilePath normalized_file_a_path, normalized_file_b_path;
+  ASSERT_FALSE(file_util::PathExists(file_a_path));
+  ASSERT_FALSE(file_util::NormalizeFilePath(file_a_path,
+                                            &normalized_file_a_path))
+    << "NormalizeFilePath() should fail on nonexistent paths.";
+
+  CreateTextFile(file_a_path, bogus_content);
+  ASSERT_TRUE(file_util::PathExists(file_a_path));
+  ASSERT_TRUE(file_util::NormalizeFilePath(file_a_path,
+                                           &normalized_file_a_path));
+
+  CreateTextFile(file_b_path, bogus_content);
+  ASSERT_TRUE(file_util::PathExists(file_b_path));
+  ASSERT_TRUE(file_util::NormalizeFilePath(file_b_path,
+                                           &normalized_file_b_path));
+
+  // Beacuse this test created |dir_path|, we know it is not a link
+  // or junction.  So, the real path of the directory holding file a
+  // must be the parent of the path holding file b.
+  ASSERT_TRUE(normalized_file_a_path.DirName()
+      .IsParent(normalized_file_b_path.DirName()));
+}
+
+#if defined(OS_WIN)
+
+TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
+  // Build the following directory structure:
+  //
+  // temp_dir
+  // |-> base_a
+  // |   |-> sub_a
+  // |       |-> file.txt
+  // |       |-> long_name___... (Very long name.)
+  // |           |-> sub_long
+  // |              |-> deep.txt
+  // |-> base_b
+  //     |-> to_sub_a (reparse point to temp_dir\base_a\sub_a)
+  //     |-> to_base_b (reparse point to temp_dir\base_b)
+  //     |-> to_sub_long (reparse point to temp_dir\sub_a\long_name_\sub_long)
+
+  FilePath base_a = temp_dir_.path().Append(FPL("base_a"));
+  ASSERT_TRUE(file_util::CreateDirectory(base_a));
+
+  FilePath sub_a = base_a.Append(FPL("sub_a"));
+  ASSERT_TRUE(file_util::CreateDirectory(sub_a));
+
+  FilePath file_txt = sub_a.Append(FPL("file.txt"));
+  CreateTextFile(file_txt, bogus_content);
+
+  // Want a directory whose name is long enough to make the path to the file
+  // inside just under MAX_PATH chars.  This will be used to test that when
+  // a junction expands to a path over MAX_PATH chars in length,
+  // NormalizeFilePath() fails without crashing.
+  FilePath sub_long_rel(FPL("sub_long"));
+  FilePath deep_txt(FPL("deep.txt"));
+
+  int target_length = MAX_PATH;
+  target_length -= (sub_a.value().length() + 1);  // +1 for the sepperator '\'.
+  target_length -= (sub_long_rel.Append(deep_txt).value().length() + 1);
+  // Without making the path a bit shorter, CreateDirectory() fails.
+  // the resulting path is still long enough to hit the failing case in
+  // NormalizePath().
+  const int kCreateDirLimit = 4;
+  target_length -= kCreateDirLimit;
+  FilePath::StringType long_name_str = FPL("long_name_");
+  long_name_str.resize(target_length, '_');
+
+  FilePath long_name = sub_a.Append(FilePath(long_name_str));
+  FilePath deep_file = long_name.Append(sub_long_rel).Append(deep_txt);
+  ASSERT_EQ(MAX_PATH - kCreateDirLimit, deep_file.value().length());
+
+  FilePath sub_long = deep_file.DirName();
+  ASSERT_TRUE(file_util::CreateDirectory(sub_long));
+  CreateTextFile(deep_file, bogus_content);
+
+  FilePath base_b = temp_dir_.path().Append(FPL("base_b"));
+  ASSERT_TRUE(file_util::CreateDirectory(base_b));
+
+  FilePath to_sub_a = base_b.Append(FPL("to_sub_a"));
+  ASSERT_TRUE(file_util::CreateDirectory(to_sub_a));
+  base::win::ScopedHandle reparse_to_sub_a(
+      ::CreateFile(to_sub_a.value().c_str(),
+                   FILE_ALL_ACCESS,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
+                   NULL));
+  ASSERT_TRUE(reparse_to_sub_a.IsValid());
+  ASSERT_TRUE(SetReparsePoint(reparse_to_sub_a, sub_a));
+
+  FilePath to_base_b = base_b.Append(FPL("to_base_b"));
+  ASSERT_TRUE(file_util::CreateDirectory(to_base_b));
+  base::win::ScopedHandle reparse_to_base_b(
+      ::CreateFile(to_base_b.value().c_str(),
+                   FILE_ALL_ACCESS,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
+                   NULL));
+  ASSERT_TRUE(reparse_to_base_b.IsValid());
+  ASSERT_TRUE(SetReparsePoint(reparse_to_base_b, base_b));
+
+  FilePath to_sub_long = base_b.Append(FPL("to_sub_long"));
+  ASSERT_TRUE(file_util::CreateDirectory(to_sub_long));
+  base::win::ScopedHandle reparse_to_sub_long(
+      ::CreateFile(to_sub_long.value().c_str(),
+                   FILE_ALL_ACCESS,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
+                   NULL));
+  ASSERT_TRUE(reparse_to_sub_long.IsValid());
+  ASSERT_TRUE(SetReparsePoint(reparse_to_sub_long, sub_long));
+
+  // Normalize a junction free path: base_a\sub_a\file.txt .
+  FilePath normalized_path;
+  ASSERT_TRUE(file_util::NormalizeFilePath(file_txt, &normalized_path));
+  ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+  // Check that the path base_b\to_sub_a\file.txt can be normalized to exclude
+  // the junction to_sub_a.
+  ASSERT_TRUE(file_util::NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
+                                           &normalized_path));
+  ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+  // Check that the path base_b\to_base_b\to_base_b\to_sub_a\file.txt can be
+  // normalized to exclude junctions to_base_b and to_sub_a .
+  ASSERT_TRUE(file_util::NormalizeFilePath(base_b.Append(FPL("to_base_b"))
+                                                 .Append(FPL("to_base_b"))
+                                                 .Append(FPL("to_sub_a"))
+                                                 .Append(FPL("file.txt")),
+                                           &normalized_path));
+  ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+  // A long enough path will cause NormalizeFilePath() to fail.  Make a long
+  // path using to_base_b many times, and check that paths long enough to fail
+  // do not cause a crash.
+  FilePath long_path = base_b;
+  const int kLengthLimit = MAX_PATH + 200;
+  while (long_path.value().length() <= kLengthLimit) {
+    long_path = long_path.Append(FPL("to_base_b"));
+  }
+  long_path = long_path.Append(FPL("to_sub_a"))
+                       .Append(FPL("file.txt"));
+
+  ASSERT_FALSE(file_util::NormalizeFilePath(long_path, &normalized_path));
+
+  // Normalizing the junction to deep.txt should fail, because the expanded
+  // path to deep.txt is longer than MAX_PATH.
+  ASSERT_FALSE(file_util::NormalizeFilePath(to_sub_long.Append(deep_txt),
+                                            &normalized_path));
+
+  // Delete the reparse points, and see that NormalizeFilePath() fails
+  // to traverse them.
+  ASSERT_TRUE(DeleteReparsePoint(reparse_to_sub_a));
+  ASSERT_TRUE(DeleteReparsePoint(reparse_to_base_b));
+  ASSERT_TRUE(DeleteReparsePoint(reparse_to_sub_long));
+
+  ASSERT_FALSE(file_util::NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
+                                            &normalized_path));
+}
+
+TEST_F(FileUtilTest, DevicePathToDriveLetter) {
+  // Get a drive letter.
+  std::wstring real_drive_letter = temp_dir_.path().value().substr(0, 2);
+  if (!isalpha(real_drive_letter[0]) || ':' != real_drive_letter[1]) {
+    LOG(ERROR) << "Can't get a drive letter to test with.";
+    return;
+  }
+
+  // Get the NT style path to that drive.
+  wchar_t device_path[MAX_PATH] = {'\0'};
+  ASSERT_TRUE(
+      ::QueryDosDevice(real_drive_letter.c_str(), device_path, MAX_PATH));
+  FilePath actual_device_path(device_path);
+  FilePath win32_path;
+
+  // Run DevicePathToDriveLetterPath() on the NT style path we got from
+  // QueryDosDevice().  Expect the drive letter we started with.
+  ASSERT_TRUE(file_util::DevicePathToDriveLetterPath(actual_device_path,
+                                                     &win32_path));
+  ASSERT_EQ(real_drive_letter, win32_path.value());
+
+  // Add some directories to the path.  Expect those extra path componenets
+  // to be preserved.
+  FilePath kRelativePath(FPL("dir1\\dir2\\file.txt"));
+  ASSERT_TRUE(file_util::DevicePathToDriveLetterPath(
+      actual_device_path.Append(kRelativePath),
+      &win32_path));
+  EXPECT_EQ(FilePath(real_drive_letter + L"\\").Append(kRelativePath).value(),
+            win32_path.value());
+
+  // Deform the real path so that it is invalid by removing the last four
+  // characters.  The way windows names devices that are hard disks
+  // (\Device\HardDiskVolume${NUMBER}) guarantees that the string is longer
+  // than three characters.  The only way the truncated string could be a
+  // real drive is if more than 10^3 disks are mounted:
+  // \Device\HardDiskVolume10000 would be truncated to \Device\HardDiskVolume1
+  // Check that DevicePathToDriveLetterPath fails.
+  int path_length = actual_device_path.value().length();
+  int new_length = path_length - 4;
+  ASSERT_LT(0, new_length);
+  FilePath prefix_of_real_device_path(
+      actual_device_path.value().substr(0, new_length));
+  ASSERT_FALSE(file_util::DevicePathToDriveLetterPath(
+      prefix_of_real_device_path,
+      &win32_path));
+
+  ASSERT_FALSE(file_util::DevicePathToDriveLetterPath(
+      prefix_of_real_device_path.Append(kRelativePath),
+      &win32_path));
+
+  // Deform the real path so that it is invalid by adding some characters. For
+  // example, if C: maps to \Device\HardDiskVolume8, then we simulate a
+  // request for the drive letter whose native path is
+  // \Device\HardDiskVolume812345 .  We assume such a device does not exist,
+  // because drives are numbered in order and mounting 112345 hard disks will
+  // never happen.
+  const FilePath::StringType kExtraChars = FPL("12345");
+
+  FilePath real_device_path_plus_numbers(
+      actual_device_path.value() + kExtraChars);
+
+  ASSERT_FALSE(file_util::DevicePathToDriveLetterPath(
+      real_device_path_plus_numbers,
+      &win32_path));
+
+  ASSERT_FALSE(file_util::DevicePathToDriveLetterPath(
+      real_device_path_plus_numbers.Append(kRelativePath),
+      &win32_path));
+}
+
+TEST_F(FileUtilTest, GetPlatformFileInfoForDirectory) {
+  FilePath empty_dir = temp_dir_.path().Append(FPL("gpfi_test"));
+  ASSERT_TRUE(file_util::CreateDirectory(empty_dir));
+  base::win::ScopedHandle dir(
+      ::CreateFile(empty_dir.value().c_str(),
+                   FILE_ALL_ACCESS,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
+                   NULL));
+  ASSERT_TRUE(dir.IsValid());
+  base::PlatformFileInfo info;
+  EXPECT_TRUE(base::GetPlatformFileInfo(dir.Get(), &info));
+  EXPECT_TRUE(info.is_directory);
+  EXPECT_FALSE(info.is_symbolic_link);
+  EXPECT_EQ(0, info.size);
+}
+
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX)
+
+TEST_F(FileUtilTest, CreateAndReadSymlinks) {
+  FilePath link_from = temp_dir_.path().Append(FPL("from_file"));
+  FilePath link_to = temp_dir_.path().Append(FPL("to_file"));
+  CreateTextFile(link_to, bogus_content);
+
+  ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from))
+    << "Failed to create file symlink.";
+
+  // If we created the link properly, we should be able to read the
+  // contents through it.
+  std::wstring contents = ReadTextFile(link_from);
+  ASSERT_EQ(contents, bogus_content);
+
+  FilePath result;
+  ASSERT_TRUE(file_util::ReadSymbolicLink(link_from, &result));
+  ASSERT_EQ(link_to.value(), result.value());
+
+  // Link to a directory.
+  link_from = temp_dir_.path().Append(FPL("from_dir"));
+  link_to = temp_dir_.path().Append(FPL("to_dir"));
+  file_util::CreateDirectory(link_to);
+
+  ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from))
+    << "Failed to create directory symlink.";
+
+  // Test failures.
+  ASSERT_FALSE(file_util::CreateSymbolicLink(link_to, link_to));
+  ASSERT_FALSE(file_util::ReadSymbolicLink(link_to, &result));
+  FilePath missing = temp_dir_.path().Append(FPL("missing"));
+  ASSERT_FALSE(file_util::ReadSymbolicLink(missing, &result));
+}
+
+// The following test of NormalizeFilePath() require that we create a symlink.
+// This can not be done on Windows before Vista.  On Vista, creating a symlink
+// requires privilege "SeCreateSymbolicLinkPrivilege".
+// TODO(skerner): Investigate the possibility of giving base_unittests the
+// privileges required to create a symlink.
+TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
+  FilePath normalized_path;
+
+  // Link one file to another.
+  FilePath link_from = temp_dir_.path().Append(FPL("from_file"));
+  FilePath link_to = temp_dir_.path().Append(FPL("to_file"));
+  CreateTextFile(link_to, bogus_content);
+
+  ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from))
+    << "Failed to create file symlink.";
+
+  // Check that NormalizeFilePath sees the link.
+  ASSERT_TRUE(file_util::NormalizeFilePath(link_from, &normalized_path));
+  ASSERT_TRUE(link_to != link_from);
+  ASSERT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value());
+  ASSERT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value());
+
+  // Link to a directory.
+  link_from = temp_dir_.path().Append(FPL("from_dir"));
+  link_to = temp_dir_.path().Append(FPL("to_dir"));
+  file_util::CreateDirectory(link_to);
+
+  ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from))
+    << "Failed to create directory symlink.";
+
+  ASSERT_FALSE(file_util::NormalizeFilePath(link_from, &normalized_path))
+    << "Links to directories should return false.";
+
+  // Test that a loop in the links causes NormalizeFilePath() to return false.
+  link_from = temp_dir_.path().Append(FPL("link_a"));
+  link_to = temp_dir_.path().Append(FPL("link_b"));
+  ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from))
+    << "Failed to create loop symlink a.";
+  ASSERT_TRUE(file_util::CreateSymbolicLink(link_from, link_to))
+    << "Failed to create loop symlink b.";
+
+  // Infinite loop!
+  ASSERT_FALSE(file_util::NormalizeFilePath(link_from, &normalized_path));
+}
+#endif  // defined(OS_POSIX)
+
+TEST_F(FileUtilTest, DeleteNonExistent) {
+  FilePath non_existent = temp_dir_.path().AppendASCII("bogus_file_dne.foobar");
+  ASSERT_FALSE(file_util::PathExists(non_existent));
+
+  EXPECT_TRUE(file_util::Delete(non_existent, false));
+  ASSERT_FALSE(file_util::PathExists(non_existent));
+  EXPECT_TRUE(file_util::Delete(non_existent, true));
+  ASSERT_FALSE(file_util::PathExists(non_existent));
+}
+
+TEST_F(FileUtilTest, DeleteFile) {
+  // Create a file
+  FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteFile 1.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(file_util::PathExists(file_name));
+
+  // Make sure it's deleted
+  EXPECT_TRUE(file_util::Delete(file_name, false));
+  EXPECT_FALSE(file_util::PathExists(file_name));
+
+  // Test recursive case, create a new file
+  file_name = temp_dir_.path().Append(FPL("Test DeleteFile 2.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(file_util::PathExists(file_name));
+
+  // Make sure it's deleted
+  EXPECT_TRUE(file_util::Delete(file_name, true));
+  EXPECT_FALSE(file_util::PathExists(file_name));
+}
+
+#if defined(OS_POSIX)
+TEST_F(FileUtilTest, DeleteSymlinkToExistentFile) {
+  // Create a file.
+  FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteFile 2.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(file_util::PathExists(file_name));
+
+  // Create a symlink to the file.
+  FilePath file_link = temp_dir_.path().Append("file_link_2");
+  ASSERT_TRUE(file_util::CreateSymbolicLink(file_name, file_link))
+      << "Failed to create symlink.";
+
+  // Delete the symbolic link.
+  EXPECT_TRUE(file_util::Delete(file_link, false));
+
+  // Make sure original file is not deleted.
+  EXPECT_FALSE(file_util::PathExists(file_link));
+  EXPECT_TRUE(file_util::PathExists(file_name));
+}
+
+TEST_F(FileUtilTest, DeleteSymlinkToNonExistentFile) {
+  // Create a non-existent file path.
+  FilePath non_existent = temp_dir_.path().Append(FPL("Test DeleteFile 3.txt"));
+  EXPECT_FALSE(file_util::PathExists(non_existent));
+
+  // Create a symlink to the non-existent file.
+  FilePath file_link = temp_dir_.path().Append("file_link_3");
+  ASSERT_TRUE(file_util::CreateSymbolicLink(non_existent, file_link))
+      << "Failed to create symlink.";
+
+  // Make sure the symbolic link is exist.
+  EXPECT_TRUE(file_util::IsLink(file_link));
+  EXPECT_FALSE(file_util::PathExists(file_link));
+
+  // Delete the symbolic link.
+  EXPECT_TRUE(file_util::Delete(file_link, false));
+
+  // Make sure the symbolic link is deleted.
+  EXPECT_FALSE(file_util::IsLink(file_link));
+}
+
+TEST_F(FileUtilTest, ChangeFilePermissionsAndRead) {
+  // Create a file path.
+  FilePath file_name = temp_dir_.path().Append(FPL("Test Readable File.txt"));
+  EXPECT_FALSE(file_util::PathExists(file_name));
+
+  const std::string kData("hello");
+
+  int buffer_size = kData.length();
+  char* buffer = new char[buffer_size];
+
+  // Write file.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            file_util::WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(file_util::PathExists(file_name));
+
+  // Make sure the file is readable.
+  int32 mode = 0;
+  EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & file_util::FILE_PERMISSION_READ_BY_USER);
+
+  // Get rid of the read permission.
+  EXPECT_TRUE(file_util::SetPosixFilePermissions(file_name, 0u));
+  EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode));
+  EXPECT_FALSE(mode & file_util::FILE_PERMISSION_READ_BY_USER);
+  // Make sure the file can't be read.
+  EXPECT_EQ(-1, file_util::ReadFile(file_name, buffer, buffer_size));
+
+  // Give the read permission.
+  EXPECT_TRUE(file_util::SetPosixFilePermissions(
+      file_name,
+      file_util::FILE_PERMISSION_READ_BY_USER));
+  EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & file_util::FILE_PERMISSION_READ_BY_USER);
+  // Make sure the file can be read.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            file_util::ReadFile(file_name, buffer, buffer_size));
+
+  // Delete the file.
+  EXPECT_TRUE(file_util::Delete(file_name, false));
+  EXPECT_FALSE(file_util::PathExists(file_name));
+
+  delete[] buffer;
+}
+
+TEST_F(FileUtilTest, ChangeFilePermissionsAndWrite) {
+  // Create a file path.
+  FilePath file_name = temp_dir_.path().Append(FPL("Test Readable File.txt"));
+  EXPECT_FALSE(file_util::PathExists(file_name));
+
+  const std::string kData("hello");
+
+  // Write file.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            file_util::WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(file_util::PathExists(file_name));
+
+  // Make sure the file is writable.
+  int mode = 0;
+  EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & file_util::FILE_PERMISSION_WRITE_BY_USER);
+  EXPECT_TRUE(file_util::PathIsWritable(file_name));
+
+  // Get rid of the write permission.
+  EXPECT_TRUE(file_util::SetPosixFilePermissions(file_name, 0u));
+  EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode));
+  EXPECT_FALSE(mode & file_util::FILE_PERMISSION_WRITE_BY_USER);
+  // Make sure the file can't be write.
+  EXPECT_EQ(-1,
+            file_util::WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_FALSE(file_util::PathIsWritable(file_name));
+
+  // Give read permission.
+  EXPECT_TRUE(file_util::SetPosixFilePermissions(
+      file_name,
+      file_util::FILE_PERMISSION_WRITE_BY_USER));
+  EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & file_util::FILE_PERMISSION_WRITE_BY_USER);
+  // Make sure the file can be write.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            file_util::WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(file_util::PathIsWritable(file_name));
+
+  // Delete the file.
+  EXPECT_TRUE(file_util::Delete(file_name, false));
+  EXPECT_FALSE(file_util::PathExists(file_name));
+}
+
+TEST_F(FileUtilTest, ChangeDirectoryPermissionsAndEnumerate) {
+  // Create a directory path.
+  FilePath subdir_path =
+      temp_dir_.path().Append(FPL("PermissionTest1"));
+  file_util::CreateDirectory(subdir_path);
+  ASSERT_TRUE(file_util::PathExists(subdir_path));
+
+  // Create a dummy file to enumerate.
+  FilePath file_name = subdir_path.Append(FPL("Test Readable File.txt"));
+  EXPECT_FALSE(file_util::PathExists(file_name));
+  const std::string kData("hello");
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            file_util::WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(file_util::PathExists(file_name));
+
+  // Make sure the directory has the all permissions.
+  int mode = 0;
+  EXPECT_TRUE(file_util::GetPosixFilePermissions(subdir_path, &mode));
+  EXPECT_EQ(file_util::FILE_PERMISSION_USER_MASK,
+            mode & file_util::FILE_PERMISSION_USER_MASK);
+
+  // Get rid of the permissions from the directory.
+  EXPECT_TRUE(file_util::SetPosixFilePermissions(subdir_path, 0u));
+  EXPECT_TRUE(file_util::GetPosixFilePermissions(subdir_path, &mode));
+  EXPECT_FALSE(mode & file_util::FILE_PERMISSION_USER_MASK);
+
+  // Make sure the file in the directory can't be enumerated.
+  file_util::FileEnumerator f1(subdir_path, true,
+                               file_util::FileEnumerator::FILES);
+  EXPECT_TRUE(file_util::PathExists(subdir_path));
+  FindResultCollector c1(f1);
+  EXPECT_EQ(c1.size(), 0);
+  EXPECT_FALSE(file_util::GetPosixFilePermissions(file_name, &mode));
+
+  // Give the permissions to the directory.
+  EXPECT_TRUE(file_util::SetPosixFilePermissions(
+      subdir_path,
+      file_util::FILE_PERMISSION_USER_MASK));
+  EXPECT_TRUE(file_util::GetPosixFilePermissions(subdir_path, &mode));
+  EXPECT_EQ(file_util::FILE_PERMISSION_USER_MASK,
+            mode & file_util::FILE_PERMISSION_USER_MASK);
+
+  // Make sure the file in the directory can be enumerated.
+  file_util::FileEnumerator f2(subdir_path, true,
+                               file_util::FileEnumerator::FILES);
+  FindResultCollector c2(f2);
+  EXPECT_TRUE(c2.HasFile(file_name));
+  EXPECT_EQ(c2.size(), 1);
+
+  // Delete the file.
+  EXPECT_TRUE(file_util::Delete(subdir_path, true));
+  EXPECT_FALSE(file_util::PathExists(subdir_path));
+}
+
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_WIN)
+// Tests that the Delete function works for wild cards, especially
+// with the recursion flag.  Also coincidentally tests PathExists.
+// TODO(erikkay): see if anyone's actually using this feature of the API
+TEST_F(FileUtilTest, DeleteWildCard) {
+  // Create a file and a directory
+  FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteWildCard.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(file_util::PathExists(file_name));
+
+  FilePath subdir_path = temp_dir_.path().Append(FPL("DeleteWildCardDir"));
+  file_util::CreateDirectory(subdir_path);
+  ASSERT_TRUE(file_util::PathExists(subdir_path));
+
+  // Create the wildcard path
+  FilePath directory_contents = temp_dir_.path();
+  directory_contents = directory_contents.Append(FPL("*"));
+
+  // Delete non-recursively and check that only the file is deleted
+  EXPECT_TRUE(file_util::Delete(directory_contents, false));
+  EXPECT_FALSE(file_util::PathExists(file_name));
+  EXPECT_TRUE(file_util::PathExists(subdir_path));
+
+  // Delete recursively and make sure all contents are deleted
+  EXPECT_TRUE(file_util::Delete(directory_contents, true));
+  EXPECT_FALSE(file_util::PathExists(file_name));
+  EXPECT_FALSE(file_util::PathExists(subdir_path));
+}
+
+// TODO(erikkay): see if anyone's actually using this feature of the API
+TEST_F(FileUtilTest, DeleteNonExistantWildCard) {
+  // Create a file and a directory
+  FilePath subdir_path =
+      temp_dir_.path().Append(FPL("DeleteNonExistantWildCard"));
+  file_util::CreateDirectory(subdir_path);
+  ASSERT_TRUE(file_util::PathExists(subdir_path));
+
+  // Create the wildcard path
+  FilePath directory_contents = subdir_path;
+  directory_contents = directory_contents.Append(FPL("*"));
+
+  // Delete non-recursively and check nothing got deleted
+  EXPECT_TRUE(file_util::Delete(directory_contents, false));
+  EXPECT_TRUE(file_util::PathExists(subdir_path));
+
+  // Delete recursively and check nothing got deleted
+  EXPECT_TRUE(file_util::Delete(directory_contents, true));
+  EXPECT_TRUE(file_util::PathExists(subdir_path));
+}
+#endif
+
+// Tests non-recursive Delete() for a directory.
+TEST_F(FileUtilTest, DeleteDirNonRecursive) {
+  // Create a subdirectory and put a file and two directories inside.
+  FilePath test_subdir = temp_dir_.path().Append(FPL("DeleteDirNonRecursive"));
+  file_util::CreateDirectory(test_subdir);
+  ASSERT_TRUE(file_util::PathExists(test_subdir));
+
+  FilePath file_name = test_subdir.Append(FPL("Test DeleteDir.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(file_util::PathExists(file_name));
+
+  FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1"));
+  file_util::CreateDirectory(subdir_path1);
+  ASSERT_TRUE(file_util::PathExists(subdir_path1));
+
+  FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2"));
+  file_util::CreateDirectory(subdir_path2);
+  ASSERT_TRUE(file_util::PathExists(subdir_path2));
+
+  // Delete non-recursively and check that the empty dir got deleted
+  EXPECT_TRUE(file_util::Delete(subdir_path2, false));
+  EXPECT_FALSE(file_util::PathExists(subdir_path2));
+
+  // Delete non-recursively and check that nothing got deleted
+  EXPECT_FALSE(file_util::Delete(test_subdir, false));
+  EXPECT_TRUE(file_util::PathExists(test_subdir));
+  EXPECT_TRUE(file_util::PathExists(file_name));
+  EXPECT_TRUE(file_util::PathExists(subdir_path1));
+}
+
+// Tests recursive Delete() for a directory.
+TEST_F(FileUtilTest, DeleteDirRecursive) {
+  // Create a subdirectory and put a file and two directories inside.
+  FilePath test_subdir = temp_dir_.path().Append(FPL("DeleteDirRecursive"));
+  file_util::CreateDirectory(test_subdir);
+  ASSERT_TRUE(file_util::PathExists(test_subdir));
+
+  FilePath file_name = test_subdir.Append(FPL("Test DeleteDirRecursive.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(file_util::PathExists(file_name));
+
+  FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1"));
+  file_util::CreateDirectory(subdir_path1);
+  ASSERT_TRUE(file_util::PathExists(subdir_path1));
+
+  FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2"));
+  file_util::CreateDirectory(subdir_path2);
+  ASSERT_TRUE(file_util::PathExists(subdir_path2));
+
+  // Delete recursively and check that the empty dir got deleted
+  EXPECT_TRUE(file_util::Delete(subdir_path2, true));
+  EXPECT_FALSE(file_util::PathExists(subdir_path2));
+
+  // Delete recursively and check that everything got deleted
+  EXPECT_TRUE(file_util::Delete(test_subdir, true));
+  EXPECT_FALSE(file_util::PathExists(file_name));
+  EXPECT_FALSE(file_util::PathExists(subdir_path1));
+  EXPECT_FALSE(file_util::PathExists(test_subdir));
+}
+
+TEST_F(FileUtilTest, MoveFileNew) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // The destination.
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
+  ASSERT_FALSE(file_util::PathExists(file_name_to));
+
+  EXPECT_TRUE(file_util::Move(file_name_from, file_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, MoveFileExists) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // The destination name.
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
+  CreateTextFile(file_name_to, L"Old file content");
+  ASSERT_TRUE(file_util::PathExists(file_name_to));
+
+  EXPECT_TRUE(file_util::Move(file_name_from, file_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+  EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to));
+}
+
+TEST_F(FileUtilTest, MoveFileDirExists) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // The destination directory
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+  file_util::CreateDirectory(dir_name_to);
+  ASSERT_TRUE(file_util::PathExists(dir_name_to));
+
+  EXPECT_FALSE(file_util::Move(file_name_from, dir_name_to));
+}
+
+
+TEST_F(FileUtilTest, MoveNew) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Move the directory.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+
+  ASSERT_FALSE(file_util::PathExists(dir_name_to));
+
+  EXPECT_TRUE(file_util::Move(dir_name_from, dir_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(file_util::PathExists(dir_name_from));
+  EXPECT_FALSE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, MoveExist) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Move the directory
+  FilePath dir_name_exists =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+
+  FilePath dir_name_to =
+      dir_name_exists.Append(FILE_PATH_LITERAL("Move_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+
+  // Create the destination directory.
+  file_util::CreateDirectory(dir_name_exists);
+  ASSERT_TRUE(file_util::PathExists(dir_name_exists));
+
+  EXPECT_TRUE(file_util::Move(dir_name_from, dir_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(file_util::PathExists(dir_name_from));
+  EXPECT_FALSE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryRecursivelyNew) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  file_util::CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(file_util::PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name2_from));
+
+  // Copy the directory recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+  FilePath file_name2_to =
+      subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  ASSERT_FALSE(file_util::PathExists(dir_name_to));
+
+  EXPECT_TRUE(file_util::CopyDirectory(dir_name_from, dir_name_to, true));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(file_util::PathExists(dir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(subdir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name2_from));
+  EXPECT_TRUE(file_util::PathExists(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+  EXPECT_TRUE(file_util::PathExists(subdir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name2_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryRecursivelyExists) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  file_util::CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(file_util::PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name2_from));
+
+  // Copy the directory recursively.
+  FilePath dir_name_exists =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+
+  FilePath dir_name_to =
+      dir_name_exists.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+  FilePath file_name2_to =
+      subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  // Create the destination directory.
+  file_util::CreateDirectory(dir_name_exists);
+  ASSERT_TRUE(file_util::PathExists(dir_name_exists));
+
+  EXPECT_TRUE(file_util::CopyDirectory(dir_name_from, dir_name_exists, true));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(file_util::PathExists(dir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(subdir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name2_from));
+  EXPECT_TRUE(file_util::PathExists(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+  EXPECT_TRUE(file_util::PathExists(subdir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name2_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryNew) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  file_util::CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(file_util::PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name2_from));
+
+  // Copy the directory not recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+
+  ASSERT_FALSE(file_util::PathExists(dir_name_to));
+
+  EXPECT_TRUE(file_util::CopyDirectory(dir_name_from, dir_name_to, false));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(file_util::PathExists(dir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(subdir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name2_from));
+  EXPECT_TRUE(file_util::PathExists(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+  EXPECT_FALSE(file_util::PathExists(subdir_name_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryExists) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  file_util::CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(file_util::PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name2_from));
+
+  // Copy the directory not recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+
+  // Create the destination directory.
+  file_util::CreateDirectory(dir_name_to);
+  ASSERT_TRUE(file_util::PathExists(dir_name_to));
+
+  EXPECT_TRUE(file_util::CopyDirectory(dir_name_from, dir_name_to, false));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(file_util::PathExists(dir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(subdir_name_from));
+  EXPECT_TRUE(file_util::PathExists(file_name2_from));
+  EXPECT_TRUE(file_util::PathExists(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+  EXPECT_FALSE(file_util::PathExists(subdir_name_to));
+}
+
+TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToNew) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // The destination name
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
+  ASSERT_FALSE(file_util::PathExists(file_name_to));
+
+  EXPECT_TRUE(file_util::CopyDirectory(file_name_from, file_name_to, true));
+
+  // Check the has been copied
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExisting) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // The destination name
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
+  CreateTextFile(file_name_to, L"Old file content");
+  ASSERT_TRUE(file_util::PathExists(file_name_to));
+
+  EXPECT_TRUE(file_util::CopyDirectory(file_name_from, file_name_to, true));
+
+  // Check the has been copied
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+  EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExistingDirectory) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // The destination
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+  file_util::CreateDirectory(dir_name_to);
+  ASSERT_TRUE(file_util::PathExists(dir_name_to));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  EXPECT_TRUE(file_util::CopyDirectory(file_name_from, dir_name_to, true));
+
+  // Check the has been copied
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyFile) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  const std::wstring file_contents(L"Gooooooooooooooooooooogle");
+  CreateTextFile(file_name_from, file_contents);
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Copy the file.
+  FilePath dest_file = dir_name_from.Append(FILE_PATH_LITERAL("DestFile.txt"));
+  ASSERT_TRUE(file_util::CopyFile(file_name_from, dest_file));
+
+  // Copy the file to another location using '..' in the path.
+  FilePath dest_file2(dir_name_from);
+  dest_file2 = dest_file2.AppendASCII("..");
+  dest_file2 = dest_file2.AppendASCII("DestFile.txt");
+  ASSERT_TRUE(file_util::CopyFile(file_name_from, dest_file2));
+
+  FilePath dest_file2_test(dir_name_from);
+  dest_file2_test = dest_file2_test.DirName();
+  dest_file2_test = dest_file2_test.AppendASCII("DestFile.txt");
+
+  // Check everything has been copied.
+  EXPECT_TRUE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(dest_file));
+  const std::wstring read_contents = ReadTextFile(dest_file);
+  EXPECT_EQ(file_contents, read_contents);
+  EXPECT_TRUE(file_util::PathExists(dest_file2_test));
+  EXPECT_TRUE(file_util::PathExists(dest_file2));
+}
+
+// TODO(erikkay): implement
+#if defined(OS_WIN)
+TEST_F(FileUtilTest, GetFileCreationLocalTime) {
+  FilePath file_name = temp_dir_.path().Append(L"Test File.txt");
+
+  SYSTEMTIME start_time;
+  GetLocalTime(&start_time);
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  CreateTextFile(file_name, L"New file!");
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  SYSTEMTIME end_time;
+  GetLocalTime(&end_time);
+
+  SYSTEMTIME file_creation_time;
+  file_util::GetFileCreationLocalTime(file_name.value(), &file_creation_time);
+
+  FILETIME start_filetime;
+  SystemTimeToFileTime(&start_time, &start_filetime);
+  FILETIME end_filetime;
+  SystemTimeToFileTime(&end_time, &end_filetime);
+  FILETIME file_creation_filetime;
+  SystemTimeToFileTime(&file_creation_time, &file_creation_filetime);
+
+  EXPECT_EQ(-1, CompareFileTime(&start_filetime, &file_creation_filetime)) <<
+    "start time: " << FileTimeAsUint64(start_filetime) << ", " <<
+    "creation time: " << FileTimeAsUint64(file_creation_filetime);
+
+  EXPECT_EQ(-1, CompareFileTime(&file_creation_filetime, &end_filetime)) <<
+    "creation time: " << FileTimeAsUint64(file_creation_filetime) << ", " <<
+    "end time: " << FileTimeAsUint64(end_filetime);
+
+  ASSERT_TRUE(DeleteFile(file_name.value().c_str()));
+}
+#endif
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest.
+typedef PlatformTest ReadOnlyFileUtilTest;
+
+TEST_F(ReadOnlyFileUtilTest, ContentsEqual) {
+  FilePath data_dir;
+  ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &data_dir));
+  data_dir = data_dir.Append(FILE_PATH_LITERAL("base"))
+                     .Append(FILE_PATH_LITERAL("data"))
+                     .Append(FILE_PATH_LITERAL("file_util_unittest"));
+  ASSERT_TRUE(file_util::PathExists(data_dir));
+
+  FilePath original_file =
+      data_dir.Append(FILE_PATH_LITERAL("original.txt"));
+  FilePath same_file =
+      data_dir.Append(FILE_PATH_LITERAL("same.txt"));
+  FilePath same_length_file =
+      data_dir.Append(FILE_PATH_LITERAL("same_length.txt"));
+  FilePath different_file =
+      data_dir.Append(FILE_PATH_LITERAL("different.txt"));
+  FilePath different_first_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_first.txt"));
+  FilePath different_last_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_last.txt"));
+  FilePath empty1_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty1.txt"));
+  FilePath empty2_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty2.txt"));
+  FilePath shortened_file =
+      data_dir.Append(FILE_PATH_LITERAL("shortened.txt"));
+  FilePath binary_file =
+      data_dir.Append(FILE_PATH_LITERAL("binary_file.bin"));
+  FilePath binary_file_same =
+      data_dir.Append(FILE_PATH_LITERAL("binary_file_same.bin"));
+  FilePath binary_file_diff =
+      data_dir.Append(FILE_PATH_LITERAL("binary_file_diff.bin"));
+
+  EXPECT_TRUE(file_util::ContentsEqual(original_file, original_file));
+  EXPECT_TRUE(file_util::ContentsEqual(original_file, same_file));
+  EXPECT_FALSE(file_util::ContentsEqual(original_file, same_length_file));
+  EXPECT_FALSE(file_util::ContentsEqual(original_file, different_file));
+  EXPECT_FALSE(file_util::ContentsEqual(
+      FilePath(FILE_PATH_LITERAL("bogusname")),
+      FilePath(FILE_PATH_LITERAL("bogusname"))));
+  EXPECT_FALSE(file_util::ContentsEqual(original_file, different_first_file));
+  EXPECT_FALSE(file_util::ContentsEqual(original_file, different_last_file));
+  EXPECT_TRUE(file_util::ContentsEqual(empty1_file, empty2_file));
+  EXPECT_FALSE(file_util::ContentsEqual(original_file, shortened_file));
+  EXPECT_FALSE(file_util::ContentsEqual(shortened_file, original_file));
+  EXPECT_TRUE(file_util::ContentsEqual(binary_file, binary_file_same));
+  EXPECT_FALSE(file_util::ContentsEqual(binary_file, binary_file_diff));
+}
+
+TEST_F(ReadOnlyFileUtilTest, TextContentsEqual) {
+  FilePath data_dir;
+  ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &data_dir));
+  data_dir = data_dir.Append(FILE_PATH_LITERAL("base"))
+                     .Append(FILE_PATH_LITERAL("data"))
+                     .Append(FILE_PATH_LITERAL("file_util_unittest"));
+  ASSERT_TRUE(file_util::PathExists(data_dir));
+
+  FilePath original_file =
+      data_dir.Append(FILE_PATH_LITERAL("original.txt"));
+  FilePath same_file =
+      data_dir.Append(FILE_PATH_LITERAL("same.txt"));
+  FilePath crlf_file =
+      data_dir.Append(FILE_PATH_LITERAL("crlf.txt"));
+  FilePath shortened_file =
+      data_dir.Append(FILE_PATH_LITERAL("shortened.txt"));
+  FilePath different_file =
+      data_dir.Append(FILE_PATH_LITERAL("different.txt"));
+  FilePath different_first_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_first.txt"));
+  FilePath different_last_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_last.txt"));
+  FilePath first1_file =
+      data_dir.Append(FILE_PATH_LITERAL("first1.txt"));
+  FilePath first2_file =
+      data_dir.Append(FILE_PATH_LITERAL("first2.txt"));
+  FilePath empty1_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty1.txt"));
+  FilePath empty2_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty2.txt"));
+  FilePath blank_line_file =
+      data_dir.Append(FILE_PATH_LITERAL("blank_line.txt"));
+  FilePath blank_line_crlf_file =
+      data_dir.Append(FILE_PATH_LITERAL("blank_line_crlf.txt"));
+
+  EXPECT_TRUE(file_util::TextContentsEqual(original_file, same_file));
+  EXPECT_TRUE(file_util::TextContentsEqual(original_file, crlf_file));
+  EXPECT_FALSE(file_util::TextContentsEqual(original_file, shortened_file));
+  EXPECT_FALSE(file_util::TextContentsEqual(original_file, different_file));
+  EXPECT_FALSE(file_util::TextContentsEqual(original_file,
+                                            different_first_file));
+  EXPECT_FALSE(file_util::TextContentsEqual(original_file,
+                                            different_last_file));
+  EXPECT_FALSE(file_util::TextContentsEqual(first1_file, first2_file));
+  EXPECT_TRUE(file_util::TextContentsEqual(empty1_file, empty2_file));
+  EXPECT_FALSE(file_util::TextContentsEqual(original_file, empty1_file));
+  EXPECT_TRUE(file_util::TextContentsEqual(blank_line_file,
+                                           blank_line_crlf_file));
+}
+
+// We don't need equivalent functionality outside of Windows.
+#if defined(OS_WIN)
+TEST_F(FileUtilTest, CopyAndDeleteDirectoryTest) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("CopyAndDelete_From_Subdir"));
+  file_util::CreateDirectory(dir_name_from);
+  ASSERT_TRUE(file_util::PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(file_util::PathExists(file_name_from));
+
+  // Move the directory by using CopyAndDeleteDirectory
+  FilePath dir_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("CopyAndDelete_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt"));
+
+  ASSERT_FALSE(file_util::PathExists(dir_name_to));
+
+  EXPECT_TRUE(file_util::CopyAndDeleteDirectory(dir_name_from, dir_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(file_util::PathExists(dir_name_from));
+  EXPECT_FALSE(file_util::PathExists(file_name_from));
+  EXPECT_TRUE(file_util::PathExists(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, GetTempDirTest) {
+  static const TCHAR* kTmpKey = _T("TMP");
+  static const TCHAR* kTmpValues[] = {
+    _T(""), _T("C:"), _T("C:\\"), _T("C:\\tmp"), _T("C:\\tmp\\")
+  };
+  // Save the original $TMP.
+  size_t original_tmp_size;
+  TCHAR* original_tmp;
+  ASSERT_EQ(0, ::_tdupenv_s(&original_tmp, &original_tmp_size, kTmpKey));
+  // original_tmp may be NULL.
+
+  for (unsigned int i = 0; i < arraysize(kTmpValues); ++i) {
+    FilePath path;
+    ::_tputenv_s(kTmpKey, kTmpValues[i]);
+    file_util::GetTempDir(&path);
+    EXPECT_TRUE(path.IsAbsolute()) << "$TMP=" << kTmpValues[i] <<
+        " result=" << path.value();
+  }
+
+  // Restore the original $TMP.
+  if (original_tmp) {
+    ::_tputenv_s(kTmpKey, original_tmp);
+    free(original_tmp);
+  } else {
+    ::_tputenv_s(kTmpKey, _T(""));
+  }
+}
+#endif  // OS_WIN
+
+TEST_F(FileUtilTest, CreateTemporaryFileTest) {
+  FilePath temp_files[3];
+  for (int i = 0; i < 3; i++) {
+    ASSERT_TRUE(file_util::CreateTemporaryFile(&(temp_files[i])));
+    EXPECT_TRUE(file_util::PathExists(temp_files[i]));
+    EXPECT_FALSE(file_util::DirectoryExists(temp_files[i]));
+  }
+  for (int i = 0; i < 3; i++)
+    EXPECT_FALSE(temp_files[i] == temp_files[(i+1)%3]);
+  for (int i = 0; i < 3; i++)
+    EXPECT_TRUE(file_util::Delete(temp_files[i], false));
+}
+
+TEST_F(FileUtilTest, CreateAndOpenTemporaryFileTest) {
+  FilePath names[3];
+  FILE* fps[3];
+  int i;
+
+  // Create; make sure they are open and exist.
+  for (i = 0; i < 3; ++i) {
+    fps[i] = file_util::CreateAndOpenTemporaryFile(&(names[i]));
+    ASSERT_TRUE(fps[i]);
+    EXPECT_TRUE(file_util::PathExists(names[i]));
+  }
+
+  // Make sure all names are unique.
+  for (i = 0; i < 3; ++i) {
+    EXPECT_FALSE(names[i] == names[(i+1)%3]);
+  }
+
+  // Close and delete.
+  for (i = 0; i < 3; ++i) {
+    EXPECT_TRUE(file_util::CloseFile(fps[i]));
+    EXPECT_TRUE(file_util::Delete(names[i], false));
+  }
+}
+
+TEST_F(FileUtilTest, CreateNewTempDirectoryTest) {
+  FilePath temp_dir;
+  ASSERT_TRUE(file_util::CreateNewTempDirectory(FilePath::StringType(),
+                                                &temp_dir));
+  EXPECT_TRUE(file_util::PathExists(temp_dir));
+  EXPECT_TRUE(file_util::Delete(temp_dir, false));
+}
+
+TEST_F(FileUtilTest, CreateNewTemporaryDirInDirTest) {
+  FilePath new_dir;
+  ASSERT_TRUE(file_util::CreateTemporaryDirInDir(
+                  temp_dir_.path(),
+                  FILE_PATH_LITERAL("CreateNewTemporaryDirInDirTest"),
+                  &new_dir));
+  EXPECT_TRUE(file_util::PathExists(new_dir));
+  EXPECT_TRUE(temp_dir_.path().IsParent(new_dir));
+  EXPECT_TRUE(file_util::Delete(new_dir, false));
+}
+
+TEST_F(FileUtilTest, GetShmemTempDirTest) {
+  FilePath dir;
+  EXPECT_TRUE(file_util::GetShmemTempDir(&dir, false));
+  EXPECT_TRUE(file_util::DirectoryExists(dir));
+}
+
+TEST_F(FileUtilTest, CreateDirectoryTest) {
+  FilePath test_root =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("create_directory_test"));
+#if defined(OS_WIN)
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("dir\\tree\\likely\\doesnt\\exist\\"));
+#elif defined(OS_POSIX)
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("dir/tree/likely/doesnt/exist/"));
+#endif
+
+  EXPECT_FALSE(file_util::PathExists(test_path));
+  EXPECT_TRUE(file_util::CreateDirectory(test_path));
+  EXPECT_TRUE(file_util::PathExists(test_path));
+  // CreateDirectory returns true if the DirectoryExists returns true.
+  EXPECT_TRUE(file_util::CreateDirectory(test_path));
+
+  // Doesn't work to create it on top of a non-dir
+  test_path = test_path.Append(FILE_PATH_LITERAL("foobar.txt"));
+  EXPECT_FALSE(file_util::PathExists(test_path));
+  CreateTextFile(test_path, L"test file");
+  EXPECT_TRUE(file_util::PathExists(test_path));
+  EXPECT_FALSE(file_util::CreateDirectory(test_path));
+
+  EXPECT_TRUE(file_util::Delete(test_root, true));
+  EXPECT_FALSE(file_util::PathExists(test_root));
+  EXPECT_FALSE(file_util::PathExists(test_path));
+
+  // Verify assumptions made by the Windows implementation:
+  // 1. The current directory always exists.
+  // 2. The root directory always exists.
+  ASSERT_TRUE(file_util::DirectoryExists(
+      FilePath(FilePath::kCurrentDirectory)));
+  FilePath top_level = test_root;
+  while (top_level != top_level.DirName()) {
+    top_level = top_level.DirName();
+  }
+  ASSERT_TRUE(file_util::DirectoryExists(top_level));
+
+  // Given these assumptions hold, it should be safe to
+  // test that "creating" these directories succeeds.
+  EXPECT_TRUE(file_util::CreateDirectory(
+      FilePath(FilePath::kCurrentDirectory)));
+  EXPECT_TRUE(file_util::CreateDirectory(top_level));
+
+#if defined(OS_WIN)
+  FilePath invalid_drive(FILE_PATH_LITERAL("o:\\"));
+  FilePath invalid_path =
+      invalid_drive.Append(FILE_PATH_LITERAL("some\\inaccessible\\dir"));
+  if (!file_util::PathExists(invalid_drive)) {
+    EXPECT_FALSE(file_util::CreateDirectory(invalid_path));
+  }
+#endif
+}
+
+TEST_F(FileUtilTest, DetectDirectoryTest) {
+  // Check a directory
+  FilePath test_root =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("detect_directory_test"));
+  EXPECT_FALSE(file_util::PathExists(test_root));
+  EXPECT_TRUE(file_util::CreateDirectory(test_root));
+  EXPECT_TRUE(file_util::PathExists(test_root));
+  EXPECT_TRUE(file_util::DirectoryExists(test_root));
+  // Check a file
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("foobar.txt"));
+  EXPECT_FALSE(file_util::PathExists(test_path));
+  CreateTextFile(test_path, L"test file");
+  EXPECT_TRUE(file_util::PathExists(test_path));
+  EXPECT_FALSE(file_util::DirectoryExists(test_path));
+  EXPECT_TRUE(file_util::Delete(test_path, false));
+
+  EXPECT_TRUE(file_util::Delete(test_root, true));
+}
+
+TEST_F(FileUtilTest, FileEnumeratorTest) {
+  // Test an empty directory.
+  file_util::FileEnumerator f0(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+  EXPECT_EQ(f0.Next().value(), FILE_PATH_LITERAL(""));
+  EXPECT_EQ(f0.Next().value(), FILE_PATH_LITERAL(""));
+
+  // Test an empty directory, non-recursively, including "..".
+  file_util::FileEnumerator f0_dotdot(temp_dir_.path(), false,
+      FILES_AND_DIRECTORIES | file_util::FileEnumerator::INCLUDE_DOT_DOT);
+  EXPECT_EQ(temp_dir_.path().Append(FILE_PATH_LITERAL("..")).value(),
+            f0_dotdot.Next().value());
+  EXPECT_EQ(FILE_PATH_LITERAL(""),
+            f0_dotdot.Next().value());
+
+  // create the directories
+  FilePath dir1 = temp_dir_.path().Append(FILE_PATH_LITERAL("dir1"));
+  EXPECT_TRUE(file_util::CreateDirectory(dir1));
+  FilePath dir2 = temp_dir_.path().Append(FILE_PATH_LITERAL("dir2"));
+  EXPECT_TRUE(file_util::CreateDirectory(dir2));
+  FilePath dir2inner = dir2.Append(FILE_PATH_LITERAL("inner"));
+  EXPECT_TRUE(file_util::CreateDirectory(dir2inner));
+
+  // create the files
+  FilePath dir2file = dir2.Append(FILE_PATH_LITERAL("dir2file.txt"));
+  CreateTextFile(dir2file, L"");
+  FilePath dir2innerfile = dir2inner.Append(FILE_PATH_LITERAL("innerfile.txt"));
+  CreateTextFile(dir2innerfile, L"");
+  FilePath file1 = temp_dir_.path().Append(FILE_PATH_LITERAL("file1.txt"));
+  CreateTextFile(file1, L"");
+  FilePath file2_rel =
+      dir2.Append(FilePath::kParentDirectory)
+          .Append(FILE_PATH_LITERAL("file2.txt"));
+  CreateTextFile(file2_rel, L"");
+  FilePath file2_abs = temp_dir_.path().Append(FILE_PATH_LITERAL("file2.txt"));
+
+  // Only enumerate files.
+  file_util::FileEnumerator f1(temp_dir_.path(), true,
+                               file_util::FileEnumerator::FILES);
+  FindResultCollector c1(f1);
+  EXPECT_TRUE(c1.HasFile(file1));
+  EXPECT_TRUE(c1.HasFile(file2_abs));
+  EXPECT_TRUE(c1.HasFile(dir2file));
+  EXPECT_TRUE(c1.HasFile(dir2innerfile));
+  EXPECT_EQ(c1.size(), 4);
+
+  // Only enumerate directories.
+  file_util::FileEnumerator f2(temp_dir_.path(), true,
+                               file_util::FileEnumerator::DIRECTORIES);
+  FindResultCollector c2(f2);
+  EXPECT_TRUE(c2.HasFile(dir1));
+  EXPECT_TRUE(c2.HasFile(dir2));
+  EXPECT_TRUE(c2.HasFile(dir2inner));
+  EXPECT_EQ(c2.size(), 3);
+
+  // Only enumerate directories non-recursively.
+  file_util::FileEnumerator f2_non_recursive(
+      temp_dir_.path(), false, file_util::FileEnumerator::DIRECTORIES);
+  FindResultCollector c2_non_recursive(f2_non_recursive);
+  EXPECT_TRUE(c2_non_recursive.HasFile(dir1));
+  EXPECT_TRUE(c2_non_recursive.HasFile(dir2));
+  EXPECT_EQ(c2_non_recursive.size(), 2);
+
+  // Only enumerate directories, non-recursively, including "..".
+  file_util::FileEnumerator f2_dotdot(temp_dir_.path(), false,
+      file_util::FileEnumerator::DIRECTORIES |
+      file_util::FileEnumerator::INCLUDE_DOT_DOT);
+  FindResultCollector c2_dotdot(f2_dotdot);
+  EXPECT_TRUE(c2_dotdot.HasFile(dir1));
+  EXPECT_TRUE(c2_dotdot.HasFile(dir2));
+  EXPECT_TRUE(c2_dotdot.HasFile(
+      temp_dir_.path().Append(FILE_PATH_LITERAL(".."))));
+  EXPECT_EQ(c2_dotdot.size(), 3);
+
+  // Enumerate files and directories.
+  file_util::FileEnumerator f3(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+  FindResultCollector c3(f3);
+  EXPECT_TRUE(c3.HasFile(dir1));
+  EXPECT_TRUE(c3.HasFile(dir2));
+  EXPECT_TRUE(c3.HasFile(file1));
+  EXPECT_TRUE(c3.HasFile(file2_abs));
+  EXPECT_TRUE(c3.HasFile(dir2file));
+  EXPECT_TRUE(c3.HasFile(dir2inner));
+  EXPECT_TRUE(c3.HasFile(dir2innerfile));
+  EXPECT_EQ(c3.size(), 7);
+
+  // Non-recursive operation.
+  file_util::FileEnumerator f4(temp_dir_.path(), false, FILES_AND_DIRECTORIES);
+  FindResultCollector c4(f4);
+  EXPECT_TRUE(c4.HasFile(dir2));
+  EXPECT_TRUE(c4.HasFile(dir2));
+  EXPECT_TRUE(c4.HasFile(file1));
+  EXPECT_TRUE(c4.HasFile(file2_abs));
+  EXPECT_EQ(c4.size(), 4);
+
+  // Enumerate with a pattern.
+  file_util::FileEnumerator f5(temp_dir_.path(), true, FILES_AND_DIRECTORIES,
+      FILE_PATH_LITERAL("dir*"));
+  FindResultCollector c5(f5);
+  EXPECT_TRUE(c5.HasFile(dir1));
+  EXPECT_TRUE(c5.HasFile(dir2));
+  EXPECT_TRUE(c5.HasFile(dir2file));
+  EXPECT_TRUE(c5.HasFile(dir2inner));
+  EXPECT_TRUE(c5.HasFile(dir2innerfile));
+  EXPECT_EQ(c5.size(), 5);
+
+  // Make sure the destructor closes the find handle while in the middle of a
+  // query to allow TearDown to delete the directory.
+  file_util::FileEnumerator f6(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+  EXPECT_FALSE(f6.Next().value().empty());  // Should have found something
+                                            // (we don't care what).
+}
+
+TEST_F(FileUtilTest, AppendToFile) {
+  FilePath data_dir =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest"));
+
+  // Create a fresh, empty copy of this directory.
+  if (file_util::PathExists(data_dir)) {
+    ASSERT_TRUE(file_util::Delete(data_dir, true));
+  }
+  ASSERT_TRUE(file_util::CreateDirectory(data_dir));
+
+  // Create a fresh, empty copy of this directory.
+  if (file_util::PathExists(data_dir)) {
+    ASSERT_TRUE(file_util::Delete(data_dir, true));
+  }
+  ASSERT_TRUE(file_util::CreateDirectory(data_dir));
+  FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt")));
+
+  std::string data("hello");
+  EXPECT_EQ(-1, file_util::AppendToFile(foobar, data.c_str(), data.length()));
+  EXPECT_EQ(static_cast<int>(data.length()),
+            file_util::WriteFile(foobar, data.c_str(), data.length()));
+  EXPECT_EQ(static_cast<int>(data.length()),
+            file_util::AppendToFile(foobar, data.c_str(), data.length()));
+
+  const std::wstring read_content = ReadTextFile(foobar);
+  EXPECT_EQ(L"hellohello", read_content);
+}
+
+TEST_F(FileUtilTest, Contains) {
+  FilePath data_dir =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest"));
+
+  // Create a fresh, empty copy of this directory.
+  if (file_util::PathExists(data_dir)) {
+    ASSERT_TRUE(file_util::Delete(data_dir, true));
+  }
+  ASSERT_TRUE(file_util::CreateDirectory(data_dir));
+
+  FilePath foo(data_dir.Append(FILE_PATH_LITERAL("foo")));
+  FilePath bar(foo.Append(FILE_PATH_LITERAL("bar.txt")));
+  FilePath baz(data_dir.Append(FILE_PATH_LITERAL("baz.txt")));
+  FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt")));
+
+  // Annoyingly, the directories must actually exist in order for realpath(),
+  // which Contains() relies on in posix, to work.
+  ASSERT_TRUE(file_util::CreateDirectory(foo));
+  std::string data("hello");
+  ASSERT_TRUE(file_util::WriteFile(bar, data.c_str(), data.length()));
+  ASSERT_TRUE(file_util::WriteFile(baz, data.c_str(), data.length()));
+  ASSERT_TRUE(file_util::WriteFile(foobar, data.c_str(), data.length()));
+
+  EXPECT_TRUE(file_util::ContainsPath(foo, bar));
+  EXPECT_FALSE(file_util::ContainsPath(foo, baz));
+  EXPECT_FALSE(file_util::ContainsPath(foo, foobar));
+  EXPECT_FALSE(file_util::ContainsPath(foo, foo));
+
+  // Platform-specific concerns.
+  FilePath foo_caps(data_dir.Append(FILE_PATH_LITERAL("FOO")));
+#if defined(OS_WIN)
+  EXPECT_TRUE(file_util::ContainsPath(foo,
+      foo_caps.Append(FILE_PATH_LITERAL("bar.txt"))));
+  EXPECT_TRUE(file_util::ContainsPath(foo,
+      FilePath(foo.value() + FILE_PATH_LITERAL("/bar.txt"))));
+#elif defined(OS_MACOSX)
+  // We can't really do this test on OS X since the case-sensitivity of the
+  // filesystem is configurable.
+#elif defined(OS_POSIX)
+  EXPECT_FALSE(file_util::ContainsPath(foo,
+      foo_caps.Append(FILE_PATH_LITERAL("bar.txt"))));
+#endif
+}
+
+TEST_F(FileUtilTest, TouchFile) {
+  FilePath data_dir =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest"));
+
+  // Create a fresh, empty copy of this directory.
+  if (file_util::PathExists(data_dir)) {
+    ASSERT_TRUE(file_util::Delete(data_dir, true));
+  }
+  ASSERT_TRUE(file_util::CreateDirectory(data_dir));
+
+  FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt")));
+  std::string data("hello");
+  ASSERT_TRUE(file_util::WriteFile(foobar, data.c_str(), data.length()));
+
+  base::Time access_time;
+  // This timestamp is divisible by one day (in local timezone),
+  // to make it work on FAT too.
+  ASSERT_TRUE(base::Time::FromString("Wed, 16 Nov 1994, 00:00:00",
+                                     &access_time));
+
+  base::Time modification_time;
+  // Note that this timestamp is divisible by two (seconds) - FAT stores
+  // modification times with 2s resolution.
+  ASSERT_TRUE(base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT",
+              &modification_time));
+
+  ASSERT_TRUE(file_util::TouchFile(foobar, access_time, modification_time));
+  base::PlatformFileInfo file_info;
+  ASSERT_TRUE(file_util::GetFileInfo(foobar, &file_info));
+  EXPECT_EQ(file_info.last_accessed.ToInternalValue(),
+            access_time.ToInternalValue());
+  EXPECT_EQ(file_info.last_modified.ToInternalValue(),
+            modification_time.ToInternalValue());
+}
+
+TEST_F(FileUtilTest, IsDirectoryEmpty) {
+  FilePath empty_dir = temp_dir_.path().Append(FILE_PATH_LITERAL("EmptyDir"));
+
+  ASSERT_FALSE(file_util::PathExists(empty_dir));
+
+  ASSERT_TRUE(file_util::CreateDirectory(empty_dir));
+
+  EXPECT_TRUE(file_util::IsDirectoryEmpty(empty_dir));
+
+  FilePath foo(empty_dir.Append(FILE_PATH_LITERAL("foo.txt")));
+  std::string bar("baz");
+  ASSERT_TRUE(file_util::WriteFile(foo, bar.c_str(), bar.length()));
+
+  EXPECT_FALSE(file_util::IsDirectoryEmpty(empty_dir));
+}
+
+#if defined(OS_POSIX)
+
+// Testing VerifyPathControlledByAdmin() is hard, because there is no
+// way a test can make a file owned by root, or change file paths
+// at the root of the file system.  VerifyPathControlledByAdmin()
+// is implemented as a call to VerifyPathControlledByUser, which gives
+// us the ability to test with paths under the test's temp directory,
+// using a user id we control.
+// Pull tests of VerifyPathControlledByUserTest() into a separate test class
+// with a common SetUp() method.
+class VerifyPathControlledByUserTest : public FileUtilTest {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    FileUtilTest::SetUp();
+
+    // Create a basic structure used by each test.
+    // base_dir_
+    //  |-> sub_dir_
+    //       |-> text_file_
+
+    base_dir_ = temp_dir_.path().AppendASCII("base_dir");
+    ASSERT_TRUE(file_util::CreateDirectory(base_dir_));
+
+    sub_dir_ = base_dir_.AppendASCII("sub_dir");
+    ASSERT_TRUE(file_util::CreateDirectory(sub_dir_));
+
+    text_file_ = sub_dir_.AppendASCII("file.txt");
+    CreateTextFile(text_file_, L"This text file has some text in it.");
+
+    // Get the user and group files are created with from |base_dir_|.
+    struct stat stat_buf;
+    ASSERT_EQ(0, stat(base_dir_.value().c_str(), &stat_buf));
+    uid_ = stat_buf.st_uid;
+    ok_gids_.insert(stat_buf.st_gid);
+    bad_gids_.insert(stat_buf.st_gid + 1);
+
+    ASSERT_EQ(uid_, getuid());  // This process should be the owner.
+
+    // To ensure that umask settings do not cause the initial state
+    // of permissions to be different from what we expect, explicitly
+    // set permissions on the directories we create.
+    // Make all files and directories non-world-writable.
+
+    // Users and group can read, write, traverse
+    int enabled_permissions =
+        file_util::FILE_PERMISSION_USER_MASK |
+        file_util::FILE_PERMISSION_GROUP_MASK;
+    // Other users can't read, write, traverse
+    int disabled_permissions =
+        file_util::FILE_PERMISSION_OTHERS_MASK;
+
+    ASSERT_NO_FATAL_FAILURE(
+        ChangePosixFilePermissions(
+            base_dir_, enabled_permissions, disabled_permissions));
+    ASSERT_NO_FATAL_FAILURE(
+        ChangePosixFilePermissions(
+            sub_dir_, enabled_permissions, disabled_permissions));
+  }
+
+  FilePath base_dir_;
+  FilePath sub_dir_;
+  FilePath text_file_;
+  uid_t uid_;
+
+  std::set<gid_t> ok_gids_;
+  std::set<gid_t> bad_gids_;
+};
+
+TEST_F(VerifyPathControlledByUserTest, BadPaths) {
+  // File does not exist.
+  FilePath does_not_exist = base_dir_.AppendASCII("does")
+                                     .AppendASCII("not")
+                                     .AppendASCII("exist");
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, does_not_exist, uid_, ok_gids_));
+
+  // |base| not a subpath of |path|.
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, base_dir_, uid_, ok_gids_));
+
+  // An empty base path will fail to be a prefix for any path.
+  FilePath empty;
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          empty, base_dir_, uid_, ok_gids_));
+
+  // Finding that a bad call fails proves nothing unless a good call succeeds.
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+}
+
+TEST_F(VerifyPathControlledByUserTest, Symlinks) {
+  // Symlinks in the path should cause failure.
+
+  // Symlink to the file at the end of the path.
+  FilePath file_link =  base_dir_.AppendASCII("file_link");
+  ASSERT_TRUE(file_util::CreateSymbolicLink(text_file_, file_link))
+      << "Failed to create symlink.";
+
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, file_link, uid_, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          file_link, file_link, uid_, ok_gids_));
+
+  // Symlink from one directory to another within the path.
+  FilePath link_to_sub_dir =  base_dir_.AppendASCII("link_to_sub_dir");
+  ASSERT_TRUE(file_util::CreateSymbolicLink(sub_dir_, link_to_sub_dir))
+    << "Failed to create symlink.";
+
+  FilePath file_path_with_link = link_to_sub_dir.AppendASCII("file.txt");
+  ASSERT_TRUE(file_util::PathExists(file_path_with_link));
+
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, file_path_with_link, uid_, ok_gids_));
+
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          link_to_sub_dir, file_path_with_link, uid_, ok_gids_));
+
+  // Symlinks in parents of base path are allowed.
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          file_path_with_link, file_path_with_link, uid_, ok_gids_));
+}
+
+TEST_F(VerifyPathControlledByUserTest, OwnershipChecks) {
+  // Get a uid that is not the uid of files we create.
+  uid_t bad_uid = uid_ + 1;
+
+  // Make all files and directories non-world-writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
+
+  // We control these paths.
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Another user does not control these paths.
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, bad_uid, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, bad_uid, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, bad_uid, ok_gids_));
+
+  // Another group does not control the paths.
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, bad_gids_));
+}
+
+TEST_F(VerifyPathControlledByUserTest, GroupWriteTest) {
+  // Make all files and directories writable only by their owner.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH|S_IWGRP));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH|S_IWGRP));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, 0u, S_IWOTH|S_IWGRP));
+
+  // Any group is okay because the path is not group-writable.
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, bad_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, bad_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, bad_gids_));
+
+  // No group is okay, because we don't check the group
+  // if no group can write.
+  std::set<gid_t> no_gids;  // Empty set of gids.
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, no_gids));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, no_gids));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, no_gids));
+
+
+  // Make all files and directories writable by their group.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, S_IWGRP, 0u));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, S_IWGRP, 0u));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, S_IWGRP, 0u));
+
+  // Now |ok_gids_| works, but |bad_gids_| fails.
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, bad_gids_));
+
+  // Because any group in the group set is allowed,
+  // the union of good and bad gids passes.
+
+  std::set<gid_t> multiple_gids;
+  std::set_union(
+      ok_gids_.begin(), ok_gids_.end(),
+      bad_gids_.begin(), bad_gids_.end(),
+      std::inserter(multiple_gids, multiple_gids.begin()));
+
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, multiple_gids));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, multiple_gids));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, multiple_gids));
+}
+
+TEST_F(VerifyPathControlledByUserTest, WriteBitChecks) {
+  // Make all files and directories non-world-writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
+
+  // Initialy, we control all parts of the path.
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Make base_dir_ world-writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, S_IWOTH, 0u));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Make sub_dir_ world writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, S_IWOTH, 0u));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Make text_file_ world writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, S_IWOTH, 0u));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Make sub_dir_ non-world writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Make base_dir_ non-world-writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Back to the initial state: Nothing is writable, so every path
+  // should pass.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      file_util::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+}
+
+#endif  // defined(OS_POSIX)
+
+}  // namespace
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
new file mode 100644
index 0000000..332414a
--- /dev/null
+++ b/base/file_util_win.cc
@@ -0,0 +1,971 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_util.h"
+
+#include <windows.h>
+#include <psapi.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <time.h>
+
+#include <limits>
+#include <string>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/process_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace file_util {
+
+namespace {
+
+const DWORD kFileShareAll =
+    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+}  // namespace
+
+bool AbsolutePath(FilePath* path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  wchar_t file_path_buf[MAX_PATH];
+  if (!_wfullpath(file_path_buf, path->value().c_str(), MAX_PATH))
+    return false;
+  *path = FilePath(file_path_buf);
+  return true;
+}
+
+int CountFilesCreatedAfter(const FilePath& path,
+                           const base::Time& comparison_time) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  int file_count = 0;
+  FILETIME comparison_filetime(comparison_time.ToFileTime());
+
+  WIN32_FIND_DATA find_file_data;
+  // All files in given dir
+  std::wstring filename_spec = path.Append(L"*").value();
+  HANDLE find_handle = FindFirstFile(filename_spec.c_str(), &find_file_data);
+  if (find_handle != INVALID_HANDLE_VALUE) {
+    do {
+      // Don't count current or parent directories.
+      if ((wcscmp(find_file_data.cFileName, L"..") == 0) ||
+          (wcscmp(find_file_data.cFileName, L".") == 0))
+        continue;
+
+      long result = CompareFileTime(&find_file_data.ftCreationTime,  // NOLINT
+                                    &comparison_filetime);
+      // File was created after or on comparison time
+      if ((result == 1) || (result == 0))
+        ++file_count;
+    } while (FindNextFile(find_handle,  &find_file_data));
+    FindClose(find_handle);
+  }
+
+  return file_count;
+}
+
+bool Delete(const FilePath& path, bool recursive) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  if (path.value().length() >= MAX_PATH)
+    return false;
+
+  if (!recursive) {
+    // If not recursing, then first check to see if |path| is a directory.
+    // If it is, then remove it with RemoveDirectory.
+    base::PlatformFileInfo file_info;
+    if (GetFileInfo(path, &file_info) && file_info.is_directory)
+      return RemoveDirectory(path.value().c_str()) != 0;
+
+    // Otherwise, it's a file, wildcard or non-existant. Try DeleteFile first
+    // because it should be faster. If DeleteFile fails, then we fall through
+    // to SHFileOperation, which will do the right thing.
+    if (DeleteFile(path.value().c_str()) != 0)
+      return true;
+  }
+
+  // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
+  // so we have to use wcscpy because wcscpy_s writes non-NULLs
+  // into the rest of the buffer.
+  wchar_t double_terminated_path[MAX_PATH + 1] = {0};
+#pragma warning(suppress:4996)  // don't complain about wcscpy deprecation
+  if (g_bug108724_debug)
+    LOG(WARNING) << "copying ";
+  wcscpy(double_terminated_path, path.value().c_str());
+
+  SHFILEOPSTRUCT file_operation = {0};
+  file_operation.wFunc = FO_DELETE;
+  file_operation.pFrom = double_terminated_path;
+  file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
+  if (!recursive)
+    file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
+  if (g_bug108724_debug)
+    LOG(WARNING) << "Performing shell operation";
+  int err = SHFileOperation(&file_operation);
+  if (g_bug108724_debug)
+    LOG(WARNING) << "Done: " << err;
+
+  // Since we're passing flags to the operation telling it to be silent,
+  // it's possible for the operation to be aborted/cancelled without err
+  // being set (although MSDN doesn't give any scenarios for how this can
+  // happen).  See MSDN for SHFileOperation and SHFILEOPTSTRUCT.
+  if (file_operation.fAnyOperationsAborted)
+    return false;
+
+  // Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting
+  // an empty directory and some return 0x402 when they should be returning
+  // ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402.
+  return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402);
+}
+
+bool DeleteAfterReboot(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  if (path.value().length() >= MAX_PATH)
+    return false;
+
+  return MoveFileEx(path.value().c_str(), NULL,
+                    MOVEFILE_DELAY_UNTIL_REBOOT |
+                        MOVEFILE_REPLACE_EXISTING) != FALSE;
+}
+
+bool Move(const FilePath& from_path, const FilePath& to_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // NOTE: I suspect we could support longer paths, but that would involve
+  // analyzing all our usage of files.
+  if (from_path.value().length() >= MAX_PATH ||
+      to_path.value().length() >= MAX_PATH) {
+    return false;
+  }
+  if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(),
+                 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0)
+    return true;
+
+  // Keep the last error value from MoveFileEx around in case the below
+  // fails.
+  bool ret = false;
+  DWORD last_error = ::GetLastError();
+
+  if (DirectoryExists(from_path)) {
+    // MoveFileEx fails if moving directory across volumes. We will simulate
+    // the move by using Copy and Delete. Ideally we could check whether
+    // from_path and to_path are indeed in different volumes.
+    ret = CopyAndDeleteDirectory(from_path, to_path);
+  }
+
+  if (!ret) {
+    // Leave a clue about what went wrong so that it can be (at least) picked
+    // up by a PLOG entry.
+    ::SetLastError(last_error);
+  }
+
+  return ret;
+}
+
+bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  // Try a simple move first.  It will only succeed when |to_path| doesn't
+  // already exist.
+  if (::MoveFile(from_path.value().c_str(), to_path.value().c_str()))
+    return true;
+  // Try the full-blown replace if the move fails, as ReplaceFile will only
+  // succeed when |to_path| does exist. When writing to a network share, we may
+  // not be able to change the ACLs. Ignore ACL errors then
+  // (REPLACEFILE_IGNORE_MERGE_ERRORS).
+  if (::ReplaceFile(to_path.value().c_str(), from_path.value().c_str(), NULL,
+                    REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) {
+    return true;
+  }
+  return false;
+}
+
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // NOTE: I suspect we could support longer paths, but that would involve
+  // analyzing all our usage of files.
+  if (from_path.value().length() >= MAX_PATH ||
+      to_path.value().length() >= MAX_PATH) {
+    return false;
+  }
+  return (::CopyFile(from_path.value().c_str(), to_path.value().c_str(),
+                     false) != 0);
+}
+
+bool ShellCopy(const FilePath& from_path, const FilePath& to_path,
+               bool recursive) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // NOTE: I suspect we could support longer paths, but that would involve
+  // analyzing all our usage of files.
+  if (from_path.value().length() >= MAX_PATH ||
+      to_path.value().length() >= MAX_PATH) {
+    return false;
+  }
+
+  // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
+  // so we have to use wcscpy because wcscpy_s writes non-NULLs
+  // into the rest of the buffer.
+  wchar_t double_terminated_path_from[MAX_PATH + 1] = {0};
+  wchar_t double_terminated_path_to[MAX_PATH + 1] = {0};
+#pragma warning(suppress:4996)  // don't complain about wcscpy deprecation
+  wcscpy(double_terminated_path_from, from_path.value().c_str());
+#pragma warning(suppress:4996)  // don't complain about wcscpy deprecation
+  wcscpy(double_terminated_path_to, to_path.value().c_str());
+
+  SHFILEOPSTRUCT file_operation = {0};
+  file_operation.wFunc = FO_COPY;
+  file_operation.pFrom = double_terminated_path_from;
+  file_operation.pTo = double_terminated_path_to;
+  file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION |
+                          FOF_NOCONFIRMMKDIR;
+  if (!recursive)
+    file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
+
+  return (SHFileOperation(&file_operation) == 0);
+}
+
+bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
+                   bool recursive) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  if (recursive)
+    return ShellCopy(from_path, to_path, true);
+
+  // The following code assumes that from path is a directory.
+  DCHECK(DirectoryExists(from_path));
+
+  // Instead of creating a new directory, we copy the old one to include the
+  // security information of the folder as part of the copy.
+  if (!PathExists(to_path)) {
+    // Except that Vista fails to do that, and instead do a recursive copy if
+    // the target directory doesn't exist.
+    if (base::win::GetVersion() >= base::win::VERSION_VISTA)
+      CreateDirectory(to_path);
+    else
+      ShellCopy(from_path, to_path, false);
+  }
+
+  FilePath directory = from_path.Append(L"*.*");
+  return ShellCopy(directory, to_path, false);
+}
+
+bool CopyAndDeleteDirectory(const FilePath& from_path,
+                            const FilePath& to_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (CopyDirectory(from_path, to_path, true)) {
+    if (Delete(from_path, true)) {
+      return true;
+    }
+    // Like Move, this function is not transactional, so we just
+    // leave the copied bits behind if deleting from_path fails.
+    // If to_path exists previously then we have already overwritten
+    // it by now, we don't get better off by deleting the new bits.
+  }
+  return false;
+}
+
+
+bool PathExists(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES);
+}
+
+bool PathIsWritable(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  HANDLE dir =
+      CreateFile(path.value().c_str(), FILE_ADD_FILE, kFileShareAll,
+                 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+  if (dir == INVALID_HANDLE_VALUE)
+    return false;
+
+  CloseHandle(dir);
+  return true;
+}
+
+bool DirectoryExists(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DWORD fileattr = GetFileAttributes(path.value().c_str());
+  if (fileattr != INVALID_FILE_ATTRIBUTES)
+    return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0;
+  return false;
+}
+
+bool GetFileCreationLocalTimeFromHandle(HANDLE file_handle,
+                                        LPSYSTEMTIME creation_time) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (!file_handle)
+    return false;
+
+  FILETIME utc_filetime;
+  if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
+    return false;
+
+  FILETIME local_filetime;
+  if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
+    return false;
+
+  return !!FileTimeToSystemTime(&local_filetime, creation_time);
+}
+
+bool GetFileCreationLocalTime(const std::wstring& filename,
+                              LPSYSTEMTIME creation_time) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  base::win::ScopedHandle file_handle(
+      CreateFile(filename.c_str(), GENERIC_READ, kFileShareAll, NULL,
+                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
+  return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
+}
+
+bool GetTempDir(FilePath* path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  wchar_t temp_path[MAX_PATH + 1];
+  DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
+  if (path_len >= MAX_PATH || path_len <= 0)
+    return false;
+  // TODO(evanm): the old behavior of this function was to always strip the
+  // trailing slash.  We duplicate this here, but it shouldn't be necessary
+  // when everyone is using the appropriate FilePath APIs.
+  *path = FilePath(temp_path).StripTrailingSeparators();
+  return true;
+}
+
+bool GetShmemTempDir(FilePath* path, bool executable) {
+  return GetTempDir(path);
+}
+
+bool CreateTemporaryFile(FilePath* path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  FilePath temp_file;
+
+  if (!GetTempDir(path))
+    return false;
+
+  if (CreateTemporaryFileInDir(*path, &temp_file)) {
+    *path = temp_file;
+    return true;
+  }
+
+  return false;
+}
+
+FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return CreateAndOpenTemporaryFile(path);
+}
+
+// On POSIX we have semantics to create and open a temporary file
+// atomically.
+// TODO(jrg): is there equivalent call to use on Windows instead of
+// going 2-step?
+FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (!CreateTemporaryFileInDir(dir, path)) {
+    return NULL;
+  }
+  // Open file in binary mode, to avoid problems with fwrite. On Windows
+  // it replaces \n's with \r\n's, which may surprise you.
+  // Reference: http://msdn.microsoft.com/en-us/library/h9t88zwz(VS.71).aspx
+  return OpenFile(*path, "wb+");
+}
+
+bool CreateTemporaryFileInDir(const FilePath& dir,
+                              FilePath* temp_file) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  wchar_t temp_name[MAX_PATH + 1];
+
+  if (!GetTempFileName(dir.value().c_str(), L"", 0, temp_name)) {
+    DPLOG(WARNING) << "Failed to get temporary file name in " << dir.value();
+    return false;
+  }
+
+  DWORD path_len = GetLongPathName(temp_name, temp_name, MAX_PATH);
+  if (path_len > MAX_PATH + 1 || path_len == 0) {
+    DPLOG(WARNING) << "Failed to get long path name for " << temp_name;
+    return false;
+  }
+
+  std::wstring temp_file_str;
+  temp_file_str.assign(temp_name, path_len);
+  *temp_file = FilePath(temp_file_str);
+  return true;
+}
+
+bool CreateTemporaryDirInDir(const FilePath& base_dir,
+                             const FilePath::StringType& prefix,
+                             FilePath* new_dir) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  FilePath path_to_create;
+  srand(static_cast<uint32>(time(NULL)));
+
+  for (int count = 0; count < 50; ++count) {
+    // Try create a new temporary directory with random generated name. If
+    // the one exists, keep trying another path name until we reach some limit.
+    string16 new_dir_name;
+    new_dir_name.assign(prefix);
+    new_dir_name.append(base::IntToString16(::base::GetCurrentProcId()));
+    new_dir_name.push_back('_');
+    new_dir_name.append(base::IntToString16(rand() % kint16max));
+
+    path_to_create = base_dir.Append(new_dir_name);
+    if (::CreateDirectory(path_to_create.value().c_str(), NULL)) {
+      *new_dir = path_to_create;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool CreateNewTempDirectory(const FilePath::StringType& prefix,
+                            FilePath* new_temp_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  FilePath system_temp_dir;
+  if (!GetTempDir(&system_temp_dir))
+    return false;
+
+  return CreateTemporaryDirInDir(system_temp_dir, prefix, new_temp_path);
+}
+
+bool CreateDirectory(const FilePath& full_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // If the path exists, we've succeeded if it's a directory, failed otherwise.
+  const wchar_t* full_path_str = full_path.value().c_str();
+  DWORD fileattr = ::GetFileAttributes(full_path_str);
+  if (fileattr != INVALID_FILE_ATTRIBUTES) {
+    if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+      DVLOG(1) << "CreateDirectory(" << full_path_str << "), "
+               << "directory already exists.";
+      return true;
+    }
+    DLOG(WARNING) << "CreateDirectory(" << full_path_str << "), "
+                  << "conflicts with existing file.";
+    return false;
+  }
+
+  // Invariant:  Path does not exist as file or directory.
+
+  // Attempt to create the parent recursively.  This will immediately return
+  // true if it already exists, otherwise will create all required parent
+  // directories starting with the highest-level missing parent.
+  FilePath parent_path(full_path.DirName());
+  if (parent_path.value() == full_path.value()) {
+    return false;
+  }
+  if (!CreateDirectory(parent_path)) {
+    DLOG(WARNING) << "Failed to create one of the parent directories.";
+    return false;
+  }
+
+  if (!::CreateDirectory(full_path_str, NULL)) {
+    DWORD error_code = ::GetLastError();
+    if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path)) {
+      // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we
+      // were racing with someone creating the same directory, or a file
+      // with the same path.  If DirectoryExists() returns true, we lost the
+      // race to create the same directory.
+      return true;
+    } else {
+      DLOG(WARNING) << "Failed to create directory " << full_path_str
+                    << ", last error is " << error_code << ".";
+      return false;
+    }
+  } else {
+    return true;
+  }
+}
+
+// TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle
+// them if we do decide to.
+bool IsLink(const FilePath& file_path) {
+  return false;
+}
+
+bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  WIN32_FILE_ATTRIBUTE_DATA attr;
+  if (!GetFileAttributesEx(file_path.value().c_str(),
+                           GetFileExInfoStandard, &attr)) {
+    return false;
+  }
+
+  ULARGE_INTEGER size;
+  size.HighPart = attr.nFileSizeHigh;
+  size.LowPart = attr.nFileSizeLow;
+  results->size = size.QuadPart;
+
+  results->is_directory =
+      (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+  results->last_modified = base::Time::FromFileTime(attr.ftLastWriteTime);
+  results->last_accessed = base::Time::FromFileTime(attr.ftLastAccessTime);
+  results->creation_time = base::Time::FromFileTime(attr.ftCreationTime);
+
+  return true;
+}
+
+FILE* OpenFile(const FilePath& filename, const char* mode) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  std::wstring w_mode = ASCIIToWide(std::string(mode));
+  return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
+}
+
+FILE* OpenFile(const std::string& filename, const char* mode) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return _fsopen(filename.c_str(), mode, _SH_DENYNO);
+}
+
+int ReadFile(const FilePath& filename, char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                          GENERIC_READ,
+                                          FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                          NULL,
+                                          OPEN_EXISTING,
+                                          FILE_FLAG_SEQUENTIAL_SCAN,
+                                          NULL));
+  if (!file)
+    return -1;
+
+  DWORD read;
+  if (::ReadFile(file, data, size, &read, NULL) &&
+      static_cast<int>(read) == size)
+    return read;
+  return -1;
+}
+
+int WriteFile(const FilePath& filename, const char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                          GENERIC_WRITE,
+                                          0,
+                                          NULL,
+                                          CREATE_ALWAYS,
+                                          0,
+                                          NULL));
+  if (!file) {
+    DLOG(WARNING) << "CreateFile failed for path " << filename.value()
+                  << " error code=" << GetLastError();
+    return -1;
+  }
+
+  DWORD written;
+  BOOL result = ::WriteFile(file, data, size, &written, NULL);
+  if (result && static_cast<int>(written) == size)
+    return written;
+
+  if (!result) {
+    // WriteFile failed.
+    DLOG(WARNING) << "writing file " << filename.value()
+                  << " failed, error code=" << GetLastError();
+  } else {
+    // Didn't write all the bytes.
+    DLOG(WARNING) << "wrote" << written << " bytes to "
+                  << filename.value() << " expected " << size;
+  }
+  return -1;
+}
+
+int AppendToFile(const FilePath& filename, const char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                          FILE_APPEND_DATA,
+                                          0,
+                                          NULL,
+                                          OPEN_EXISTING,
+                                          0,
+                                          NULL));
+  if (!file) {
+    DLOG(WARNING) << "CreateFile failed for path " << filename.value()
+                  << " error code=" << GetLastError();
+    return -1;
+  }
+
+  DWORD written;
+  BOOL result = ::WriteFile(file, data, size, &written, NULL);
+  if (result && static_cast<int>(written) == size)
+    return written;
+
+  if (!result) {
+    // WriteFile failed.
+    DLOG(WARNING) << "writing file " << filename.value()
+                  << " failed, error code=" << GetLastError();
+  } else {
+    // Didn't write all the bytes.
+    DLOG(WARNING) << "wrote" << written << " bytes to "
+                  << filename.value() << " expected " << size;
+  }
+  return -1;
+}
+
+// Gets the current working directory for the process.
+bool GetCurrentDirectory(FilePath* dir) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  wchar_t system_buffer[MAX_PATH];
+  system_buffer[0] = 0;
+  DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
+  if (len == 0 || len > MAX_PATH)
+    return false;
+  // TODO(evanm): the old behavior of this function was to always strip the
+  // trailing slash.  We duplicate this here, but it shouldn't be necessary
+  // when everyone is using the appropriate FilePath APIs.
+  std::wstring dir_str(system_buffer);
+  *dir = FilePath(dir_str).StripTrailingSeparators();
+  return true;
+}
+
+// Sets the current working directory for the process.
+bool SetCurrentDirectory(const FilePath& directory) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  BOOL ret = ::SetCurrentDirectory(directory.value().c_str());
+  return ret != 0;
+}
+
+///////////////////////////////////////////////
+// FileEnumerator
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+                               bool recursive,
+                               int file_type)
+    : recursive_(recursive),
+      file_type_(file_type),
+      has_find_data_(false),
+      find_handle_(INVALID_HANDLE_VALUE) {
+  // INCLUDE_DOT_DOT must not be specified if recursive.
+  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
+  memset(&find_data_, 0, sizeof(find_data_));
+  pending_paths_.push(root_path);
+}
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+                               bool recursive,
+                               int file_type,
+                               const FilePath::StringType& pattern)
+    : recursive_(recursive),
+      file_type_(file_type),
+      has_find_data_(false),
+      pattern_(pattern),
+      find_handle_(INVALID_HANDLE_VALUE) {
+  // INCLUDE_DOT_DOT must not be specified if recursive.
+  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
+  memset(&find_data_, 0, sizeof(find_data_));
+  pending_paths_.push(root_path);
+}
+
+FileEnumerator::~FileEnumerator() {
+  if (find_handle_ != INVALID_HANDLE_VALUE)
+    FindClose(find_handle_);
+}
+
+void FileEnumerator::GetFindInfo(FindInfo* info) {
+  DCHECK(info);
+
+  if (!has_find_data_)
+    return;
+
+  memcpy(info, &find_data_, sizeof(*info));
+}
+
+// static
+bool FileEnumerator::IsDirectory(const FindInfo& info) {
+  return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+// static
+FilePath FileEnumerator::GetFilename(const FindInfo& find_info) {
+  return FilePath(find_info.cFileName);
+}
+
+// static
+int64 FileEnumerator::GetFilesize(const FindInfo& find_info) {
+  ULARGE_INTEGER size;
+  size.HighPart = find_info.nFileSizeHigh;
+  size.LowPart = find_info.nFileSizeLow;
+  DCHECK_LE(size.QuadPart, std::numeric_limits<int64>::max());
+  return static_cast<int64>(size.QuadPart);
+}
+
+// static
+base::Time FileEnumerator::GetLastModifiedTime(const FindInfo& find_info) {
+  return base::Time::FromFileTime(find_info.ftLastWriteTime);
+}
+
+FilePath FileEnumerator::Next() {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  while (has_find_data_ || !pending_paths_.empty()) {
+    if (!has_find_data_) {
+      // The last find FindFirstFile operation is done, prepare a new one.
+      root_path_ = pending_paths_.top();
+      pending_paths_.pop();
+
+      // Start a new find operation.
+      FilePath src = root_path_;
+
+      if (pattern_.empty())
+        src = src.Append(L"*");  // No pattern = match everything.
+      else
+        src = src.Append(pattern_);
+
+      find_handle_ = FindFirstFile(src.value().c_str(), &find_data_);
+      has_find_data_ = true;
+    } else {
+      // Search for the next file/directory.
+      if (!FindNextFile(find_handle_, &find_data_)) {
+        FindClose(find_handle_);
+        find_handle_ = INVALID_HANDLE_VALUE;
+      }
+    }
+
+    if (INVALID_HANDLE_VALUE == find_handle_) {
+      has_find_data_ = false;
+
+      // This is reached when we have finished a directory and are advancing to
+      // the next one in the queue. We applied the pattern (if any) to the files
+      // in the root search directory, but for those directories which were
+      // matched, we want to enumerate all files inside them. This will happen
+      // when the handle is empty.
+      pattern_ = FilePath::StringType();
+
+      continue;
+    }
+
+    FilePath cur_file(find_data_.cFileName);
+    if (ShouldSkip(cur_file))
+      continue;
+
+    // Construct the absolute filename.
+    cur_file = root_path_.Append(find_data_.cFileName);
+
+    if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+      if (recursive_) {
+        // If |cur_file| is a directory, and we are doing recursive searching,
+        // add it to pending_paths_ so we scan it after we finish scanning this
+        // directory.
+        pending_paths_.push(cur_file);
+      }
+      if (file_type_ & FileEnumerator::DIRECTORIES)
+        return cur_file;
+    } else if (file_type_ & FileEnumerator::FILES) {
+      return cur_file;
+    }
+  }
+
+  return FilePath();
+}
+
+///////////////////////////////////////////////
+// MemoryMappedFile
+
+MemoryMappedFile::MemoryMappedFile()
+    : file_(INVALID_HANDLE_VALUE),
+      file_mapping_(INVALID_HANDLE_VALUE),
+      data_(NULL),
+      length_(INVALID_FILE_SIZE) {
+}
+
+bool MemoryMappedFile::InitializeAsImageSection(const FilePath& file_name) {
+  if (IsValid())
+    return false;
+  file_ = base::CreatePlatformFile(
+      file_name, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+      NULL, NULL);
+
+  if (file_ == base::kInvalidPlatformFileValue) {
+    DLOG(ERROR) << "Couldn't open " << file_name.value();
+    return false;
+  }
+
+  if (!MapFileToMemoryInternalEx(SEC_IMAGE)) {
+    CloseHandles();
+    return false;
+  }
+
+  return true;
+}
+
+bool MemoryMappedFile::MapFileToMemoryInternal() {
+  return MapFileToMemoryInternalEx(0);
+}
+
+bool MemoryMappedFile::MapFileToMemoryInternalEx(int flags) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  if (file_ == INVALID_HANDLE_VALUE)
+    return false;
+
+  length_ = ::GetFileSize(file_, NULL);
+  if (length_ == INVALID_FILE_SIZE)
+    return false;
+
+  file_mapping_ = ::CreateFileMapping(file_, NULL, PAGE_READONLY | flags,
+                                      0, 0, NULL);
+  if (!file_mapping_) {
+    // According to msdn, system error codes are only reserved up to 15999.
+    // http://msdn.microsoft.com/en-us/library/ms681381(v=VS.85).aspx.
+    UMA_HISTOGRAM_ENUMERATION("MemoryMappedFile.CreateFileMapping",
+                              logging::GetLastSystemErrorCode(), 16000);
+    return false;
+  }
+
+  data_ = static_cast<uint8*>(
+      ::MapViewOfFile(file_mapping_, FILE_MAP_READ, 0, 0, 0));
+  if (!data_) {
+    UMA_HISTOGRAM_ENUMERATION("MemoryMappedFile.MapViewOfFile",
+                              logging::GetLastSystemErrorCode(), 16000);
+  }
+  return data_ != NULL;
+}
+
+void MemoryMappedFile::CloseHandles() {
+  if (data_)
+    ::UnmapViewOfFile(data_);
+  if (file_mapping_ != INVALID_HANDLE_VALUE)
+    ::CloseHandle(file_mapping_);
+  if (file_ != INVALID_HANDLE_VALUE)
+    ::CloseHandle(file_);
+
+  data_ = NULL;
+  file_mapping_ = file_ = INVALID_HANDLE_VALUE;
+  length_ = INVALID_FILE_SIZE;
+}
+
+bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info,
+                              const base::Time& cutoff_time) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  FILETIME file_time = cutoff_time.ToFileTime();
+  long result = CompareFileTime(&find_info.ftLastWriteTime,  // NOLINT
+                                &file_time);
+  return result == 1 || result == 0;
+}
+
+bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  FilePath mapped_file;
+  if (!NormalizeToNativeFilePath(path, &mapped_file))
+    return false;
+  // NormalizeToNativeFilePath() will return a path that starts with
+  // "\Device\Harddisk...".  Helper DevicePathToDriveLetterPath()
+  // will find a drive letter which maps to the path's device, so
+  // that we return a path starting with a drive letter.
+  return DevicePathToDriveLetterPath(mapped_file, real_path);
+}
+
+bool DevicePathToDriveLetterPath(const FilePath& nt_device_path,
+                                 FilePath* out_drive_letter_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // Get the mapping of drive letters to device paths.
+  const int kDriveMappingSize = 1024;
+  wchar_t drive_mapping[kDriveMappingSize] = {'\0'};
+  if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) {
+    DLOG(ERROR) << "Failed to get drive mapping.";
+    return false;
+  }
+
+  // The drive mapping is a sequence of null terminated strings.
+  // The last string is empty.
+  wchar_t* drive_map_ptr = drive_mapping;
+  wchar_t device_path_as_string[MAX_PATH];
+  wchar_t drive[] = L" :";
+
+  // For each string in the drive mapping, get the junction that links
+  // to it.  If that junction is a prefix of |device_path|, then we
+  // know that |drive| is the real path prefix.
+  while (*drive_map_ptr) {
+    drive[0] = drive_map_ptr[0];  // Copy the drive letter.
+
+    if (QueryDosDevice(drive, device_path_as_string, MAX_PATH)) {
+      FilePath device_path(device_path_as_string);
+      if (device_path == nt_device_path ||
+          device_path.IsParent(nt_device_path)) {
+        *out_drive_letter_path = FilePath(drive +
+            nt_device_path.value().substr(wcslen(device_path_as_string)));
+        return true;
+      }
+    }
+    // Move to the next drive letter string, which starts one
+    // increment after the '\0' that terminates the current string.
+    while (*drive_map_ptr++);
+  }
+
+  // No drive matched.  The path does not start with a device junction
+  // that is mounted as a drive letter.  This means there is no drive
+  // letter path to the volume that holds |device_path|, so fail.
+  return false;
+}
+
+bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  // In Vista, GetFinalPathNameByHandle() would give us the real path
+  // from a file handle.  If we ever deprecate XP, consider changing the
+  // code below to a call to GetFinalPathNameByHandle().  The method this
+  // function uses is explained in the following msdn article:
+  // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
+  base::win::ScopedHandle file_handle(
+      ::CreateFile(path.value().c_str(),
+                   GENERIC_READ,
+                   kFileShareAll,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_ATTRIBUTE_NORMAL,
+                   NULL));
+  if (!file_handle)
+    return false;
+
+  // Create a file mapping object.  Can't easily use MemoryMappedFile, because
+  // we only map the first byte, and need direct access to the handle. You can
+  // not map an empty file, this call fails in that case.
+  base::win::ScopedHandle file_map_handle(
+      ::CreateFileMapping(file_handle.Get(),
+                          NULL,
+                          PAGE_READONLY,
+                          0,
+                          1,  // Just one byte.  No need to look at the data.
+                          NULL));
+  if (!file_map_handle)
+    return false;
+
+  // Use a view of the file to get the path to the file.
+  void* file_view = MapViewOfFile(file_map_handle.Get(),
+                                  FILE_MAP_READ, 0, 0, 1);
+  if (!file_view)
+    return false;
+
+  // The expansion of |path| into a full path may make it longer.
+  // GetMappedFileName() will fail if the result is longer than MAX_PATH.
+  // Pad a bit to be safe.  If kMaxPathLength is ever changed to be less
+  // than MAX_PATH, it would be nessisary to test that GetMappedFileName()
+  // not return kMaxPathLength.  This would mean that only part of the
+  // path fit in |mapped_file_path|.
+  const int kMaxPathLength = MAX_PATH + 10;
+  wchar_t mapped_file_path[kMaxPathLength];
+  bool success = false;
+  HANDLE cp = GetCurrentProcess();
+  if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) {
+    *nt_path = FilePath(mapped_file_path);
+    success = true;
+  }
+  ::UnmapViewOfFile(file_view);
+  return success;
+}
+
+}  // namespace file_util
diff --git a/base/file_version_info.h b/base/file_version_info.h
new file mode 100644
index 0000000..84eec41
--- /dev/null
+++ b/base/file_version_info.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILE_VERSION_INFO_H__
+#define BASE_FILE_VERSION_INFO_H__
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+#endif  // OS_WIN
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/string16.h"
+
+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 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.
+  BASE_EXPORT static FileVersionInfo* CreateFileVersionInfo(
+      const 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.
+  BASE_EXPORT static FileVersionInfo* CreateFileVersionInfoForModule(
+      HMODULE module);
+
+  // Creates a FileVersionInfo for the current module. Returns NULL in case
+  // of error. The returned object should be deleted when you are done with it.
+  // This function should be inlined so that the "current module" is evaluated
+  // correctly, instead of being the module that contains base.
+  __forceinline static FileVersionInfo*
+  CreateFileVersionInfoForCurrentModule() {
+    HMODULE module = reinterpret_cast<HMODULE>(&__ImageBase);
+    return CreateFileVersionInfoForModule(module);
+  }
+#else
+  // Creates a FileVersionInfo for the current module. Returns NULL in case
+  // of error. The returned object should be deleted when you are done with it.
+  BASE_EXPORT static FileVersionInfo* CreateFileVersionInfoForCurrentModule();
+#endif  // OS_WIN
+
+  // Accessors to the different version properties.
+  // Returns an empty string if the property is not found.
+  virtual string16 company_name() = 0;
+  virtual string16 company_short_name() = 0;
+  virtual string16 product_name() = 0;
+  virtual string16 product_short_name() = 0;
+  virtual string16 internal_name() = 0;
+  virtual string16 product_version() = 0;
+  virtual string16 private_build() = 0;
+  virtual string16 special_build() = 0;
+  virtual string16 comments() = 0;
+  virtual string16 original_filename() = 0;
+  virtual string16 file_description() = 0;
+  virtual string16 file_version() = 0;
+  virtual string16 legal_copyright() = 0;
+  virtual string16 legal_trademarks() = 0;
+  virtual string16 last_change() = 0;
+  virtual bool is_official_build() = 0;
+};
+
+#endif  // BASE_FILE_VERSION_INFO_H__
diff --git a/base/file_version_info_mac.h b/base/file_version_info_mac.h
new file mode 100644
index 0000000..0ab3296
--- /dev/null
+++ b/base/file_version_info_mac.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILE_VERSION_INFO_MAC_H_
+#define BASE_FILE_VERSION_INFO_MAC_H_
+
+#include <string>
+
+#include "base/file_version_info.h"
+#include "base/memory/scoped_nsobject.h"
+
+#ifdef __OBJC__
+@class NSBundle;
+#else
+class NSBundle;
+#endif
+
+class FileVersionInfoMac : public FileVersionInfo {
+ public:
+  explicit FileVersionInfoMac(NSBundle *bundle);
+  virtual ~FileVersionInfoMac();
+
+  // Accessors to the different version properties.
+  // Returns an empty string if the property is not found.
+  virtual string16 company_name() OVERRIDE;
+  virtual string16 company_short_name() OVERRIDE;
+  virtual string16 product_name() OVERRIDE;
+  virtual string16 product_short_name() OVERRIDE;
+  virtual string16 internal_name() OVERRIDE;
+  virtual string16 product_version() OVERRIDE;
+  virtual string16 private_build() OVERRIDE;
+  virtual string16 special_build() OVERRIDE;
+  virtual string16 comments() OVERRIDE;
+  virtual string16 original_filename() OVERRIDE;
+  virtual string16 file_description() OVERRIDE;
+  virtual string16 file_version() OVERRIDE;
+  virtual string16 legal_copyright() OVERRIDE;
+  virtual string16 legal_trademarks() OVERRIDE;
+  virtual string16 last_change() OVERRIDE;
+  virtual bool is_official_build() OVERRIDE;
+
+ private:
+  // Returns a string16 value for a property name.
+  // Returns the empty string if the property does not exist.
+  string16 GetString16Value(CFStringRef name);
+
+  scoped_nsobject<NSBundle> bundle_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileVersionInfoMac);
+};
+
+#endif  // BASE_FILE_VERSION_INFO_MAC_H_
diff --git a/base/file_version_info_mac.mm b/base/file_version_info_mac.mm
new file mode 100644
index 0000000..3a6df81
--- /dev/null
+++ b/base/file_version_info_mac.mm
@@ -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/file_version_info_mac.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/sys_string_conversions.h"
+
+FileVersionInfoMac::FileVersionInfoMac(NSBundle *bundle)
+    : bundle_([bundle retain]) {
+}
+
+FileVersionInfoMac::~FileVersionInfoMac() {}
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForCurrentModule() {
+  return CreateFileVersionInfo(base::mac::FrameworkBundlePath());
+}
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
+    const FilePath& file_path) {
+  NSString* path = base::SysUTF8ToNSString(file_path.value());
+  NSBundle* bundle = [NSBundle bundleWithPath:path];
+  return new FileVersionInfoMac(bundle);
+}
+
+string16 FileVersionInfoMac::company_name() {
+  return string16();
+}
+
+string16 FileVersionInfoMac::company_short_name() {
+  return string16();
+}
+
+string16 FileVersionInfoMac::internal_name() {
+  return string16();
+}
+
+string16 FileVersionInfoMac::product_name() {
+  return GetString16Value(kCFBundleNameKey);
+}
+
+string16 FileVersionInfoMac::product_short_name() {
+  return GetString16Value(kCFBundleNameKey);
+}
+
+string16 FileVersionInfoMac::comments() {
+  return string16();
+}
+
+string16 FileVersionInfoMac::legal_copyright() {
+  return GetString16Value(CFSTR("CFBundleGetInfoString"));
+}
+
+string16 FileVersionInfoMac::product_version() {
+  // On OS X, CFBundleVersion is used by LaunchServices, and must follow
+  // specific formatting rules, so the four-part Chrome version is in
+  // CFBundleShortVersionString. On iOS, however, CFBundleVersion can be the
+  // full version, but CFBundleShortVersionString has a policy-enfoced limit
+  // of three version components.
+#if defined(OS_IOS)
+  return GetString16Value(CFSTR("CFBundleVersion"));
+#else
+  return GetString16Value(CFSTR("CFBundleShortVersionString"));
+#endif  // defined(OS_IOS)
+}
+
+string16 FileVersionInfoMac::file_description() {
+  return string16();
+}
+
+string16 FileVersionInfoMac::legal_trademarks() {
+  return string16();
+}
+
+string16 FileVersionInfoMac::private_build() {
+  return string16();
+}
+
+string16 FileVersionInfoMac::file_version() {
+  return product_version();
+}
+
+string16 FileVersionInfoMac::original_filename() {
+  return GetString16Value(kCFBundleNameKey);
+}
+
+string16 FileVersionInfoMac::special_build() {
+  return string16();
+}
+
+string16 FileVersionInfoMac::last_change() {
+  return GetString16Value(CFSTR("SCMRevision"));
+}
+
+bool FileVersionInfoMac::is_official_build() {
+#if defined (GOOGLE_CHROME_BUILD)
+  return true;
+#else
+  return false;
+#endif
+}
+
+string16 FileVersionInfoMac::GetString16Value(CFStringRef name) {
+  if (bundle_) {
+    NSString *ns_name = base::mac::CFToNSCast(name);
+    NSString* value = [bundle_ objectForInfoDictionaryKey:ns_name];
+    if (value) {
+      return base::SysNSStringToUTF16(value);
+    }
+  }
+  return string16();
+}
diff --git a/base/file_version_info_unittest.cc b/base/file_version_info_unittest.cc
new file mode 100644
index 0000000..4184e04
--- /dev/null
+++ b/base/file_version_info_unittest.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/file_version_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "base/file_version_info_win.h"
+#endif
+
+namespace {
+
+class FileVersionInfoTest : public testing::Test {
+};
+
+#if defined(OS_WIN)
+FilePath GetTestDataPath() {
+  FilePath path;
+  PathService::Get(base::DIR_SOURCE_ROOT, &path);
+  path = path.AppendASCII("base");
+  path = path.AppendASCII("data");
+  path = path.AppendASCII("file_version_info_unittest");
+  return path;
+}
+#endif
+
+}
+
+#if defined(OS_WIN)
+TEST(FileVersionInfoTest, HardCodedProperties) {
+  const wchar_t* kDLLNames[] = {
+    L"FileVersionInfoTest1.dll"
+  };
+
+  const wchar_t* kExpectedValues[1][15] = {
+      // FileVersionInfoTest.dll
+      L"Goooooogle",                      // company_name
+      L"Google",                          // company_short_name
+      L"This is the product name",        // product_name
+      L"This is the product short name",  // product_short_name
+      L"The Internal Name",               // internal_name
+      L"4.3.2.1",                         // product_version
+      L"Private build property",          // private_build
+      L"Special build property",          // special_build
+      L"This is a particularly interesting comment",  // comments
+      L"This is the original filename",   // original_filename
+      L"This is my file description",     // file_description
+      L"1.2.3.4",                         // file_version
+      L"This is the legal copyright",     // legal_copyright
+      L"This is the legal trademarks",    // legal_trademarks
+      L"This is the last change",         // last_change
+  };
+
+  for (int i = 0; i < arraysize(kDLLNames); ++i) {
+    FilePath dll_path = GetTestDataPath();
+    dll_path = dll_path.Append(kDLLNames[i]);
+
+    scoped_ptr<FileVersionInfo> version_info(
+        FileVersionInfo::CreateFileVersionInfo(dll_path));
+
+    int j = 0;
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->company_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->company_short_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_short_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->internal_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_version());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->private_build());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->special_build());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->comments());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->original_filename());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->file_description());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->file_version());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->legal_copyright());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->legal_trademarks());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->last_change());
+  }
+}
+#endif
+
+#if defined(OS_WIN)
+TEST(FileVersionInfoTest, IsOfficialBuild) {
+  const wchar_t* kDLLNames[] = {
+    L"FileVersionInfoTest1.dll",
+    L"FileVersionInfoTest2.dll"
+  };
+
+  const bool kExpected[] = {
+    true,
+    false,
+  };
+
+  // Test consistency check.
+  ASSERT_EQ(arraysize(kDLLNames), arraysize(kExpected));
+
+  for (int i = 0; i < arraysize(kDLLNames); ++i) {
+    FilePath dll_path = GetTestDataPath();
+    dll_path = dll_path.Append(kDLLNames[i]);
+
+    scoped_ptr<FileVersionInfo> version_info(
+        FileVersionInfo::CreateFileVersionInfo(dll_path));
+
+    EXPECT_EQ(kExpected[i], version_info->is_official_build());
+  }
+}
+#endif
+
+#if defined(OS_WIN)
+TEST(FileVersionInfoTest, CustomProperties) {
+  FilePath dll_path = GetTestDataPath();
+  dll_path = dll_path.AppendASCII("FileVersionInfoTest1.dll");
+
+  scoped_ptr<FileVersionInfo> version_info(
+      FileVersionInfo::CreateFileVersionInfo(dll_path));
+
+  // Test few existing properties.
+  std::wstring str;
+  FileVersionInfoWin* version_info_win =
+      static_cast<FileVersionInfoWin*>(version_info.get());
+  EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 1",  &str));
+  EXPECT_EQ(L"Un", str);
+  EXPECT_EQ(L"Un", version_info_win->GetStringValue(L"Custom prop 1"));
+
+  EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 2",  &str));
+  EXPECT_EQ(L"Deux", str);
+  EXPECT_EQ(L"Deux", version_info_win->GetStringValue(L"Custom prop 2"));
+
+  EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 3",  &str));
+  EXPECT_EQ(L"1600 Amphitheatre Parkway Mountain View, CA 94043", str);
+  EXPECT_EQ(L"1600 Amphitheatre Parkway Mountain View, CA 94043",
+            version_info_win->GetStringValue(L"Custom prop 3"));
+
+  // Test an non-existing property.
+  EXPECT_FALSE(version_info_win->GetValue(L"Unknown property",  &str));
+  EXPECT_EQ(L"", version_info_win->GetStringValue(L"Unknown property"));
+}
+#endif
diff --git a/base/file_version_info_win.cc b/base/file_version_info_win.cc
new file mode 100644
index 0000000..6528ca3
--- /dev/null
+++ b/base/file_version_info_win.cc
@@ -0,0 +1,187 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_version_info_win.h"
+
+#include <windows.h>
+
+#include "base/file_path.h"
+#include "base/file_version_info.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
+
+FileVersionInfoWin::FileVersionInfoWin(void* data, int language, int code_page)
+    : language_(language), code_page_(code_page) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  data_.reset((char*) data);
+  fixed_file_info_ = NULL;
+  UINT size;
+  ::VerQueryValue(data_.get(), L"\\", (LPVOID*)&fixed_file_info_, &size);
+}
+
+FileVersionInfoWin::~FileVersionInfoWin() {
+  DCHECK(data_.get());
+}
+
+typedef struct {
+  WORD language;
+  WORD code_page;
+} LanguageAndCodePage;
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForModule(
+    HMODULE module) {
+  // Note that the use of MAX_PATH is basically in line with what we do for
+  // all registered paths (PathProviderWin).
+  wchar_t system_buffer[MAX_PATH];
+  system_buffer[0] = 0;
+  if (!GetModuleFileName(module, system_buffer, MAX_PATH))
+    return NULL;
+
+  FilePath app_path(system_buffer);
+  return CreateFileVersionInfo(app_path);
+}
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
+    const FilePath& file_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  DWORD dummy;
+  const wchar_t* path = file_path.value().c_str();
+  DWORD length = ::GetFileVersionInfoSize(path, &dummy);
+  if (length == 0)
+    return NULL;
+
+  void* data = calloc(length, 1);
+  if (!data)
+    return NULL;
+
+  if (!::GetFileVersionInfo(path, dummy, length, data)) {
+    free(data);
+    return NULL;
+  }
+
+  LanguageAndCodePage* translate = NULL;
+  uint32 page_count;
+  BOOL query_result = VerQueryValue(data, L"\\VarFileInfo\\Translation",
+                                   (void**) &translate, &page_count);
+
+  if (query_result && translate) {
+    return new FileVersionInfoWin(data, translate->language,
+                                  translate->code_page);
+
+  } else {
+    free(data);
+    return NULL;
+  }
+}
+
+string16 FileVersionInfoWin::company_name() {
+  return GetStringValue(L"CompanyName");
+}
+
+string16 FileVersionInfoWin::company_short_name() {
+  return GetStringValue(L"CompanyShortName");
+}
+
+string16 FileVersionInfoWin::internal_name() {
+  return GetStringValue(L"InternalName");
+}
+
+string16 FileVersionInfoWin::product_name() {
+  return GetStringValue(L"ProductName");
+}
+
+string16 FileVersionInfoWin::product_short_name() {
+  return GetStringValue(L"ProductShortName");
+}
+
+string16 FileVersionInfoWin::comments() {
+  return GetStringValue(L"Comments");
+}
+
+string16 FileVersionInfoWin::legal_copyright() {
+  return GetStringValue(L"LegalCopyright");
+}
+
+string16 FileVersionInfoWin::product_version() {
+  return GetStringValue(L"ProductVersion");
+}
+
+string16 FileVersionInfoWin::file_description() {
+  return GetStringValue(L"FileDescription");
+}
+
+string16 FileVersionInfoWin::legal_trademarks() {
+  return GetStringValue(L"LegalTrademarks");
+}
+
+string16 FileVersionInfoWin::private_build() {
+  return GetStringValue(L"PrivateBuild");
+}
+
+string16 FileVersionInfoWin::file_version() {
+  return GetStringValue(L"FileVersion");
+}
+
+string16 FileVersionInfoWin::original_filename() {
+  return GetStringValue(L"OriginalFilename");
+}
+
+string16 FileVersionInfoWin::special_build() {
+  return GetStringValue(L"SpecialBuild");
+}
+
+string16 FileVersionInfoWin::last_change() {
+  return GetStringValue(L"LastChange");
+}
+
+bool FileVersionInfoWin::is_official_build() {
+  return (GetStringValue(L"Official Build").compare(L"1") == 0);
+}
+
+bool FileVersionInfoWin::GetValue(const wchar_t* name,
+                                  std::wstring* value_str) {
+  WORD lang_codepage[8];
+  int i = 0;
+  // Use the language and codepage from the DLL.
+  lang_codepage[i++] = language_;
+  lang_codepage[i++] = code_page_;
+  // Use the default language and codepage from the DLL.
+  lang_codepage[i++] = ::GetUserDefaultLangID();
+  lang_codepage[i++] = code_page_;
+  // Use the language from the DLL and Latin codepage (most common).
+  lang_codepage[i++] = language_;
+  lang_codepage[i++] = 1252;
+  // Use the default language and Latin codepage (most common).
+  lang_codepage[i++] = ::GetUserDefaultLangID();
+  lang_codepage[i++] = 1252;
+
+  i = 0;
+  while (i < arraysize(lang_codepage)) {
+    wchar_t sub_block[MAX_PATH];
+    WORD language = lang_codepage[i++];
+    WORD code_page = lang_codepage[i++];
+    _snwprintf_s(sub_block, MAX_PATH, MAX_PATH,
+                 L"\\StringFileInfo\\%04x%04x\\%ls", language, code_page, name);
+    LPVOID value = NULL;
+    uint32 size;
+    BOOL r = ::VerQueryValue(data_.get(), sub_block, &value, &size);
+    if (r && value) {
+      value_str->assign(static_cast<wchar_t*>(value));
+      return true;
+    }
+  }
+  return false;
+}
+
+std::wstring FileVersionInfoWin::GetStringValue(const wchar_t* name) {
+  std::wstring str;
+  if (GetValue(name, &str))
+    return str;
+  else
+    return L"";
+}
diff --git a/base/file_version_info_win.h b/base/file_version_info_win.h
new file mode 100644
index 0000000..a378577
--- /dev/null
+++ b/base/file_version_info_win.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILE_VERSION_INFO_WIN_H_
+#define BASE_FILE_VERSION_INFO_WIN_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/file_version_info.h"
+#include "base/memory/scoped_ptr.h"
+
+struct tagVS_FIXEDFILEINFO;
+typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
+
+class FileVersionInfoWin : public FileVersionInfo {
+ public:
+  BASE_EXPORT FileVersionInfoWin(void* data, int language, int code_page);
+  BASE_EXPORT ~FileVersionInfoWin();
+
+  // Accessors to the different version properties.
+  // Returns an empty string if the property is not found.
+  virtual string16 company_name() OVERRIDE;
+  virtual string16 company_short_name() OVERRIDE;
+  virtual string16 product_name() OVERRIDE;
+  virtual string16 product_short_name() OVERRIDE;
+  virtual string16 internal_name() OVERRIDE;
+  virtual string16 product_version() OVERRIDE;
+  virtual string16 private_build() OVERRIDE;
+  virtual string16 special_build() OVERRIDE;
+  virtual string16 comments() OVERRIDE;
+  virtual string16 original_filename() OVERRIDE;
+  virtual string16 file_description() OVERRIDE;
+  virtual string16 file_version() OVERRIDE;
+  virtual string16 legal_copyright() OVERRIDE;
+  virtual string16 legal_trademarks() OVERRIDE;
+  virtual string16 last_change() OVERRIDE;
+  virtual bool is_official_build() OVERRIDE;
+
+  // Lets you access other properties not covered above.
+  BASE_EXPORT bool GetValue(const wchar_t* name, std::wstring* value);
+
+  // Similar to GetValue but returns a wstring (empty string if the property
+  // does not exist).
+  BASE_EXPORT std::wstring GetStringValue(const wchar_t* name);
+
+  // Get the fixed file info if it exists. Otherwise NULL
+  VS_FIXEDFILEINFO* fixed_file_info() { return fixed_file_info_; }
+
+ private:
+  scoped_ptr_malloc<char> data_;
+  int language_;
+  int code_page_;
+  // This is a pointer into the data_ if it exists. Otherwise NULL.
+  VS_FIXEDFILEINFO* fixed_file_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileVersionInfoWin);
+};
+
+#endif  // BASE_FILE_VERSION_INFO_WIN_H_
diff --git a/base/files/OWNERS b/base/files/OWNERS
new file mode 100644
index 0000000..7260260
--- /dev/null
+++ b/base/files/OWNERS
@@ -0,0 +1,2 @@
+# for file_path_watcher*
+mnissler@chromium.org
diff --git a/base/files/dir_reader_fallback.h b/base/files/dir_reader_fallback.h
new file mode 100644
index 0000000..a435f25
--- /dev/null
+++ b/base/files/dir_reader_fallback.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_DIR_READER_FALLBACK_H_
+#define BASE_FILES_DIR_READER_FALLBACK_H_
+
+namespace base {
+
+class DirReaderFallback {
+ public:
+  // Open a directory. If |IsValid| is true, then |Next| can be called to start
+  // the iteration at the beginning of the directory.
+  explicit DirReaderFallback(const char* directory_path) {}
+
+  // After construction, IsValid returns true iff the directory was
+  // successfully opened.
+  bool IsValid() const { return false; }
+
+  // Move to the next entry returning false if the iteration is complete.
+  bool Next() { return false; }
+
+  // Return the name of the current directory entry.
+  const char* name() { return 0;}
+
+  // Return the file descriptor which is being used.
+  int fd() const { return -1; }
+
+  // Returns true if this is a no-op fallback class (for testing).
+  static bool IsFallback() { return true; }
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_DIR_READER_FALLBACK_H_
diff --git a/base/files/dir_reader_linux.h b/base/files/dir_reader_linux.h
new file mode 100644
index 0000000..8dd3530
--- /dev/null
+++ b/base/files/dir_reader_linux.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_DIR_READER_LINUX_H_
+#define BASE_FILES_DIR_READER_LINUX_H_
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/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 (HANDLE_EINTR(close(fd_)))
+        RAW_LOG(ERROR, "Failed to close directory handle");
+    }
+  }
+
+  bool IsValid() const {
+    return fd_ >= 0;
+  }
+
+  // Move to the next entry returning false if the iteration is complete.
+  bool Next() {
+    if (size_) {
+      linux_dirent* dirent = reinterpret_cast<linux_dirent*>(&buf_[offset_]);
+      offset_ += dirent->d_reclen;
+    }
+
+    if (offset_ != size_)
+      return true;
+
+    const int r = syscall(__NR_getdents64, fd_, buf_, sizeof(buf_));
+    if (r == 0)
+      return false;
+    if (r == -1) {
+      DPLOG(FATAL) << "getdents64 returned an error: " << errno;
+      return false;
+    }
+    size_ = r;
+    offset_ = 0;
+    return true;
+  }
+
+  const char* name() const {
+    if (!size_)
+      return NULL;
+
+    const linux_dirent* dirent =
+        reinterpret_cast<const linux_dirent*>(&buf_[offset_]);
+    return dirent->d_name;
+  }
+
+  int fd() const {
+    return fd_;
+  }
+
+  static bool IsFallback() {
+    return false;
+  }
+
+ private:
+  const int fd_;
+  unsigned char buf_[512];
+  size_t offset_, size_;
+
+  DISALLOW_COPY_AND_ASSIGN(DirReaderLinux);
+};
+
+}  // namespace base
+
+#endif // BASE_FILES_DIR_READER_LINUX_H_
diff --git a/base/files/dir_reader_posix.h b/base/files/dir_reader_posix.h
new file mode 100644
index 0000000..6a20ced
--- /dev/null
+++ b/base/files/dir_reader_posix.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_DIR_READER_POSIX_H_
+#define BASE_FILES_DIR_READER_POSIX_H_
+
+#include "build/build_config.h"
+
+// This header provides a class, DirReaderPosix, which allows one to open and
+// read from directories without allocating memory. For the interface, see
+// the generic fallback in dir_reader_fallback.h.
+
+// Mac note: OS X has getdirentries, but it only works if we restrict Chrome to
+// 32-bit inodes. There is a getdirentries64 syscall in 10.6, but it's not
+// wrapped and the direct syscall interface is unstable. Using an unstable API
+// seems worse than falling back to enumerating all file descriptors so we will
+// probably never implement this on the Mac.
+
+#if defined(OS_LINUX)
+#include "base/files/dir_reader_linux.h"
+#else
+#include "base/files/dir_reader_fallback.h"
+#endif
+
+namespace base {
+
+#if defined(OS_LINUX)
+typedef DirReaderLinux DirReaderPosix;
+#else
+typedef DirReaderFallback DirReaderPosix;
+#endif
+
+}  // namespace base
+
+#endif // BASE_FILES_DIR_READER_POSIX_H_
diff --git a/base/files/dir_reader_posix_unittest.cc b/base/files/dir_reader_posix_unittest.cc
new file mode 100644
index 0000000..0685031
--- /dev/null
+++ b/base/files/dir_reader_posix_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/dir_reader_posix.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#endif
+
+namespace base {
+
+TEST(DirReaderPosixUnittest, Read) {
+  static const unsigned kNumFiles = 100;
+
+  if (DirReaderPosix::IsFallback())
+    return;
+
+  char kDirTemplate[] = "/tmp/org.chromium.dir-reader-posix-XXXXXX";
+  const char* dir = mkdtemp(kDirTemplate);
+  ASSERT_TRUE(dir);
+
+  const int prev_wd = open(".", O_RDONLY | O_DIRECTORY);
+  DCHECK_GE(prev_wd, 0);
+
+  PCHECK(chdir(dir) == 0);
+
+  for (unsigned i = 0; i < kNumFiles; i++) {
+    char buf[16];
+    snprintf(buf, sizeof(buf), "%d", i);
+    const int fd = open(buf, O_CREAT | O_RDONLY | O_EXCL, 0600);
+    PCHECK(fd >= 0);
+    PCHECK(close(fd) == 0);
+  }
+
+  std::set<unsigned> seen;
+
+  DirReaderPosix reader(dir);
+  EXPECT_TRUE(reader.IsValid());
+
+  if (!reader.IsValid())
+    return;
+
+  bool seen_dot = false, seen_dotdot = false;
+
+  for (; reader.Next(); ) {
+    if (strcmp(reader.name(), ".") == 0) {
+      seen_dot = true;
+      continue;
+    }
+    if (strcmp(reader.name(), "..") == 0) {
+      seen_dotdot = true;
+      continue;
+    }
+
+    SCOPED_TRACE(testing::Message() << "reader.name(): " << reader.name());
+
+    char *endptr;
+    const unsigned long value = strtoul(reader.name(), &endptr, 10);
+
+    EXPECT_FALSE(*endptr);
+    EXPECT_LT(value, kNumFiles);
+    EXPECT_EQ(0u, seen.count(value));
+    seen.insert(value);
+  }
+
+  for (unsigned i = 0; i < kNumFiles; i++) {
+    char buf[16];
+    snprintf(buf, sizeof(buf), "%d", i);
+    PCHECK(unlink(buf) == 0);
+  }
+
+  PCHECK(rmdir(dir) == 0);
+
+  PCHECK(fchdir(prev_wd) == 0);
+  PCHECK(close(prev_wd) == 0);
+
+  EXPECT_TRUE(seen_dot);
+  EXPECT_TRUE(seen_dotdot);
+  EXPECT_EQ(kNumFiles, seen.size());
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher.cc b/base/files/file_path_watcher.cc
new file mode 100644
index 0000000..dd2b37f
--- /dev/null
+++ b/base/files/file_path_watcher.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2011 The Chromium 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.h"
+
+namespace base {
+namespace files {
+
+namespace {
+
+// A delegate implementation for the callback interface.
+class FilePathWatcherDelegate : public base::files::FilePathWatcher::Delegate {
+ public:
+  explicit FilePathWatcherDelegate(const FilePathWatcher::Callback& callback)
+      : callback_(callback) {}
+
+  // FilePathWatcher::Delegate implementation.
+  virtual void OnFilePathChanged(const FilePath& path) OVERRIDE {
+    callback_.Run(path, false);
+  }
+
+  virtual void OnFilePathError(const FilePath& path) OVERRIDE {
+    callback_.Run(path, true);
+  }
+
+ private:
+  virtual ~FilePathWatcherDelegate() {}
+
+  FilePathWatcher::Callback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherDelegate);
+};
+
+}  // namespace
+
+FilePathWatcher::~FilePathWatcher() {
+  impl_->Cancel();
+}
+
+// static
+void FilePathWatcher::CancelWatch(
+    const scoped_refptr<PlatformDelegate>& delegate) {
+  delegate->CancelOnMessageLoopThread();
+}
+
+bool FilePathWatcher::Watch(const FilePath& path, Delegate* delegate) {
+  DCHECK(path.IsAbsolute());
+  return impl_->Watch(path, delegate);
+}
+
+FilePathWatcher::PlatformDelegate::PlatformDelegate(): cancelled_(false) {
+}
+
+FilePathWatcher::PlatformDelegate::~PlatformDelegate() {
+  DCHECK(is_cancelled());
+}
+
+bool FilePathWatcher::Watch(const FilePath& path, const Callback& callback) {
+  return Watch(path, new FilePathWatcherDelegate(callback));
+}
+
+}  // namespace files
+}  // namespace base
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h
new file mode 100644
index 0000000..367be94
--- /dev/null
+++ b/base/files/file_path_watcher.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This module provides a way to monitor a file or directory for changes.
+
+#ifndef BASE_FILES_FILE_PATH_WATCHER_H_
+#define BASE_FILES_FILE_PATH_WATCHER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop_proxy.h"
+
+namespace base {
+namespace files {
+
+// This class lets you register interest in changes on a FilePath.
+// The delegate 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;
+
+  // Declares the callback client code implements to receive notifications. Note
+  // that implementations of this interface should not keep a reference to the
+  // corresponding FileWatcher object to prevent a reference cycle.
+  //
+  // Deprecated: see comment on Watch() below.
+  class Delegate : public base::RefCountedThreadSafe<Delegate> {
+   public:
+    virtual void OnFilePathChanged(const FilePath& path) = 0;
+    // Called when platform specific code detected an error. The watcher will
+    // not call OnFilePathChanged for future changes.
+    virtual void OnFilePathError(const FilePath& path) {}
+
+   protected:
+    friend class base::RefCountedThreadSafe<Delegate>;
+    virtual ~Delegate() {}
+  };
+
+  // Used internally to encapsulate different members on different platforms.
+  // TODO(jhawkins): Move this into its own file. Also fix the confusing naming
+  // wrt Delegate vs PlatformDelegate.
+  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,
+                       Delegate* delegate) 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::MessageLoopProxy> message_loop() const {
+      return message_loop_;
+    }
+
+    void set_message_loop(base::MessageLoopProxy* loop) {
+      message_loop_ = loop;
+    }
+
+    // Must be called before the PlatformDelegate is deleted.
+    void set_cancelled() {
+      cancelled_ = true;
+    }
+
+    bool is_cancelled() const {
+      return cancelled_;
+    }
+
+   private:
+    scoped_refptr<base::MessageLoopProxy> message_loop_;
+    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);
+
+  // Register interest in any changes on |path|. OnPathChanged will be called
+  // back for each change. Returns true on success.
+  // OnFilePathChanged() will be called on the same thread as Watch() is called,
+  // which should have a MessageLoop of TYPE_IO.
+  //
+  // Deprecated: new code should use the callback interface, declared below.
+  // The FilePathWatcher::Delegate interface will be removed once all client
+  // code has been updated. http://crbug.com/130980
+  virtual bool Watch(const FilePath& path, Delegate* delegate)
+      WARN_UNUSED_RESULT;
+
+  // Invokes |callback| whenever updates to |path| are detected. This should be
+  // called at most once, and from a MessageLoop of TYPE_IO. The callback will
+  // be invoked on the same loop. Returns true on success.
+  bool Watch(const FilePath& path, const Callback& callback);
+
+ private:
+  scoped_refptr<PlatformDelegate> impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcher);
+};
+
+}  // namespace files
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PATH_WATCHER_H_
diff --git a/base/files/file_path_watcher_browsertest.cc b/base/files/file_path_watcher_browsertest.cc
new file mode 100644
index 0000000..94439b1
--- /dev/null
+++ b/base/files/file_path_watcher_browsertest.cc
@@ -0,0 +1,844 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <set>
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <aclapi.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#endif
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/path_service.h"
+#include "base/scoped_temp_dir.h"
+#include "base/stl_util.h"
+#include "base/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 "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace files {
+
+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()
+      : loop_(base::MessageLoopProxy::current()) {}
+
+  // Called from the file thread by the delegates.
+  void OnChange(TestDelegate* delegate) {
+    loop_->PostTask(FROM_HERE,
+                    base::Bind(&NotificationCollector::RecordChange, this,
+                               make_scoped_refptr(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) {
+    ASSERT_TRUE(loop_->BelongsToCurrentThread());
+    ASSERT_TRUE(delegates_.count(delegate));
+    signaled_.insert(delegate);
+
+    // Check whether all delegates have been signaled.
+    if (signaled_ == delegates_)
+      loop_->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+  }
+
+  // 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::MessageLoopProxy> loop_;
+};
+
+// A mock FilePathWatcher::Delegate for testing. I'd rather use gmock, but it's
+// not thread safe for setting expectations, so the test code couldn't safely
+// reset expectations while the file watcher is running. In order to allow this,
+// we keep simple thread safe status flags in TestDelegate.
+class TestDelegate : public FilePathWatcher::Delegate {
+ public:
+  // The message loop specified by |loop| will be quit if a notification is
+  // received while the delegate is |armed_|. Note that the testing code must
+  // guarantee |loop| outlives the file thread on which OnFilePathChanged runs.
+  explicit TestDelegate(NotificationCollector* collector)
+      : collector_(collector) {
+    collector_->Register(this);
+  }
+
+  virtual void OnFilePathChanged(const FilePath&) {
+    collector_->OnChange(this);
+  }
+
+  virtual void OnFilePathError(const FilePath& path) {
+    ADD_FAILURE() << "Error " << path.value();
+  }
+
+ protected:
+  virtual ~TestDelegate() {}
+
+ private:
+  scoped_refptr<NotificationCollector> collector_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+void SetupWatchDelegate(const FilePath& target,
+                        FilePathWatcher* watcher,
+                        FilePathWatcher::Delegate* delegate,
+                        bool* result,
+                        base::WaitableEvent* completion) {
+  *result = watcher->Watch(target, delegate);
+  completion->Signal();
+}
+
+void SetupWatchCallback(const FilePath& target,
+                        FilePathWatcher* watcher,
+                        const FilePathWatcher::Callback& callback) {
+  ASSERT_TRUE(watcher->Watch(target, callback));
+}
+
+void QuitLoopWatchCallback(MessageLoop* loop,
+                           const FilePath& expected_path,
+                           bool expected_error,
+                           bool* flag,
+                           const FilePath& path,
+                           bool error) {
+  ASSERT_TRUE(flag);
+  *flag = true;
+  EXPECT_EQ(expected_path, path);
+  EXPECT_EQ(expected_error, error);
+  loop->PostTask(FROM_HERE, loop->QuitClosure());
+}
+
+class FilePathWatcherTest : public testing::Test {
+ public:
+  FilePathWatcherTest()
+      : file_thread_("FilePathWatcherTest") {}
+
+  virtual ~FilePathWatcherTest() {}
+
+ protected:
+  virtual 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));
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    collector_ = new NotificationCollector();
+  }
+
+  virtual void TearDown() OVERRIDE {
+    loop_.RunUntilIdle();
+  }
+
+  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 = file_util::WriteFile(file, content.c_str(),
+                                          content.length());
+    return write_size == static_cast<int>(content.length());
+  }
+
+  bool SetupWatch(const FilePath& target,
+                  FilePathWatcher* watcher,
+                  FilePathWatcher::Delegate* delegate) WARN_UNUSED_RESULT {
+    base::WaitableEvent completion(false, false);
+    bool result;
+    file_thread_.message_loop_proxy()->PostTask(
+        FROM_HERE,
+        base::Bind(SetupWatchDelegate, target, watcher,
+                   make_scoped_refptr(delegate), &result, &completion));
+    completion.Wait();
+    return result;
+  }
+
+  bool WaitForEvents() WARN_UNUSED_RESULT {
+    collector_->Reset();
+    loop_.Run();
+    return collector_->Success();
+  }
+
+  NotificationCollector* collector() { return collector_.get(); }
+
+  MessageLoop loop_;
+  base::Thread file_thread_;
+  ScopedTempDir temp_dir_;
+  scoped_refptr<NotificationCollector> collector_;
+};
+
+// Basic test: Create the file and verify that we notice.
+TEST_F(FilePathWatcherTest, NewFile) {
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// Verify that modifying the file is caught.
+TEST_F(FilePathWatcherTest, ModifiedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(WriteFile(test_file(), "new content"));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// Verify that moving the file into place is caught.
+TEST_F(FilePathWatcherTest, MovedFile) {
+  FilePath source_file(temp_dir_.path().AppendASCII("source"));
+  ASSERT_TRUE(WriteFile(source_file, "content"));
+
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(file_util::Move(source_file, test_file()));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+TEST_F(FilePathWatcherTest, DeletedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
+
+  // Now make sure we get notified if the file is deleted.
+  file_util::Delete(test_file(), false);
+  ASSERT_TRUE(WaitForEvents());
+}
+
+TEST_F(FilePathWatcherTest, Callback) {
+  FilePathWatcher* watcher = new FilePathWatcher();
+  bool called_back = false;
+
+  MessageLoop* file_loop = file_thread_.message_loop();
+  ASSERT_TRUE(file_loop);
+  // The callback makes |loop_| quit on file events, and flips |called_back|
+  // to true.
+  FilePathWatcher::Callback callback = base::Bind(
+      QuitLoopWatchCallback, &loop_, test_file(), false, &called_back);
+
+  // Start watching on the file thread, and unblock the loop once the callback
+  // has been installed.
+  file_thread_.message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(SetupWatchCallback, test_file(), watcher, callback),
+      base::Bind(&MessageLoop::Quit, base::Unretained(&loop_)));
+  loop_.Run();
+
+  // The watch has been installed. Trigger a file event now, which will unblock
+  // the loop again.
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  loop_.Run();
+  EXPECT_TRUE(called_back);
+
+  // Multiple events might have triggered, meaning that multiple
+  // QuitLoopWatchCallback have been posted. The FilePathWatcher can only cancel
+  // on the FILE thread, and thus that callback might still trigger after this
+  // function returns. Make sure the |watcher| is deleted before returning and
+  // destroying |called_back|.
+  // A better fix requires significant changes to the FilePathWatcher.
+  // TODO(joaodasilva): fix the FPW interface. http://crbug.com/145653
+  file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher);
+  file_thread_.message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(base::DoNothing),
+      base::Bind(&MessageLoop::Quit, base::Unretained(&loop_)));
+  loop_.Run();
+}
+
+// Used by the DeleteDuringNotify test below.
+// Deletes the FilePathWatcher when it's notified.
+class Deleter : public FilePathWatcher::Delegate {
+ public:
+  Deleter(FilePathWatcher* watcher, MessageLoop* loop)
+      : watcher_(watcher),
+        loop_(loop) {
+  }
+
+  virtual void OnFilePathChanged(const FilePath& path) {
+    watcher_.reset();
+    loop_->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+  }
+
+  scoped_ptr<FilePathWatcher> watcher_;
+  MessageLoop* loop_;
+
+ private:
+  virtual ~Deleter() {}
+};
+
+// Verify that deleting a watcher during the callback doesn't crash.
+TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
+  FilePathWatcher* watcher = new FilePathWatcher;
+  // Takes ownership of watcher.
+  scoped_refptr<Deleter> deleter(new Deleter(watcher, &loop_));
+  ASSERT_TRUE(SetupWatch(test_file(), watcher, deleter.get()));
+
+  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_.get() == NULL);
+}
+
+// Verify that deleting the watcher works even if there is a pending
+// notification.
+// Flaky on MacOS. http://crbug.com/85930
+#if defined(OS_MACOSX)
+#define MAYBE_DestroyWithPendingNotification DISABLED_DestroyWithPendingNotification
+#else
+#define MAYBE_DestroyWithPendingNotification DestroyWithPendingNotification
+#endif
+TEST_F(FilePathWatcherTest, MAYBE_DestroyWithPendingNotification) {
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  FilePathWatcher* watcher = new FilePathWatcher;
+  ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get()));
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher);
+}
+
+TEST_F(FilePathWatcherTest, MultipleWatchersSingleFile) {
+  FilePathWatcher watcher1, watcher2;
+  scoped_refptr<TestDelegate> delegate1(new TestDelegate(collector()));
+  scoped_refptr<TestDelegate> delegate2(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get()));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// Verify that watching a file whose parent directory doesn't exist yet works if
+// the directory and file are created eventually.
+TEST_F(FilePathWatcherTest, NonExistentDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file(dir.AppendASCII("file"));
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get()));
+
+  ASSERT_TRUE(file_util::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(file_util::Delete(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// Exercises watch reconfiguration for the case that directories on the path
+// are rapidly created.
+TEST_F(FilePathWatcherTest, DirectoryChain) {
+  FilePath path(temp_dir_.path());
+  std::vector<std::string> dir_names;
+  for (int i = 0; i < 20; i++) {
+    std::string dir(base::StringPrintf("d%d", i));
+    dir_names.push_back(dir);
+    path = path.AppendASCII(dir);
+  }
+
+  FilePathWatcher watcher;
+  FilePath file(path.AppendASCII("file"));
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get()));
+
+  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(file_util::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());
+}
+
+#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(file_util::CreateDirectory(dir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get()));
+
+  ASSERT_TRUE(file_util::Delete(dir, true));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// Tests that a file that is deleted and reappears is tracked correctly.
+TEST_F(FilePathWatcherTest, DeleteAndRecreate) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
+
+  ASSERT_TRUE(file_util::Delete(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());
+}
+
+TEST_F(FilePathWatcherTest, WatchDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file1(dir.AppendASCII("file1"));
+  FilePath file2(dir.AppendASCII("file2"));
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get()));
+
+  ASSERT_TRUE(file_util::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(file_util::Delete(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());
+}
+
+TEST_F(FilePathWatcherTest, MoveParent) {
+  FilePathWatcher file_watcher;
+  FilePathWatcher subdir_watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath dest(temp_dir_.path().AppendASCII("dest"));
+  FilePath subdir(dir.AppendASCII("subdir"));
+  FilePath file(subdir.AppendASCII("file"));
+  scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &file_watcher, file_delegate.get()));
+  scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(subdir, &subdir_watcher, subdir_delegate.get()));
+
+  // Setup a directory hierarchy.
+  ASSERT_TRUE(file_util::CreateDirectory(subdir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  // Move the parent directory.
+  file_util::Move(dir, dest);
+  VLOG(1) << "Waiting for directory move";
+  ASSERT_TRUE(WaitForEvents());
+}
+
+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(file_util::CreateDirectory(source_subdir));
+  ASSERT_TRUE(WriteFile(source_file, "content"));
+
+  scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get()));
+  scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get()));
+
+  // Move the directory into place, s.t. the watched file appears.
+  ASSERT_TRUE(file_util::Move(source_dir, dest_dir));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+#if !defined(OS_LINUX)
+// Linux implementation of FilePathWatcher doesn't catch attribute changes.
+// http://crbug.com/78043
+
+// Verify that changing attributes on a file is caught
+TEST_F(FilePathWatcherTest, FileAttributesChanged) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(file_util::MakeFileUnreadable(test_file()));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+#endif  // !OS_LINUX
+
+#if defined(OS_LINUX)
+
+// Verify that creating a symlink is caught.
+TEST_F(FilePathWatcherTest, CreateLink) {
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get()));
+
+  // Now make sure we get notified if the link is created.
+  // Note that test_file() doesn't have to exist.
+  ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// 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(file_util::CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get()));
+
+  // Now make sure we get notified if the link is deleted.
+  ASSERT_TRUE(file_util::Delete(test_link(), false));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// 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(file_util::CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get()));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(WriteFile(test_file(), "new content"));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// 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(file_util::CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get()));
+
+  // Now make sure we get notified if the target file is created.
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// 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(file_util::CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get()));
+
+  // Now make sure we get notified if the target file is deleted.
+  ASSERT_TRUE(file_util::Delete(test_file(), false));
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// Verify that watching a file whose parent directory is a link that
+// doesn't exist yet works if the symlink is created eventually.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart1) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // dir/file should exist.
+  ASSERT_TRUE(file_util::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()));
+
+  ASSERT_TRUE(file_util::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(file_util::Delete(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// Verify that watching a file whose parent directory is a
+// dangling symlink works if the directory is created eventually.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart2) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_refptr<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(file_util::CreateSymbolicLink(dir, link_dir));
+  // Note that we are watching dir.lnk/file.
+  ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get()));
+
+  ASSERT_TRUE(file_util::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(file_util::Delete(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+}
+
+// Verify that watching a file with a symlink on the path
+// to the file works.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart3) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(file_util::CreateDirectory(dir));
+  ASSERT_TRUE(file_util::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()));
+
+  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(file_util::Delete(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+}
+
+#endif  // OS_LINUX
+
+enum Permission {
+  Read,
+  Write,
+  Execute
+};
+
+bool ChangeFilePermissions(const FilePath& path, Permission perm, bool allow) {
+#if defined(OS_POSIX)
+  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;
+
+#elif defined(OS_WIN)
+  PACL old_dacl;
+  PSECURITY_DESCRIPTOR security_descriptor;
+  if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                           SE_FILE_OBJECT,
+                           DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl,
+                           NULL, &security_descriptor) != ERROR_SUCCESS)
+    return false;
+
+  DWORD mode = 0;
+  switch (perm) {
+    case Read:
+      mode = GENERIC_READ;
+      break;
+    case Write:
+      mode = GENERIC_WRITE;
+      break;
+    case Execute:
+      mode = GENERIC_EXECUTE;
+      break;
+    default:
+      ADD_FAILURE() << "unknown perm " << perm;
+      return false;
+  }
+
+  // Deny Read access for the current user.
+  EXPLICIT_ACCESS change;
+  change.grfAccessPermissions = mode;
+  change.grfAccessMode = allow ? GRANT_ACCESS : DENY_ACCESS;
+  change.grfInheritance = 0;
+  change.Trustee.pMultipleTrustee = NULL;
+  change.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+  change.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
+  change.Trustee.TrusteeType = TRUSTEE_IS_USER;
+  change.Trustee.ptstrName = L"CURRENT_USER";
+
+  PACL new_dacl;
+  if (SetEntriesInAcl(1, &change, old_dacl, &new_dacl) != ERROR_SUCCESS) {
+    LocalFree(security_descriptor);
+    return false;
+  }
+
+  DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                                  SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
+                                  NULL, NULL, new_dacl, NULL);
+  LocalFree(security_descriptor);
+  LocalFree(new_dacl);
+
+  return rc == ERROR_SUCCESS;
+#else
+  NOTIMPLEMENTED();
+  return false;
+#endif
+}
+
+#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(file_util::CreateDirectory(test_dir1));
+  ASSERT_TRUE(file_util::CreateDirectory(test_dir2));
+  ASSERT_TRUE(WriteFile(test_file, "content"));
+
+  FilePathWatcher watcher;
+  scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file, &watcher, delegate.get()));
+
+  // We should not get notified in this case as it hasn't affected our ability
+  // to access the file.
+  ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, false));
+  loop_.PostDelayedTask(FROM_HERE,
+                        MessageLoop::QuitClosure(),
+                        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));
+}
+
+#endif  // OS_MACOSX
+}  // namespace
+
+}  // namespace files
+}  // namespace base
diff --git a/base/files/file_path_watcher_kqueue.cc b/base/files/file_path_watcher_kqueue.cc
new file mode 100644
index 0000000..6221a62
--- /dev/null
+++ b/base/files/file_path_watcher_kqueue.cc
@@ -0,0 +1,504 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <fcntl.h>
+#include <sys/event.h>
+#include <sys/param.h>
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/stringprintf.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 {
+namespace files {
+
+namespace {
+
+// Mac-specific file watcher implementation based on kqueue.
+// Originally it was based on FSEvents so that the semantics were equivalent
+// on Linux, OSX and Windows where it was 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 FSEvents version did all of the above except handling attribute changes
+// to path components. Unfortunately FSEvents appears to have an issue where the
+// current implementation (Mac OS X 10.6.7) sometimes drops events and doesn't
+// send notifications. See
+// http://code.google.com/p/chromium/issues/detail?id=54822#c31 for source that
+// will reproduce the problem. FSEvents also required having a CFRunLoop
+// backing the thread that it was running on, that caused added complexity
+// in the interfaces.
+// 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 FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
+                            public MessageLoopForIO::Watcher,
+                            public MessageLoop::DestructionObserver {
+ public:
+  FilePathWatcherImpl() : kqueue_(-1) {}
+
+  // MessageLoopForIO::Watcher overrides.
+  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
+  virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
+
+  // MessageLoop::DestructionObserver overrides.
+  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
+
+  // FilePathWatcher::PlatformDelegate overrides.
+  virtual bool Watch(const FilePath& path,
+                     FilePathWatcher::Delegate* delegate) OVERRIDE;
+  virtual void Cancel() OVERRIDE;
+
+ protected:
+  virtual ~FilePathWatcherImpl() {}
+
+ 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_message_loop_|'s thread.
+  virtual 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 of 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 int FileDescriptorForPath(const FilePath& path);
+
+  // Closes |*fd| and sets |*fd| to -1.
+  static void CloseFileDescriptor(int* fd);
+
+  // Returns true if kevent has open file descriptor.
+  static bool IsKeventFileDescriptorOpen(const struct kevent& event) {
+    return event.ident != static_cast<uintptr_t>(-1);
+  }
+
+  static EventData* EventDataForKevent(const struct kevent& event) {
+    return reinterpret_cast<EventData*>(event.udata);
+  }
+
+  EventVector events_;
+  scoped_refptr<base::MessageLoopProxy> io_message_loop_;
+  MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_;
+  scoped_refptr<FilePathWatcher::Delegate> delegate_;
+  FilePath target_;
+  int kqueue_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
+};
+
+void FilePathWatcherImpl::ReleaseEvent(struct kevent& event) {
+  CloseFileDescriptor(reinterpret_cast<int*>(&event.ident));
+  EventData* entry = EventDataForKevent(event);
+  delete entry;
+  event.udata = NULL;
+}
+
+int FilePathWatcherImpl::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);
+    }
+    int fd = -1;
+    if (path_still_exists) {
+      fd = FileDescriptorForPath(built_path);
+      if (fd == -1) {
+        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;
+}
+
+int FilePathWatcherImpl::FileDescriptorForPath(const FilePath& path) {
+  return HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY));
+}
+
+void FilePathWatcherImpl::CloseFileDescriptor(int *fd) {
+  if (*fd == -1) {
+    return;
+  }
+
+  if (HANDLE_EINTR(close(*fd)) != 0) {
+    DPLOG(ERROR) << "close";
+  }
+  *fd = -1;
+}
+
+bool FilePathWatcherImpl::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 %d", *reinterpret_cast<int*>(&kevents[i].ident));
+      }
+      DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name;
+      valid = false;
+    }
+  }
+  return valid;
+}
+
+void FilePathWatcherImpl::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.
+  int have_access = FileDescriptorForPath(next_event_data->path_);
+  if (have_access == -1) {
+    *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(reinterpret_cast<int*>(&local_event->ident));
+    }
+  } else {
+    CloseFileDescriptor(&have_access);
+  }
+}
+
+void FilePathWatcherImpl::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(reinterpret_cast<int*>(&local_event->ident));
+  }
+}
+
+void FilePathWatcherImpl::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;
+  EventData* next_event_data = EventDataForKevent(*next_event);
+
+  // Check to see if it already has a valid file descriptor.
+  if (!IsKeventFileDescriptorOpen(*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 FilePathWatcherImpl::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 FilePathWatcherImpl::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)) {
+    delegate_->OnFilePathError(target_);
+    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 (!IsKeventFileDescriptorOpen(*event) || event == events_.end()) {
+      // 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)) {
+      delegate_->OnFilePathError(target_);
+      Cancel();
+    }
+  }
+
+  if (send_notification) {
+    delegate_->OnFilePathChanged(target_);
+  }
+}
+
+void FilePathWatcherImpl::OnFileCanWriteWithoutBlocking(int fd) {
+  NOTREACHED();
+}
+
+void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
+  CancelOnMessageLoopThread();
+}
+
+bool FilePathWatcherImpl::Watch(const FilePath& path,
+                                FilePathWatcher::Delegate* delegate) {
+  DCHECK(MessageLoopForIO::current());
+  DCHECK(target_.value().empty());  // Can only watch one path.
+  DCHECK(delegate);
+  DCHECK_EQ(kqueue_, -1);
+
+  delegate_ = delegate;
+  target_ = path;
+
+  MessageLoop::current()->AddDestructionObserver(this);
+  io_message_loop_ = base::MessageLoopProxy::current();
+
+  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 FilePathWatcherImpl::Cancel() {
+  base::MessageLoopProxy* proxy = io_message_loop_.get();
+  if (!proxy) {
+    set_cancelled();
+    return;
+  }
+  if (!proxy->BelongsToCurrentThread()) {
+    proxy->PostTask(FROM_HERE,
+                    base::Bind(&FilePathWatcherImpl::Cancel, this));
+    return;
+  }
+  CancelOnMessageLoopThread();
+}
+
+void FilePathWatcherImpl::CancelOnMessageLoopThread() {
+  DCHECK(MessageLoopForIO::current());
+  if (!is_cancelled()) {
+    set_cancelled();
+    kqueue_watcher_.StopWatchingFileDescriptor();
+    CloseFileDescriptor(&kqueue_);
+    std::for_each(events_.begin(), events_.end(), ReleaseEvent);
+    events_.clear();
+    io_message_loop_ = NULL;
+    MessageLoop::current()->RemoveDestructionObserver(this);
+    delegate_ = NULL;
+  }
+}
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace files
+}  // namespace base
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
new file mode 100644
index 0000000..1438539
--- /dev/null
+++ b/base/files/file_path_watcher_linux.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/files/file_path_watcher.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
+
+namespace base {
+namespace files {
+
+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|. Returns true on success.
+  bool RemoveWatch(Watch watch, FilePathWatcherImpl* watcher);
+
+  // Callback for InotifyReaderTask.
+  void OnInotifyEvent(const inotify_event* event);
+
+ private:
+  friend struct ::base::DefaultLazyInstanceTraits<InotifyReader>;
+
+  typedef std::set<FilePathWatcherImpl*> WatcherSet;
+
+  InotifyReader();
+  ~InotifyReader();
+
+  // We keep track of which delegates want to be notified on which watches.
+  base::hash_map<Watch, WatcherSet> watchers_;
+
+  // Lock to protect watchers_.
+  base::Lock lock_;
+
+  // Separate thread on which we run blocking read for inotify events.
+  base::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|. The flag |created| is true if
+  // the object appears.
+  void OnFilePathChanged(InotifyReader::Watch fired_watch,
+                         const FilePath::StringType& child,
+                         bool created);
+
+  // Start watching |path| for changes and notify |delegate| on each change.
+  // Returns true if watch for |path| has been added successfully.
+  virtual bool Watch(const FilePath& path,
+                     FilePathWatcher::Delegate* delegate) OVERRIDE;
+
+  // Cancel the watch. This unregisters the instance with InotifyReader.
+  virtual void Cancel() OVERRIDE;
+
+  // Deletion of the FilePathWatcher will call Cancel() to dispose of this
+  // object in the right thread. This also observes destruction of the required
+  // cleanup thread, in case it quits before Cancel() is called.
+  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
+
+ protected:
+  virtual ~FilePathWatcherImpl() {}
+
+ private:
+  // Cleans up and stops observing the |message_loop_| thread.
+  virtual void CancelOnMessageLoopThread() OVERRIDE;
+
+  // Inotify watches are installed for all directory components of |target_|. A
+  // WatchEntry instance holds the watch descriptor for a component and the
+  // subdirectory for that identifies the next component. If a symbolic link
+  // is being watched, the target of the link is also kept.
+  struct WatchEntry {
+    WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir)
+        : watch_(watch),
+          subdir_(subdir) {}
+
+    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. Updates |watched_path_|. Returns true on success.
+  bool UpdateWatches() WARN_UNUSED_RESULT;
+
+  // Delegate to notify upon changes.
+  scoped_refptr<FilePathWatcher::Delegate> delegate_;
+
+  // The file or directory we're supposed to watch.
+  FilePath target_;
+
+  // 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_;
+
+  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);
+
+  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 base::LazyInstance<InotifyReader>::Leaky g_inotify_reader =
+    LAZY_INSTANCE_INITIALIZER;
+
+InotifyReader::InotifyReader()
+    : thread_("inotify_reader"),
+      inotify_fd_(inotify_init()),
+      valid_(false) {
+  shutdown_pipe_[0] = -1;
+  shutdown_pipe_[1] = -1;
+  if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
+    thread_.message_loop()->PostTask(
+        FROM_HERE, base::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;
+
+  base::AutoLock auto_lock(lock_);
+
+  Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(),
+                                  IN_CREATE | IN_DELETE |
+                                  IN_CLOSE_WRITE | IN_MOVE |
+                                  IN_ONLYDIR);
+
+  if (watch == kInvalidWatch)
+    return kInvalidWatch;
+
+  watchers_[watch].insert(watcher);
+
+  return watch;
+}
+
+bool InotifyReader::RemoveWatch(Watch watch,
+                                FilePathWatcherImpl* watcher) {
+  if (!valid_)
+    return false;
+
+  base::AutoLock auto_lock(lock_);
+
+  watchers_[watch].erase(watcher);
+
+  if (watchers_[watch].empty()) {
+    watchers_.erase(watch);
+    return (inotify_rm_watch(inotify_fd_, watch) == 0);
+  }
+
+  return true;
+}
+
+void InotifyReader::OnInotifyEvent(const inotify_event* event) {
+  if (event->mask & IN_IGNORED)
+    return;
+
+  FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL(""));
+  base::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));
+  }
+}
+
+FilePathWatcherImpl::FilePathWatcherImpl()
+    : delegate_(NULL) {
+}
+
+void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
+                                            const FilePath::StringType& child,
+                                            bool created) {
+  if (!message_loop()->BelongsToCurrentThread()) {
+    // Switch to message_loop_ to access watches_ safely.
+    message_loop()->PostTask(FROM_HERE,
+        base::Bind(&FilePathWatcherImpl::OnFilePathChanged,
+                   this,
+                   fired_watch,
+                   child,
+                   created));
+    return;
+  }
+
+  DCHECK(MessageLoopForIO::current());
+
+  // Find the entry in |watches_| that corresponds to |fired_watch|.
+  WatchVector::const_iterator watch_entry(watches_.begin());
+  for ( ; watch_entry != watches_.end(); ++watch_entry) {
+    if (fired_watch == watch_entry->watch_) {
+      // Check whether a path component of |target_| changed.
+      bool change_on_target_path = child.empty() ||
+          ((child == watch_entry->subdir_) && watch_entry->linkname_.empty()) ||
+          (child == watch_entry->linkname_);
+
+      // Check whether the change references |target_| or a direct child.
+      DCHECK(watch_entry->subdir_.empty() ||
+          (watch_entry + 1) != watches_.end());
+      bool target_changed =
+          (watch_entry->subdir_.empty() && (child == watch_entry->linkname_)) ||
+          (watch_entry->subdir_.empty() && watch_entry->linkname_.empty()) ||
+          (watch_entry->subdir_ == child && (watch_entry + 1)->subdir_.empty());
+
+      // 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 && !UpdateWatches()) {
+        delegate_->OnFilePathError(target_);
+        return;
+      }
+
+      // 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 && !created) ||
+          (change_on_target_path && file_util::PathExists(target_))) {
+        delegate_->OnFilePathChanged(target_);
+        return;
+      }
+    }
+  }
+}
+
+bool FilePathWatcherImpl::Watch(const FilePath& path,
+                                FilePathWatcher::Delegate* delegate) {
+  DCHECK(target_.empty());
+  DCHECK(MessageLoopForIO::current());
+
+  set_message_loop(base::MessageLoopProxy::current());
+  delegate_ = delegate;
+  target_ = path;
+  MessageLoop::current()->AddDestructionObserver(this);
+
+  std::vector<FilePath::StringType> comps;
+  target_.GetComponents(&comps);
+  DCHECK(!comps.empty());
+  std::vector<FilePath::StringType>::const_iterator comp = comps.begin();
+  for (++comp; comp != comps.end(); ++comp)
+    watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp));
+
+  watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch,
+                                FilePath::StringType()));
+  return UpdateWatches();
+}
+
+void FilePathWatcherImpl::Cancel() {
+  if (!delegate_) {
+    // 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 (!message_loop()->BelongsToCurrentThread()) {
+    message_loop()->PostTask(FROM_HERE,
+                             base::Bind(&FilePathWatcher::CancelWatch,
+                                        make_scoped_refptr(this)));
+  } else {
+    CancelOnMessageLoopThread();
+  }
+}
+
+void FilePathWatcherImpl::CancelOnMessageLoopThread() {
+  if (!is_cancelled())
+    set_cancelled();
+
+  if (delegate_) {
+    MessageLoop::current()->RemoveDestructionObserver(this);
+    delegate_ = NULL;
+  }
+
+  for (WatchVector::iterator watch_entry(watches_.begin());
+       watch_entry != watches_.end(); ++watch_entry) {
+    if (watch_entry->watch_ != InotifyReader::kInvalidWatch)
+      g_inotify_reader.Get().RemoveWatch(watch_entry->watch_, this);
+  }
+  watches_.clear();
+  target_.clear();
+}
+
+void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
+  CancelOnMessageLoopThread();
+}
+
+bool FilePathWatcherImpl::UpdateWatches() {
+  // Ensure this runs on the |message_loop_| exclusively in order to avoid
+  // concurrency issues.
+  DCHECK(message_loop()->BelongsToCurrentThread());
+
+  // Walk the list of watches and update them as we go.
+  FilePath path(FILE_PATH_LITERAL("/"));
+  bool path_valid = true;
+  for (WatchVector::iterator watch_entry(watches_.begin());
+       watch_entry != watches_.end(); ++watch_entry) {
+    InotifyReader::Watch old_watch = watch_entry->watch_;
+    if (path_valid) {
+      watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this);
+      if ((watch_entry->watch_ == InotifyReader::kInvalidWatch) &&
+          file_util::IsLink(path)) {
+        FilePath link;
+        if (file_util::ReadSymbolicLink(path, &link)) {
+          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.
+          watch_entry->watch_ =
+              g_inotify_reader.Get().AddWatch(link.DirName(), this);
+          if (watch_entry->watch_ != InotifyReader::kInvalidWatch) {
+            watch_entry->linkname_ = link.BaseName().value();
+          } else {
+            DPLOG(WARNING) << "Watch failed for "  << link.DirName().value();
+            // 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.
+          }
+        }
+      }
+      if (watch_entry->watch_ == InotifyReader::kInvalidWatch) {
+        path_valid = false;
+      }
+    } else {
+      watch_entry->watch_ = InotifyReader::kInvalidWatch;
+    }
+    if (old_watch != InotifyReader::kInvalidWatch &&
+        old_watch != watch_entry->watch_) {
+      g_inotify_reader.Get().RemoveWatch(old_watch, this);
+    }
+    path = path.Append(watch_entry->subdir_);
+  }
+
+  return true;
+}
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace files
+}  // namespace base
diff --git a/base/files/file_path_watcher_stub.cc b/base/files/file_path_watcher_stub.cc
new file mode 100644
index 0000000..d91c1a7
--- /dev/null
+++ b/base/files/file_path_watcher_stub.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file exists for Unix systems which don't have the inotify headers, and
+// thus cannot build file_watcher_inotify.cc
+
+#include "base/files/file_path_watcher.h"
+
+namespace base {
+namespace files {
+
+namespace {
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
+ public:
+  virtual bool Watch(const FilePath& path,
+                     FilePathWatcher::Delegate* delegate) OVERRIDE {
+    return false;
+  }
+
+  virtual void Cancel() OVERRIDE {}
+
+  virtual void CancelOnMessageLoopThread() OVERRIDE {}
+
+ protected:
+  virtual ~FilePathWatcherImpl() {}
+};
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace files
+}  // namespace base
diff --git a/base/files/file_path_watcher_win.cc b/base/files/file_path_watcher_win.cc
new file mode 100644
index 0000000..37b1e7b
--- /dev/null
+++ b/base/files/file_path_watcher_win.cc
@@ -0,0 +1,283 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path_watcher.h"
+
+#include "base/bind.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop_proxy.h"
+#include "base/time.h"
+#include "base/win/object_watcher.h"
+
+namespace base {
+namespace files {
+
+namespace {
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
+                            public base::win::ObjectWatcher::Delegate,
+                            public MessageLoop::DestructionObserver {
+ public:
+  FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {}
+
+  // FilePathWatcher::PlatformDelegate overrides.
+  virtual bool Watch(const FilePath& path,
+                     FilePathWatcher::Delegate* delegate) OVERRIDE;
+  virtual void Cancel() OVERRIDE;
+
+  // Deletion of the FilePathWatcher will call Cancel() to dispose of this
+  // object in the right thread. This also observes destruction of the required
+  // cleanup thread, in case it quits before Cancel() is called.
+  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
+
+  // Callback from MessageLoopForIO.
+  virtual void OnObjectSignaled(HANDLE object);
+
+ private:
+  virtual ~FilePathWatcherImpl() {}
+
+  // Setup a watch handle for directory |dir|. Returns true if no fatal error
+  // occurs. |handle| will receive the handle value if |dir| is watchable,
+  // otherwise INVALID_HANDLE_VALUE.
+  static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle)
+      WARN_UNUSED_RESULT;
+
+  // (Re-)Initialize the watch handle.
+  bool UpdateWatch() WARN_UNUSED_RESULT;
+
+  // Destroy the watch handle.
+  void DestroyWatch();
+
+  // Cleans up and stops observing the |message_loop_| thread.
+  void CancelOnMessageLoopThread() OVERRIDE;
+
+  // Delegate to notify upon changes.
+  scoped_refptr<FilePathWatcher::Delegate> delegate_;
+
+  // Path we're supposed to watch (passed to delegate).
+  FilePath target_;
+
+  // Handle for FindFirstChangeNotification.
+  HANDLE handle_;
+
+  // ObjectWatcher to watch handle_ for events.
+  base::win::ObjectWatcher watcher_;
+
+  // Keep track of the last modified time of the file.  We use nulltime
+  // to represent the file not existing.
+  base::Time last_modified_;
+
+  // The time at which we processed the first notification with the
+  // |last_modified_| time stamp.
+  base::Time first_notification_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
+};
+
+bool FilePathWatcherImpl::Watch(const FilePath& path,
+                                FilePathWatcher::Delegate* delegate) {
+  DCHECK(target_.value().empty());  // Can only watch one path.
+
+  set_message_loop(base::MessageLoopProxy::current());
+  delegate_ = delegate;
+  target_ = path;
+  MessageLoop::current()->AddDestructionObserver(this);
+
+  if (!UpdateWatch())
+    return false;
+
+  watcher_.StartWatching(handle_, this);
+
+  return true;
+}
+
+void FilePathWatcherImpl::Cancel() {
+  if (!delegate_) {
+    // Watch was never called, or the |message_loop_| has already quit.
+    set_cancelled();
+    return;
+  }
+
+  // Switch to the file thread if necessary so we can stop |watcher_|.
+  if (!message_loop()->BelongsToCurrentThread()) {
+    message_loop()->PostTask(FROM_HERE,
+                             base::Bind(&FilePathWatcher::CancelWatch,
+                                        make_scoped_refptr(this)));
+  } else {
+    CancelOnMessageLoopThread();
+  }
+}
+
+void FilePathWatcherImpl::CancelOnMessageLoopThread() {
+  set_cancelled();
+
+  if (handle_ != INVALID_HANDLE_VALUE)
+    DestroyWatch();
+
+  if (delegate_) {
+    MessageLoop::current()->RemoveDestructionObserver(this);
+    delegate_ = NULL;
+  }
+}
+
+void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
+  CancelOnMessageLoopThread();
+}
+
+void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) {
+  DCHECK(object == handle_);
+  // Make sure we stay alive through the body of this function.
+  scoped_refptr<FilePathWatcherImpl> keep_alive(this);
+
+  if (!UpdateWatch()) {
+    delegate_->OnFilePathError(target_);
+    return;
+  }
+
+  // Check whether the event applies to |target_| and notify the delegate.
+  base::PlatformFileInfo file_info;
+  bool file_exists = file_util::GetFileInfo(target_, &file_info);
+  if (file_exists && (last_modified_.is_null() ||
+      last_modified_ != file_info.last_modified)) {
+    last_modified_ = file_info.last_modified;
+    first_notification_ = base::Time::Now();
+    delegate_->OnFilePathChanged(target_);
+  } else if (file_exists && !first_notification_.is_null()) {
+    // The target's last modification time is equal to what's on record. This
+    // means that either an unrelated event occurred, or the target changed
+    // again (file modification times only have a resolution of 1s). Comparing
+    // file modification times against the wall clock is not reliable to find
+    // out whether the change is recent, since this code might just run too
+    // late. Moreover, there's no guarantee that file modification time and wall
+    // clock times come from the same source.
+    //
+    // Instead, the time at which the first notification carrying the current
+    // |last_notified_| time stamp is recorded. Later notifications that find
+    // the same file modification time only need to be forwarded until wall
+    // clock has advanced one second from the initial notification. After that
+    // interval, client code is guaranteed to having seen the current revision
+    // of the file.
+    if (base::Time::Now() - first_notification_ >
+        base::TimeDelta::FromSeconds(1)) {
+      // Stop further notifications for this |last_modification_| time stamp.
+      first_notification_ = base::Time();
+    }
+    delegate_->OnFilePathChanged(target_);
+  } else if (!file_exists && !last_modified_.is_null()) {
+    last_modified_ = base::Time();
+    delegate_->OnFilePathChanged(target_);
+  }
+
+  // The watch may have been cancelled by the callback.
+  if (handle_ != INVALID_HANDLE_VALUE)
+    watcher_.StartWatching(handle_, this);
+}
+
+// static
+bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
+                                           HANDLE* handle) {
+  *handle = FindFirstChangeNotification(
+      dir.value().c_str(),
+      false,  // Don't watch subtrees
+      FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
+      FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
+      FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
+  if (*handle != INVALID_HANDLE_VALUE) {
+    // Make sure the handle we got points to an existing directory. It seems
+    // that windows sometimes hands out watches to direectories that are
+    // about to go away, but doesn't sent notifications if that happens.
+    if (!file_util::DirectoryExists(dir)) {
+      FindCloseChangeNotification(*handle);
+      *handle = INVALID_HANDLE_VALUE;
+    }
+    return true;
+  }
+
+  // If FindFirstChangeNotification failed because the target directory
+  // doesn't exist, access is denied (happens if the file is already gone but
+  // there are still handles open), or the target is not a directory, try the
+  // immediate parent directory instead.
+  DWORD error_code = GetLastError();
+  if (error_code != ERROR_FILE_NOT_FOUND &&
+      error_code != ERROR_PATH_NOT_FOUND &&
+      error_code != ERROR_ACCESS_DENIED &&
+      error_code != ERROR_SHARING_VIOLATION &&
+      error_code != ERROR_DIRECTORY) {
+    using ::operator<<; // Pick the right operator<< below.
+    DPLOG(ERROR) << "FindFirstChangeNotification failed for "
+                 << dir.value();
+    return false;
+  }
+
+  return true;
+}
+
+bool FilePathWatcherImpl::UpdateWatch() {
+  if (handle_ != INVALID_HANDLE_VALUE)
+    DestroyWatch();
+
+  base::PlatformFileInfo file_info;
+  if (file_util::GetFileInfo(target_, &file_info)) {
+    last_modified_ = file_info.last_modified;
+    first_notification_ = base::Time::Now();
+  }
+
+  // Start at the target and walk up the directory chain until we succesfully
+  // create a watch handle in |handle_|. |child_dirs| keeps a stack of child
+  // directories stripped from target, in reverse order.
+  std::vector<FilePath> child_dirs;
+  FilePath watched_path(target_);
+  while (true) {
+    if (!SetupWatchHandle(watched_path, &handle_))
+      return false;
+
+    // Break if a valid handle is returned. Try the parent directory otherwise.
+    if (handle_ != INVALID_HANDLE_VALUE)
+      break;
+
+    // Abort if we hit the root directory.
+    child_dirs.push_back(watched_path.BaseName());
+    FilePath parent(watched_path.DirName());
+    if (parent == watched_path) {
+      DLOG(ERROR) << "Reached the root directory";
+      return false;
+    }
+    watched_path = parent;
+  }
+
+  // At this point, handle_ is valid. However, the bottom-up search that the
+  // above code performs races against directory creation. So try to walk back
+  // down and see whether any children appeared in the mean time.
+  while (!child_dirs.empty()) {
+    watched_path = watched_path.Append(child_dirs.back());
+    child_dirs.pop_back();
+    HANDLE temp_handle = INVALID_HANDLE_VALUE;
+    if (!SetupWatchHandle(watched_path, &temp_handle))
+      return false;
+    if (temp_handle == INVALID_HANDLE_VALUE)
+      break;
+    FindCloseChangeNotification(handle_);
+    handle_ = temp_handle;
+  }
+
+  return true;
+}
+
+void FilePathWatcherImpl::DestroyWatch() {
+  watcher_.StopWatching();
+  FindCloseChangeNotification(handle_);
+  handle_ = INVALID_HANDLE_VALUE;
+}
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace files
+}  // namespace base
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
new file mode 100644
index 0000000..536b0fb
--- /dev/null
+++ b/base/files/important_file_writer.cc
@@ -0,0 +1,160 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/important_file_writer.h"
+
+#include <stdio.h>
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/critical_closure.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/task_runner.h"
+#include "base/metrics/histogram.h"
+#include "base/string_number_conversions.h"
+#include "base/threading/thread.h"
+#include "base/time.h"
+
+namespace base {
+
+namespace {
+
+const int kDefaultCommitIntervalMs = 10000;
+
+enum TempFileFailure {
+  FAILED_CREATING,
+  FAILED_OPENING,
+  FAILED_CLOSING,
+  FAILED_WRITING,
+  FAILED_RENAMING,
+  TEMP_FILE_FAILURE_MAX
+};
+
+void LogFailure(const FilePath& path, TempFileFailure failure_code,
+                const std::string& message) {
+  UMA_HISTOGRAM_ENUMERATION("ImportantFile.TempFileFailures", failure_code,
+                            TEMP_FILE_FAILURE_MAX);
+  DPLOG(WARNING) << "temp file failure: " << path.value().c_str()
+                 << " : " << message;
+}
+
+void WriteToDiskTask(const FilePath& path, const std::string& data) {
+  // 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 (!file_util::CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) {
+    LogFailure(path, FAILED_CREATING, "could not create temporary file");
+    return;
+  }
+
+  int flags = PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE;
+  PlatformFile tmp_file =
+      CreatePlatformFile(tmp_file_path, flags, NULL, NULL);
+  if (tmp_file == kInvalidPlatformFileValue) {
+    LogFailure(path, FAILED_OPENING, "could not open temporary file");
+    return;
+  }
+
+  // If this happens in the wild something really bad is going on.
+  CHECK_LE(data.length(), static_cast<size_t>(kint32max));
+  int bytes_written = WritePlatformFile(
+      tmp_file, 0, data.data(), static_cast<int>(data.length()));
+  FlushPlatformFile(tmp_file);  // Ignore return value.
+
+  if (!ClosePlatformFile(tmp_file)) {
+    LogFailure(path, FAILED_CLOSING, "failed to close temporary file");
+    file_util::Delete(tmp_file_path, false);
+    return;
+  }
+
+  if (bytes_written < static_cast<int>(data.length())) {
+    LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" +
+               IntToString(bytes_written));
+    file_util::Delete(tmp_file_path, false);
+    return;
+  }
+
+  if (!file_util::ReplaceFile(tmp_file_path, path)) {
+    LogFailure(path, FAILED_RENAMING, "could not rename temporary file");
+    file_util::Delete(tmp_file_path, false);
+    return;
+  }
+}
+
+}  // namespace
+
+ImportantFileWriter::ImportantFileWriter(
+    const FilePath& path, base::SequencedTaskRunner* task_runner)
+        : path_(path),
+          task_runner_(task_runner),
+          serializer_(NULL),
+          commit_interval_(TimeDelta::FromMilliseconds(
+              kDefaultCommitIntervalMs)) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(task_runner_.get());
+}
+
+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(const std::string& data) {
+  DCHECK(CalledOnValidThread());
+  if (data.length() > static_cast<size_t>(kint32max)) {
+    NOTREACHED();
+    return;
+  }
+
+  if (HasPendingWrite())
+    timer_.Stop();
+
+  if (!task_runner_->PostTask(FROM_HERE,
+          MakeCriticalClosure(Bind(&WriteToDiskTask, path_, data)))) {
+    // 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();
+
+    WriteToDiskTask(path_, data);
+  }
+}
+
+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::string data;
+  if (serializer_->SerializeData(&data)) {
+    WriteNow(data);
+  } else {
+    DLOG(WARNING) << "failed to serialize data to be saved in "
+                  << path_.value().c_str();
+  }
+  serializer_ = NULL;
+}
+
+}  // namespace base
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
new file mode 100644
index 0000000..ae814d5
--- /dev/null
+++ b/base/files/important_file_writer.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_FILES_IMPORTANT_FILE_WRITER_H_
+#define BASE_FILES_IMPORTANT_FILE_WRITER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/time.h"
+#include "base/timer.h"
+
+namespace base {
+
+class SequencedTaskRunner;
+class Thread;
+
+// Helper to ensure that a file won't be corrupted by the write (for example on
+// application crash). Consider a naive way to save an important file F:
+//
+// 1. Open F for writing, truncating it.
+// 2. Write new data to F.
+//
+// It's good when it works, but it gets very bad if step 2. doesn't complete.
+// It can be caused by a crash, a computer hang, or a weird I/O error. And you
+// end up with a broken file.
+//
+// To be safe, we don't start with writing directly to F. Instead, we write to
+// to a temporary file. Only after that write is successful, we rename the
+// temporary file to target filename.
+//
+// If you want to know more about this approach and ext3/ext4 fsync issues, see
+// http://valhenson.livejournal.com/37921.html
+class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
+ public:
+  // Used by ScheduleSave to lazily provide the data to be saved. Allows us
+  // to also batch data serializations.
+  class BASE_EXPORT DataSerializer {
+   public:
+    // Should put serialized string in |data| and return true on successful
+    // serialization. Will be called on the same thread on which
+    // ImportantFileWriter has been created.
+    virtual bool SerializeData(std::string* data) = 0;
+
+   protected:
+    virtual ~DataSerializer() {}
+  };
+
+  // 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,
+                      base::SequencedTaskRunner* task_runner);
+
+  // You have to ensure that there are no pending writes at the moment
+  // of destruction.
+  ~ImportantFileWriter();
+
+  const FilePath& path() const { return path_; }
+
+  // Returns true if there is a scheduled write pending which has not yet
+  // been started.
+  bool HasPendingWrite() const;
+
+  // Save |data| to target filename. Does not block. If there is a pending write
+  // scheduled by ScheduleWrite, it is cancelled.
+  void WriteNow(const 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();
+
+  TimeDelta commit_interval() const {
+    return commit_interval_;
+  }
+
+  void set_commit_interval(const TimeDelta& interval) {
+    commit_interval_ = interval;
+  }
+
+ private:
+  // Path being written to.
+  const FilePath path_;
+
+  // TaskRunner for the thread on which file I/O can be done.
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  // Timer used to schedule commit after ScheduleWrite.
+  OneShotTimer<ImportantFileWriter> timer_;
+
+  // Serializer which will provide the data to be saved.
+  DataSerializer* serializer_;
+
+  // Time delta after which scheduled data will be written to disk.
+  TimeDelta commit_interval_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImportantFileWriter);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_IMPORTANT_FILE_WRITER_H_
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
new file mode 100644
index 0000000..a284d38
--- /dev/null
+++ b/base/files/important_file_writer_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/important_file_writer.h"
+
+#include "base/compiler_specific.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/scoped_temp_dir.h"
+#include "base/threading/thread.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+std::string GetFileContent(const FilePath& path) {
+  std::string content;
+  if (!file_util::ReadFileToString(path, &content)) {
+    NOTREACHED();
+  }
+  return content;
+}
+
+class DataSerializer : public ImportantFileWriter::DataSerializer {
+ public:
+  explicit DataSerializer(const std::string& data) : data_(data) {
+  }
+
+  virtual bool SerializeData(std::string* output) {
+    output->assign(data_);
+    return true;
+  }
+
+ private:
+  const std::string data_;
+};
+
+}  // namespace
+
+class ImportantFileWriterTest : public testing::Test {
+ public:
+  ImportantFileWriterTest() { }
+  virtual void SetUp() {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    file_ = temp_dir_.path().AppendASCII("test-file");
+  }
+
+ protected:
+  FilePath file_;
+  MessageLoop loop_;
+
+ private:
+  ScopedTempDir temp_dir_;
+};
+
+TEST_F(ImportantFileWriterTest, Basic) {
+  ImportantFileWriter writer(file_,
+                             MessageLoopProxy::current());
+  EXPECT_FALSE(file_util::PathExists(writer.path()));
+  writer.WriteNow("foo");
+  loop_.RunUntilIdle();
+
+  ASSERT_TRUE(file_util::PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, ScheduleWrite) {
+  ImportantFileWriter writer(file_,
+                             MessageLoopProxy::current());
+  writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
+  EXPECT_FALSE(writer.HasPendingWrite());
+  DataSerializer serializer("foo");
+  writer.ScheduleWrite(&serializer);
+  EXPECT_TRUE(writer.HasPendingWrite());
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      MessageLoop::QuitClosure(),
+      TimeDelta::FromMilliseconds(100));
+  MessageLoop::current()->Run();
+  EXPECT_FALSE(writer.HasPendingWrite());
+  ASSERT_TRUE(file_util::PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
+  ImportantFileWriter writer(file_,
+                             MessageLoopProxy::current());
+  EXPECT_FALSE(writer.HasPendingWrite());
+  DataSerializer serializer("foo");
+  writer.ScheduleWrite(&serializer);
+  EXPECT_TRUE(writer.HasPendingWrite());
+  writer.DoScheduledWrite();
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      MessageLoop::QuitClosure(),
+      TimeDelta::FromMilliseconds(100));
+  MessageLoop::current()->Run();
+  EXPECT_FALSE(writer.HasPendingWrite());
+  ASSERT_TRUE(file_util::PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, BatchingWrites) {
+  ImportantFileWriter writer(file_,
+                             MessageLoopProxy::current());
+  writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
+  DataSerializer foo("foo"), bar("bar"), baz("baz");
+  writer.ScheduleWrite(&foo);
+  writer.ScheduleWrite(&bar);
+  writer.ScheduleWrite(&baz);
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      MessageLoop::QuitClosure(),
+      TimeDelta::FromMilliseconds(100));
+  MessageLoop::current()->Run();
+  ASSERT_TRUE(file_util::PathExists(writer.path()));
+  EXPECT_EQ("baz", GetFileContent(writer.path()));
+}
+
+}  // namespace base
diff --git a/base/float_util.h b/base/float_util.h
new file mode 100644
index 0000000..31a307d
--- /dev/null
+++ b/base/float_util.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_FLOAT_UTIL_H_
+#define BASE_FLOAT_UTIL_H_
+
+#include "build/build_config.h"
+
+#include <float.h>
+#include <math.h>
+
+namespace base {
+
+inline bool IsFinite(const double& number) {
+#if defined(OS_ANDROID)
+  // isfinite isn't available on Android: http://b.android.com/34793
+  return finite(number) != 0;
+#elif defined(OS_POSIX)
+  return isfinite(number) != 0;
+#elif defined(OS_WIN)
+  return _finite(number) != 0;
+#endif
+}
+
+}  // namespace base
+
+#endif  // BASE_FLOAT_UTIL_H_
diff --git a/base/format_macros.h b/base/format_macros.h
new file mode 100644
index 0000000..466d79b
--- /dev/null
+++ b/base/format_macros.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FORMAT_MACROS_H_
+#define BASE_FORMAT_MACROS_H_
+
+// This file defines the format macros for some integer types.
+
+// To print a 64-bit value in a portable way:
+//   int64_t value;
+//   printf("xyz:%" PRId64, value);
+// The "d" in the macro corresponds to %d; you can also use PRIu64 etc.
+//
+// For wide strings, prepend "Wide" to the macro:
+//   int64_t value;
+//   StringPrintf(L"xyz: %" WidePRId64, value);
+//
+// To print a size_t value in a portable way:
+//   size_t size;
+//   printf("xyz: %" PRIuS, size);
+// The "u" in the macro corresponds to %u, and S is for "size".
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+
+#if (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(__STDC_FORMAT_MACROS)
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include <inttypes.h>
+
+// 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
+
+#else  // OS_WIN
+
+#if !defined(PRId64)
+#define PRId64 "I64d"
+#endif
+
+#if !defined(PRIu64)
+#define PRIu64 "I64u"
+#endif
+
+#if !defined(PRIx64)
+#define PRIx64 "I64x"
+#endif
+
+#define WidePRId64 L"I64d"
+#define WidePRIu64 L"I64u"
+#define WidePRIx64 L"I64x"
+
+#if !defined(PRIuS)
+#define PRIuS "Iu"
+#endif
+
+#endif
+
+#endif  // BASE_FORMAT_MACROS_H_
diff --git a/base/gmock_unittest.cc b/base/gmock_unittest.cc
new file mode 100644
index 0000000..855380a
--- /dev/null
+++ b/base/gmock_unittest.cc
@@ -0,0 +1,137 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This test is a simple sanity check to make sure gmock is able to build/link
+// correctly.  It just instantiates a mock object and runs through a couple of
+// the basic mock features.
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Gmock matchers and actions that we use below.
+using testing::AnyOf;
+using testing::Eq;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::WithArg;
+using testing::_;
+
+namespace {
+
+// Simple class that we can mock out the behavior for.  Everything is virtual
+// for easy mocking.
+class SampleClass {
+ public:
+  SampleClass() {}
+  virtual ~SampleClass() {}
+
+  virtual int ReturnSomething() {
+    return -1;
+  }
+
+  virtual void ReturnNothingConstly() const {
+  }
+
+  virtual void OutputParam(int* a) {
+  }
+
+  virtual int ReturnSecond(int a, int b) {
+    return b;
+  }
+};
+
+// Declare a mock for the class.
+class MockSampleClass : public SampleClass {
+ public:
+  MOCK_METHOD0(ReturnSomething, int());
+  MOCK_CONST_METHOD0(ReturnNothingConstly, void());
+  MOCK_METHOD1(OutputParam, void(int* a));
+  MOCK_METHOD2(ReturnSecond, int(int a, int b));
+};
+
+// Create a couple of custom actions.  Custom actions can be used for adding
+// more complex behavior into your mock...though if you start needing these, ask
+// if you're asking your mock to do too much.
+ACTION(ReturnVal) {
+  // Return the first argument received.
+  return arg0;
+}
+ACTION(ReturnSecond) {
+  // Returns the second argument.  This basically implemetns ReturnSecond.
+  return arg1;
+}
+
+TEST(GmockTest, SimpleMatchAndActions) {
+  // Basic test of some simple gmock matchers, actions, and cardinality
+  // expectations.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, ReturnSomething())
+      .WillOnce(Return(1))
+      .WillOnce(Return(2))
+      .WillOnce(Return(3));
+  EXPECT_EQ(1, mock.ReturnSomething());
+  EXPECT_EQ(2, mock.ReturnSomething());
+  EXPECT_EQ(3, mock.ReturnSomething());
+
+  EXPECT_CALL(mock, ReturnNothingConstly()).Times(2);
+  mock.ReturnNothingConstly();
+  mock.ReturnNothingConstly();
+}
+
+TEST(GmockTest, AssignArgument) {
+  // Capture an argument for examination.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, OutputParam(_))
+      .WillRepeatedly(SetArgumentPointee<0>(5));
+
+  int arg = 0;
+  mock.OutputParam(&arg);
+  EXPECT_EQ(5, arg);
+}
+
+TEST(GmockTest, SideEffects) {
+  // Capture an argument for examination.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, OutputParam(_))
+      .WillRepeatedly(SetArgumentPointee<0>(5));
+
+  int arg = 0;
+  mock.OutputParam(&arg);
+  EXPECT_EQ(5, arg);
+}
+
+TEST(GmockTest, CustomAction_ReturnSecond) {
+  // Test a mock of the ReturnSecond behavior using an action that provides an
+  // alternate implementation of the function.  Danger here though, this is
+  // starting to add too much behavior of the mock, which means the mock
+  // implementation might start to have bugs itself.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5))))
+      .WillRepeatedly(ReturnSecond());
+  EXPECT_EQ(4, mock.ReturnSecond(-1, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(0, 5));
+  EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4));
+  EXPECT_EQ(4, mock.ReturnSecond(112358, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(1337, 5));
+}
+
+TEST(GmockTest, CustomAction_ReturnVal) {
+  // Alternate implemention of ReturnSecond using a more general custom action,
+  // and a WithArg adapter to bridge the interfaces.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5))))
+      .WillRepeatedly(WithArg<1>(ReturnVal()));
+  EXPECT_EQ(4, mock.ReturnSecond(-1, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(0, 5));
+  EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4));
+  EXPECT_EQ(4, mock.ReturnSecond(112358, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(1337, 5));
+}
+
+}  // namespace
diff --git a/base/gtest_prod_util.h b/base/gtest_prod_util.h
new file mode 100644
index 0000000..3289e63
--- /dev/null
+++ b/base/gtest_prod_util.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_GTEST_PROD_UTIL_H_
+#define BASE_GTEST_PROD_UTIL_H_
+
+#include "testing/gtest/include/gtest/gtest_prod.h"
+
+// This is a wrapper for gtest's FRIEND_TEST macro that friends
+// test with all possible prefixes. This is very helpful when changing the test
+// prefix, because the friend declarations don't need to be updated.
+//
+// Example usage:
+//
+// class MyClass {
+//  private:
+//   void MyMethod();
+//   FRIEND_TEST_ALL_PREFIXES(MyClassTest, MyMethod);
+// };
+#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \
+  FRIEND_TEST(test_case_name, test_name); \
+  FRIEND_TEST(test_case_name, DISABLED_##test_name); \
+  FRIEND_TEST(test_case_name, FLAKY_##test_name)
+
+// C++ compilers will refuse to compile the following code:
+//
+// namespace foo {
+// class MyClass {
+//  private:
+//   FRIEND_TEST_ALL_PREFIXES(MyClassTest, TestMethod);
+//   bool private_var;
+// };
+// }  // namespace foo
+//
+// class MyClassTest::TestMethod() {
+//   foo::MyClass foo_class;
+//   foo_class.private_var = true;
+// }
+//
+// Unless you forward declare MyClassTest::TestMethod outside of namespace foo.
+// Use FORWARD_DECLARE_TEST to do so for all possible prefixes.
+//
+// Example usage:
+//
+// FORWARD_DECLARE_TEST(MyClassTest, TestMethod);
+//
+// namespace foo {
+// class MyClass {
+//  private:
+//   FRIEND_TEST_ALL_PREFIXES(::MyClassTest, TestMethod);  // NOTE use of ::
+//   bool private_var;
+// };
+// }  // namespace foo
+//
+// class MyClassTest::TestMethod() {
+//   foo::MyClass foo_class;
+//   foo_class.private_var = true;
+// }
+
+#define FORWARD_DECLARE_TEST(test_case_name, test_name) \
+  class test_case_name##_##test_name##_Test; \
+  class test_case_name##_##DISABLED_##test_name##_Test; \
+  class test_case_name##_##FLAKY_##test_name##_Test
+
+#endif  // BASE_GTEST_PROD_UTIL_H_
diff --git a/base/guid.cc b/base/guid.cc
new file mode 100644
index 0000000..920dae5
--- /dev/null
+++ b/base/guid.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/guid.h"
+
+#include "base/rand_util.h"
+#include "base/stringprintf.h"
+
+namespace base {
+
+bool IsValidGUID(const std::string& guid) {
+  const size_t kGUIDLength = 36U;
+  if (guid.length() != kGUIDLength)
+    return false;
+
+  std::string hexchars = "0123456789ABCDEF";
+  for (uint32 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 (hexchars.find(current) == std::string::npos)
+        return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace guid
diff --git a/base/guid.h b/base/guid.h
new file mode 100644
index 0000000..468b65f
--- /dev/null
+++ b/base/guid.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_GUID_H_
+#define BASE_GUID_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Generate a 128-bit random GUID of the form: "%08X-%04X-%04X-%04X-%012llX".
+// If GUID generation fails an empty string is returned.
+// The POSIX implementation uses psuedo random number generation to create
+// the GUID.  The Windows implementation uses system services.
+BASE_EXPORT std::string GenerateGUID();
+
+// Returns true if the input string conforms to the GUID format.
+BASE_EXPORT bool IsValidGUID(const std::string& guid);
+
+#if defined(OS_POSIX)
+// For unit testing purposes only.  Do not use outside of tests.
+BASE_EXPORT std::string RandomDataToGUIDString(const uint64 bytes[2]);
+#endif
+
+}  // namespace guid
+
+#endif  // BASE_GUID_H_
diff --git a/base/guid_posix.cc b/base/guid_posix.cc
new file mode 100644
index 0000000..89811d0
--- /dev/null
+++ b/base/guid_posix.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/guid.h"
+
+#include "base/rand_util.h"
+#include "base/stringprintf.h"
+
+namespace base {
+
+std::string GenerateGUID() {
+  uint64 sixteen_bytes[2] = { base::RandUint64(), base::RandUint64() };
+  return RandomDataToGUIDString(sixteen_bytes);
+}
+
+// TODO(cmasone): Once we're comfortable this works, migrate Windows code to
+// use this as well.
+std::string RandomDataToGUIDString(const uint64 bytes[2]) {
+  return StringPrintf("%08X-%04X-%04X-%04X-%012llX",
+                      static_cast<unsigned int>(bytes[0] >> 32),
+                      static_cast<unsigned int>((bytes[0] >> 16) & 0x0000ffff),
+                      static_cast<unsigned int>(bytes[0] & 0x0000ffff),
+                      static_cast<unsigned int>(bytes[1] >> 48),
+                      bytes[1] & 0x0000ffffffffffffULL);
+}
+
+}  // namespace guid
diff --git a/base/guid_unittest.cc b/base/guid_unittest.cc
new file mode 100644
index 0000000..18c04a9
--- /dev/null
+++ b/base/guid_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/guid.h"
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_POSIX)
+TEST(GUIDTest, GUIDGeneratesAllZeroes) {
+  uint64 bytes[] = { 0, 0 };
+  std::string clientid = base::RandomDataToGUIDString(bytes);
+  EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid);
+}
+
+TEST(GUIDTest, GUIDGeneratesCorrectly) {
+  uint64 bytes[] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL };
+  std::string clientid = base::RandomDataToGUIDString(bytes);
+  EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid);
+}
+#endif
+
+TEST(GUIDTest, GUIDCorrectlyFormatted) {
+  const int kIterations = 10;
+  for (int it = 0; it < kIterations; ++it) {
+    std::string guid = base::GenerateGUID();
+    EXPECT_TRUE(base::IsValidGUID(guid));
+  }
+}
+
+TEST(GUIDTest, GUIDBasicUniqueness) {
+  const int kIterations = 10;
+  for (int it = 0; it < kIterations; ++it) {
+    std::string guid1 = base::GenerateGUID();
+    std::string guid2 = base::GenerateGUID();
+    EXPECT_EQ(36U, guid1.length());
+    EXPECT_EQ(36U, guid2.length());
+    EXPECT_NE(guid1, guid2);
+  }
+}
diff --git a/base/guid_win.cc b/base/guid_win.cc
new file mode 100644
index 0000000..1cddff8
--- /dev/null
+++ b/base/guid_win.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/guid.h"
+
+#include <stdlib.h>
+
+#include <objbase.h>
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+std::string GenerateGUID() {
+  const int kGUIDSize = 39;
+
+  GUID guid;
+  HRESULT guid_result = CoCreateGuid(&guid);
+  DCHECK(SUCCEEDED(guid_result));
+  if (!SUCCEEDED(guid_result))
+    return std::string();
+
+  std::wstring guid_string;
+  int result = StringFromGUID2(guid,
+                               WriteInto(&guid_string, kGUIDSize), kGUIDSize);
+  DCHECK(result == kGUIDSize);
+  if (result != kGUIDSize)
+    return std::string();
+
+  return WideToUTF8(guid_string.substr(1, guid_string.length() - 2));
+}
+
+}  // namespace guid
diff --git a/base/hash.cc b/base/hash.cc
new file mode 100644
index 0000000..2c87065
--- /dev/null
+++ b/base/hash.cc
@@ -0,0 +1,73 @@
+// From http://www.azillionmonkeys.com/qed/hash.html
+
+#include "base/hash.h"
+
+typedef uint32 uint32_t;
+typedef uint16 uint16_t;
+
+namespace base {
+
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+  || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+                       +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+uint32 SuperFastHash(const char * data, int len) {
+  uint32_t hash = len, tmp;
+  int rem;
+
+  if (len <= 0 || data == NULL)
+    return 0;
+
+  rem = len & 3;
+  len >>= 2;
+
+  /* Main loop */
+  for (; len > 0; len--) {
+    hash  += get16bits(data);
+    tmp    = (get16bits(data + 2) << 11) ^ hash;
+    hash   = (hash << 16) ^ tmp;
+    data  += 2 * sizeof(uint16_t);
+    hash  += hash >> 11;
+  }
+
+  /* Handle end cases */
+  switch (rem) {
+    case 3:
+      hash += get16bits(data);
+      hash ^= hash << 16;
+
+      // Treat the final character as signed. This ensures all platforms behave
+      // consistently with the original x86 code.
+      hash ^= static_cast<signed char>(data[sizeof(uint16_t)]) << 18;
+      hash += hash >> 11;
+      break;
+    case 2:
+      hash += get16bits(data);
+      hash ^= hash << 11;
+      hash += hash >> 17;
+      break;
+    case 1:
+      hash += static_cast<signed char>(*data);
+      hash ^= hash << 10;
+      hash += hash >> 1;
+  }
+
+  /* Force "avalanching" of final 127 bits */
+  hash ^= hash << 3;
+  hash += hash >> 5;
+  hash ^= hash << 4;
+  hash += hash >> 17;
+  hash ^= hash << 25;
+  hash += hash >> 6;
+
+  return hash;
+}
+
+}  // namespace base
diff --git a/base/hash.h b/base/hash.h
new file mode 100644
index 0000000..cf8ea3a
--- /dev/null
+++ b/base/hash.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_HASH_H_
+#define BASE_HASH_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+// From http://www.azillionmonkeys.com/qed/hash.html
+// This is the hash used on WebCore/platform/stringhash
+BASE_EXPORT uint32 SuperFastHash(const char * data, int len);
+
+inline uint32 Hash(const char* key, size_t length) {
+  return SuperFastHash(key, static_cast<int>(length));
+}
+
+inline uint32 Hash(const std::string& key) {
+  if (key.empty())
+    return 0;
+  return SuperFastHash(key.data(), static_cast<int>(key.size()));
+}
+
+}  // namespace base
+
+#endif  // BASE_HASH_H_
diff --git a/base/hash_tables.h b/base/hash_tables.h
new file mode 100644
index 0000000..14119ed
--- /dev/null
+++ b/base/hash_tables.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Deal with the differences between Microsoft and GNU implemenations
+// of hash_map. Allows all platforms to use |base::hash_map| and
+// |base::hash_set|.
+//  eg:
+//   base::hash_map<int> my_map;
+//   base::hash_set<int> my_set;
+//
+// NOTE: It is an explicit non-goal of this class to provide a generic hash
+// function for pointers.  If you want to hash a pointers to a particular class,
+// please define the template specialization elsewhere (for example, in its
+// header file) and keep it specific to just pointers to that class.  This is
+// because identity hashes are not desirable for all types that might show up
+// in containers as pointers.
+
+#ifndef BASE_HASH_TABLES_H_
+#define BASE_HASH_TABLES_H_
+
+#include "build/build_config.h"
+
+#include "base/string16.h"
+
+#if defined(COMPILER_MSVC)
+#include <hash_map>
+#include <hash_set>
+
+#define BASE_HASH_NAMESPACE stdext
+
+#elif defined(COMPILER_GCC)
+#if defined(OS_ANDROID)
+#define BASE_HASH_NAMESPACE std
+#else
+#define BASE_HASH_NAMESPACE __gnu_cxx
+#endif
+
+// This is a hack to disable the gcc 4.4 warning about hash_map and hash_set
+// being deprecated.  We can get rid of this when we upgrade to VS2008 and we
+// can use <tr1/unordered_map> and <tr1/unordered_set>.
+#ifdef __DEPRECATED
+#define CHROME_OLD__DEPRECATED __DEPRECATED
+#undef __DEPRECATED
+#endif
+
+#if defined(OS_ANDROID)
+#include <hash_map>
+#include <hash_set>
+#else
+#include <ext/hash_map>
+#include <ext/hash_set>
+#endif
+
+#include <string>
+
+#ifdef CHROME_OLD__DEPRECATED
+#define __DEPRECATED CHROME_OLD__DEPRECATED
+#undef CHROME_OLD__DEPRECATED
+#endif
+
+namespace BASE_HASH_NAMESPACE {
+
+#if !defined(OS_ANDROID)
+// The GNU C++ library provides identity hash functions for many integral types,
+// but not for |long long|.  This hash function will truncate if |size_t| is
+// narrower than |long long|.  This is probably good enough for what we will
+// use it for.
+
+#define DEFINE_TRIVIAL_HASH(integral_type) \
+    template<> \
+    struct hash<integral_type> { \
+      std::size_t operator()(integral_type value) const { \
+        return static_cast<std::size_t>(value); \
+      } \
+    }
+
+DEFINE_TRIVIAL_HASH(long long);
+DEFINE_TRIVIAL_HASH(unsigned long long);
+
+#undef DEFINE_TRIVIAL_HASH
+#endif  // !defined(OS_ANDROID)
+
+// Implement string hash functions so that strings of various flavors can
+// be used as keys in STL maps and sets.  The hash algorithm comes from the
+// GNU C++ library, in <tr1/functional>.  It is duplicated here because GCC
+// versions prior to 4.3.2 are unable to compile <tr1/functional> when RTTI
+// is disabled, as it is in our build.
+
+#define DEFINE_STRING_HASH(string_type) \
+    template<> \
+    struct hash<string_type> { \
+      std::size_t operator()(const string_type& s) const { \
+        std::size_t result = 0; \
+        for (string_type::const_iterator i = s.begin(); i != s.end(); ++i) \
+          result = (result * 131) + *i; \
+        return result; \
+      } \
+    }
+
+DEFINE_STRING_HASH(std::string);
+DEFINE_STRING_HASH(string16);
+
+#undef DEFINE_STRING_HASH
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#else  // COMPILER
+#error define BASE_HASH_NAMESPACE for your compiler
+#endif  // COMPILER
+
+namespace base {
+using BASE_HASH_NAMESPACE::hash_map;
+using BASE_HASH_NAMESPACE::hash_set;
+}
+
+#endif  // BASE_HASH_TABLES_H_
diff --git a/base/hi_res_timer_manager.h b/base/hi_res_timer_manager.h
new file mode 100644
index 0000000..1bd5538
--- /dev/null
+++ b/base/hi_res_timer_manager.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_HI_RES_TIMER_MANAGER_H_
+#define BASE_HI_RES_TIMER_MANAGER_H_
+
+#include "base/base_export.h"
+#include "base/system_monitor/system_monitor.h"
+
+// Ensures that the Windows high resolution timer is only used
+// when not running on battery power.
+class BASE_EXPORT HighResolutionTimerManager
+    : public base::SystemMonitor::PowerObserver {
+ public:
+  HighResolutionTimerManager();
+  virtual ~HighResolutionTimerManager();
+
+  // base::SystemMonitor::PowerObserver:
+  virtual 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);
+};
+
+#endif  // BASE_HI_RES_TIMER_MANAGER_H_
diff --git a/base/hi_res_timer_manager_posix.cc b/base/hi_res_timer_manager_posix.cc
new file mode 100644
index 0000000..7c16eb7
--- /dev/null
+++ b/base/hi_res_timer_manager_posix.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/hi_res_timer_manager.h"
+
+// On POSIX we don't need to do anything special with the system timer.
+
+HighResolutionTimerManager::HighResolutionTimerManager()
+    : hi_res_clock_available_(false) {
+}
+
+HighResolutionTimerManager::~HighResolutionTimerManager() {
+}
+
+void HighResolutionTimerManager::OnPowerStateChange(bool on_battery_power) {
+}
+
+void HighResolutionTimerManager::UseHiResClock(bool use) {
+}
diff --git a/base/hi_res_timer_manager_unittest.cc b/base/hi_res_timer_manager_unittest.cc
new file mode 100644
index 0000000..07651ce
--- /dev/null
+++ b/base/hi_res_timer_manager_unittest.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/hi_res_timer_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/system_monitor/system_monitor.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+// http://crbug.com/114048
+TEST(HiResTimerManagerTest, DISABLED_ToggleOnOff) {
+  MessageLoop loop;
+  scoped_ptr<base::SystemMonitor> system_monitor(new base::SystemMonitor());
+  HighResolutionTimerManager manager;
+
+  // At this point, we don't know if the high resolution timers are on or off,
+  // it depends on what system the tests are running on (for example, if this
+  // test is running on a laptop/battery, then the SystemMonitor would have
+  // already set the PowerState to battery power; but if we're running on a
+  // desktop, then the PowerState will be non-battery power).  Simulate a power
+  // level change to get to a deterministic state.
+  manager.OnPowerStateChange(/* on_battery */ false);
+
+  // Loop a few times to test power toggling.
+  for (int loop = 2; loop >= 0; --loop) {
+    // 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(/* on_battery */ true);
+    EXPECT_FALSE(manager.hi_res_clock_available());
+    EXPECT_FALSE(base::Time::IsHighResolutionTimerInUse());
+
+    // Simulate a off-battery power event.
+    manager.OnPowerStateChange(/* on_battery */ 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)
diff --git a/base/hi_res_timer_manager_win.cc b/base/hi_res_timer_manager_win.cc
new file mode 100644
index 0000000..1a92394
--- /dev/null
+++ b/base/hi_res_timer_manager_win.cc
@@ -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.
+
+#include "base/hi_res_timer_manager.h"
+
+#include "base/time.h"
+
+HighResolutionTimerManager::HighResolutionTimerManager()
+    : hi_res_clock_available_(false) {
+  base::SystemMonitor* system_monitor = base::SystemMonitor::Get();
+  system_monitor->AddPowerObserver(this);
+  UseHiResClock(!system_monitor->BatteryPower());
+}
+
+HighResolutionTimerManager::~HighResolutionTimerManager() {
+  base::SystemMonitor::Get()->RemovePowerObserver(this);
+  UseHiResClock(false);
+}
+
+void HighResolutionTimerManager::OnPowerStateChange(bool on_battery_power) {
+  UseHiResClock(!on_battery_power);
+}
+
+void HighResolutionTimerManager::UseHiResClock(bool use) {
+  if (use == hi_res_clock_available_)
+    return;
+  hi_res_clock_available_ = use;
+  base::Time::EnableHighResolutionTimer(use);
+}
diff --git a/base/i18n/OWNERS b/base/i18n/OWNERS
new file mode 100644
index 0000000..d717b8d
--- /dev/null
+++ b/base/i18n/OWNERS
@@ -0,0 +1 @@
+jshin@chromium.org
diff --git a/base/i18n/base_i18n_export.h b/base/i18n/base_i18n_export.h
new file mode 100644
index 0000000..e8a2add
--- /dev/null
+++ b/base/i18n/base_i18n_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_BASE_I18N_EXPORT_H_
+#define BASE_I18N_BASE_I18N_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_I18N_IMPLEMENTATION)
+#define BASE_I18N_EXPORT __declspec(dllexport)
+#else
+#define BASE_I18N_EXPORT __declspec(dllimport)
+#endif  // defined(BASE_I18N_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(BASE_I18N_IMPLEMENTATION)
+#define BASE_I18N_EXPORT __attribute__((visibility("default")))
+#else
+#define BASE_I18N_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define BASE_I18N_EXPORT
+#endif
+
+#endif  // BASE_I18N_BASE_I18N_EXPORT_H_
diff --git a/base/i18n/bidi_line_iterator.cc b/base/i18n/bidi_line_iterator.cc
new file mode 100644
index 0000000..e81a36b
--- /dev/null
+++ b/base/i18n/bidi_line_iterator.cc
@@ -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.
+
+#include "base/i18n/bidi_line_iterator.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace i18n {
+
+BiDiLineIterator::BiDiLineIterator() : bidi_(NULL) {
+}
+
+BiDiLineIterator::~BiDiLineIterator() {
+  if (bidi_) {
+    ubidi_close(bidi_);
+    bidi_ = NULL;
+  }
+}
+
+bool BiDiLineIterator::Open(const string16& text,
+                            bool right_to_left,
+                            bool url) {
+  DCHECK(!bidi_);
+  UErrorCode error = U_ZERO_ERROR;
+  bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
+  if (U_FAILURE(error))
+    return false;
+  if (right_to_left && url)
+    ubidi_setReorderingMode(bidi_, UBIDI_REORDER_RUNS_ONLY);
+  ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()),
+                right_to_left ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR,
+                NULL, &error);
+  return (U_SUCCESS(error) == TRUE);
+}
+
+int BiDiLineIterator::CountRuns() {
+  DCHECK(bidi_ != NULL);
+  UErrorCode error = U_ZERO_ERROR;
+  const int runs = ubidi_countRuns(bidi_, &error);
+  return U_SUCCESS(error) ? runs : 0;
+}
+
+UBiDiDirection BiDiLineIterator::GetVisualRun(int index,
+                                              int* start,
+                                              int* length) {
+  DCHECK(bidi_ != NULL);
+  return ubidi_getVisualRun(bidi_, index, start, length);
+}
+
+void BiDiLineIterator::GetLogicalRun(int start,
+                                     int* end,
+                                     UBiDiLevel* level) {
+  DCHECK(bidi_ != NULL);
+  ubidi_getLogicalRun(bidi_, start, end, level);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/bidi_line_iterator.h b/base/i18n/bidi_line_iterator.h
new file mode 100644
index 0000000..c1dc0ca
--- /dev/null
+++ b/base/i18n/bidi_line_iterator.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_BIDI_LINE_ITERATOR_H_
+#define BASE_I18N_BIDI_LINE_ITERATOR_H_
+
+#include "unicode/ubidi.h"
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/string16.h"
+
+namespace base {
+namespace i18n {
+
+// A simple wrapper class for the bidirectional iterator of ICU.
+// This class uses the bidirectional iterator of ICU to split a line of
+// bidirectional texts into visual runs in its display order.
+class BASE_I18N_EXPORT BiDiLineIterator {
+ public:
+  BiDiLineIterator();
+  ~BiDiLineIterator();
+
+  // Initializes the bidirectional iterator with the specified text.  Returns
+  // whether initialization succeeded.
+  bool Open(const string16& text, bool right_to_left, bool url);
+
+  // Returns the number of visual runs in the text, or zero on error.
+  int CountRuns();
+
+  // Gets the logical offset, length, and direction of the specified visual run.
+  UBiDiDirection GetVisualRun(int index, int* start, int* length);
+
+  // Given a start position, figure out where the run ends (and the BiDiLevel).
+  void GetLogicalRun(int start, int* end, UBiDiLevel* level);
+
+ private:
+  UBiDi* bidi_;
+
+  DISALLOW_COPY_AND_ASSIGN(BiDiLineIterator);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_BIDI_LINE_ITERATOR_H_
diff --git a/base/i18n/break_iterator.cc b/base/i18n/break_iterator.cc
new file mode 100644
index 0000000..15451e2
--- /dev/null
+++ b/base/i18n/break_iterator.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/break_iterator.h"
+
+#include "base/logging.h"
+#include "unicode/ubrk.h"
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+
+namespace base {
+namespace i18n {
+
+const size_t npos = -1;
+
+BreakIterator::BreakIterator(const string16& str, BreakType break_type)
+    : iter_(NULL),
+      string_(str),
+      break_type_(break_type),
+      prev_(npos),
+      pos_(0) {
+}
+
+BreakIterator::~BreakIterator() {
+  if (iter_)
+    ubrk_close(static_cast<UBreakIterator*>(iter_));
+}
+
+bool BreakIterator::Init() {
+  UErrorCode status = U_ZERO_ERROR;
+  UBreakIteratorType break_type;
+  switch (break_type_) {
+    case BREAK_CHARACTER:
+      break_type = UBRK_CHARACTER;
+      break;
+    case BREAK_WORD:
+      break_type = UBRK_WORD;
+      break;
+    case BREAK_LINE:
+    case BREAK_NEWLINE:
+      break_type = UBRK_LINE;
+      break;
+    default:
+      NOTREACHED() << "invalid break_type_";
+      return false;
+  }
+  iter_ = ubrk_open(break_type, NULL,
+                    string_.data(), static_cast<int32_t>(string_.size()),
+                    &status);
+  if (U_FAILURE(status)) {
+    NOTREACHED() << "ubrk_open failed";
+    return false;
+  }
+  // Move the iterator to the beginning of the string.
+  ubrk_first(static_cast<UBreakIterator*>(iter_));
+  return true;
+}
+
+bool BreakIterator::Advance() {
+  int32_t pos;
+  int32_t status;
+  prev_ = pos_;
+  switch (break_type_) {
+    case BREAK_CHARACTER:
+    case BREAK_WORD:
+    case BREAK_LINE:
+      pos = ubrk_next(static_cast<UBreakIterator*>(iter_));
+      if (pos == UBRK_DONE) {
+        pos_ = npos;
+        return false;
+      }
+      pos_ = static_cast<size_t>(pos);
+      return true;
+    case BREAK_NEWLINE:
+      do {
+        pos = ubrk_next(static_cast<UBreakIterator*>(iter_));
+        if (pos == UBRK_DONE)
+          break;
+        pos_ = static_cast<size_t>(pos);
+        status = ubrk_getRuleStatus(static_cast<UBreakIterator*>(iter_));
+      } while (status >= UBRK_LINE_SOFT && status < UBRK_LINE_SOFT_LIMIT);
+      if (pos == UBRK_DONE && prev_ == pos_) {
+        pos_ = npos;
+        return false;
+      }
+      return true;
+    default:
+      NOTREACHED() << "invalid break_type_";
+      return false;
+  }
+}
+
+bool BreakIterator::IsWord() const {
+  int32_t status = ubrk_getRuleStatus(static_cast<UBreakIterator*>(iter_));
+  return (break_type_ == BREAK_WORD && status != UBRK_WORD_NONE);
+}
+
+bool BreakIterator::IsEndOfWord(size_t position) const {
+  if (break_type_ != BREAK_WORD)
+    return false;
+
+  UBreakIterator* iter = static_cast<UBreakIterator*>(iter_);
+  UBool boundary = ubrk_isBoundary(iter, static_cast<int32_t>(position));
+  int32_t status = ubrk_getRuleStatus(iter);
+  return (!!boundary && status != UBRK_WORD_NONE);
+}
+
+bool BreakIterator::IsStartOfWord(size_t position) const {
+  if (break_type_ != BREAK_WORD)
+    return false;
+
+  UBreakIterator* iter = static_cast<UBreakIterator*>(iter_);
+  UBool boundary = ubrk_isBoundary(iter, static_cast<int32_t>(position));
+  ubrk_next(iter);
+  int32_t next_status = ubrk_getRuleStatus(iter);
+  return (!!boundary && next_status != UBRK_WORD_NONE);
+}
+
+string16 BreakIterator::GetString() const {
+  DCHECK(prev_ != npos && pos_ != npos);
+  return string_.substr(prev_, pos_ - prev_);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/break_iterator.h b/base/i18n/break_iterator.h
new file mode 100644
index 0000000..d558e23
--- /dev/null
+++ b/base/i18n/break_iterator.h
@@ -0,0 +1,131 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_BREAK_ITERATOR_H_
+#define BASE_I18N_BREAK_ITERATOR_H_
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+#include "base/i18n/base_i18n_export.h"
+
+// The BreakIterator class iterates through the words, word breaks, and
+// line breaks in a UTF-16 string.
+//
+// It provides several modes, BREAK_WORD, BREAK_LINE, and BREAK_NEWLINE,
+// which modify how characters are aggregated into the returned string.
+//
+// Under BREAK_WORD mode, once a word is encountered any non-word
+// characters are not included in the returned string (e.g. in the
+// UTF-16 equivalent of the string " foo bar! ", the word breaks are at
+// the periods in ". .foo. .bar.!. .").
+// Note that Chinese/Japanese/Thai do not use spaces between words so that
+// boundaries can fall in the middle of a continuous run of non-space /
+// non-punctuation characters.
+//
+// Under BREAK_LINE mode, once a line breaking opportunity is encountered,
+// any non-word  characters are included in the returned string, breaking
+// only when a space-equivalent character or a line breaking opportunity
+// is encountered (e.g. in the UTF16-equivalent of the string " foo bar! ",
+// the breaks are at the periods in ". .foo .bar! .").
+//
+// Note that lines can be broken at any character/syllable/grapheme cluster
+// boundary in Chinese/Japanese/Korean and at word boundaries in Thai
+// (Thai does not use spaces between words). Therefore, this is NOT the same
+// as breaking only at space-equivalent characters where its former
+// name (BREAK_SPACE) implied.
+//
+// Under BREAK_NEWLINE mode, all characters are included in the returned
+// string, breking only when a newline-equivalent character is encountered
+// (eg. in the UTF-16 equivalent of the string "foo\nbar!\n\n", the line
+// breaks are at the periods in ".foo\n.bar\n.\n.").
+//
+// To extract the words from a string, move a BREAK_WORD BreakIterator
+// through the string and test whether IsWord() is true. E.g.,
+//   BreakIterator iter(str, BreakIterator::BREAK_WORD);
+//   if (!iter.Init())
+//     return false;
+//   while (iter.Advance()) {
+//     if (iter.IsWord()) {
+//       // Region [iter.prev(), iter.pos()) contains a word.
+//       VLOG(1) << "word: " << iter.GetString();
+//     }
+//   }
+
+namespace base {
+namespace i18n {
+
+class BASE_I18N_EXPORT BreakIterator {
+ public:
+  enum BreakType {
+    BREAK_WORD,
+    BREAK_LINE,
+    // TODO(jshin): Remove this after reviewing call sites.
+    // If call sites really need break only on space-like characters
+    // implement it separately.
+    BREAK_SPACE = BREAK_LINE,
+    BREAK_NEWLINE,
+    BREAK_CHARACTER,
+  };
+
+  // Requires |str| to live as long as the BreakIterator does.
+  BreakIterator(const string16& str, BreakType break_type);
+  ~BreakIterator();
+
+  // Init() must be called before any of the iterators are valid.
+  // Returns false if ICU failed to initialize.
+  bool Init();
+
+  // Advance to the next break.  Returns false if we've run past the end of
+  // the string.  (Note that the very last "break" is after the final
+  // character in the string, and when we advance to that position it's the
+  // last time Advance() returns true.)
+  bool Advance();
+
+  // Under BREAK_WORD mode, returns true if the break we just hit is the
+  // end of a word. (Otherwise, the break iterator just skipped over e.g.
+  // whitespace or punctuation.)  Under BREAK_LINE and BREAK_NEWLINE modes,
+  // this distinction doesn't apply and it always retuns false.
+  bool IsWord() const;
+
+  // Under BREAK_WORD mode, returns true if |position| is at the end of word or
+  // at the start of word. It always retuns false under BREAK_LINE and
+  // BREAK_NEWLINE modes.
+  bool IsEndOfWord(size_t position) const;
+  bool IsStartOfWord(size_t position) const;
+
+  // Returns the string between prev() and pos().
+  // Advance() must have been called successfully at least once for pos() to
+  // have advanced to somewhere useful.
+  string16 GetString() const;
+
+  // Returns the value of pos() returned before Advance() was last called.
+  size_t prev() const { return prev_; }
+
+  // Returns the current break position within the string,
+  // or BreakIterator::npos when done.
+  size_t pos() const { return pos_; }
+
+ private:
+  // ICU iterator, avoiding ICU ubrk.h dependence.
+  // This is actually an ICU UBreakiterator* type, which turns out to be
+  // a typedef for a void* in the ICU headers. Using void* directly prevents
+  // callers from needing access to the ICU public headers directory.
+  void* iter_;
+
+  // The string we're iterating over.
+  const string16& string_;
+
+  // The breaking style (word/space/newline).
+  BreakType break_type_;
+
+  // Previous and current iterator positions.
+  size_t prev_, pos_;
+
+  DISALLOW_COPY_AND_ASSIGN(BreakIterator);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_BREAK_ITERATOR_H_
diff --git a/base/i18n/break_iterator_unittest.cc b/base/i18n/break_iterator_unittest.cc
new file mode 100644
index 0000000..afb780c
--- /dev/null
+++ b/base/i18n/break_iterator_unittest.cc
@@ -0,0 +1,338 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/break_iterator.h"
+
+#include "base/string_piece.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace i18n {
+
+TEST(BreakIteratorTest, BreakWordEmpty) {
+  string16 empty;
+  BreakIterator iter(empty, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWord) {
+  string16 space(UTF8ToUTF16(" "));
+  string16 str(UTF8ToUTF16(" foo bar! \npouet boom"));
+  BreakIterator iter(str, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("bar"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("!"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("\n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWide16) {
+  // Two greek words separated by space.
+  const string16 str(WideToUTF16(
+      L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+      L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
+  const string16 word1(str.substr(0, 10));
+  const string16 word2(str.substr(11, 5));
+  BreakIterator iter(str, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(word1, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(word2, iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWide32) {
+  // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+  const char* very_wide_char = "\xF0\x9D\x92\x9C";
+  const string16 str(
+      UTF8ToUTF16(base::StringPrintf("%s a", very_wide_char)));
+  const string16 very_wide_word(str.substr(0, 2));
+
+  BreakIterator iter(str, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(very_wide_word, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceEmpty) {
+  string16 empty;
+  BreakIterator iter(empty, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpace) {
+  string16 str(UTF8ToUTF16(" foo bar! \npouet boom"));
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceSP) {
+  string16 str(UTF8ToUTF16(" foo bar! \npouet boom "));
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("boom "), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpacekWide16) {
+  // Two Greek words.
+  const string16 str(WideToUTF16(
+      L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+      L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
+  const string16 word1(str.substr(0, 11));
+  const string16 word2(str.substr(11, 5));
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(word1, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(word2, iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceWide32) {
+  // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+  const char* very_wide_char = "\xF0\x9D\x92\x9C";
+  const string16 str(
+      UTF8ToUTF16(base::StringPrintf("%s a", very_wide_char)));
+  const string16 very_wide_word(str.substr(0, 3));
+
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(very_wide_word, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineEmpty) {
+  string16 empty;
+  BreakIterator iter(empty, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLine) {
+  string16 nl(UTF8ToUTF16("\n"));
+  string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom"));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet boom"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineNL) {
+  string16 nl(UTF8ToUTF16("\n"));
+  string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom\n"));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet boom\n"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineWide16) {
+  // Two Greek words separated by newline.
+  const string16 str(WideToUTF16(
+      L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+      L"\x03bf\x03c2\x000a\x0399\x03c3\x03c4\x03cc\x03c2"));
+  const string16 line1(str.substr(0, 11));
+  const string16 line2(str.substr(11, 5));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(line1, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(line2, iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineWide32) {
+  // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+  const char* very_wide_char = "\xF0\x9D\x92\x9C";
+  const string16 str(
+      UTF8ToUTF16(base::StringPrintf("%s\na", very_wide_char)));
+  const string16 very_wide_line(str.substr(0, 3));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(very_wide_line, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakCharacter) {
+  static const wchar_t* kCharacters[] = {
+    // An English word consisting of four ASCII characters.
+    L"w", L"o", L"r", L"d", L" ",
+    // A Hindi word (which means "Hindi") consisting of three Devanagari
+    // characters.
+    L"\x0939\x093F", L"\x0928\x094D", L"\x0926\x0940", L" ",
+    // A Thai word (which means "feel") consisting of three Thai characters.
+    L"\x0E23\x0E39\x0E49", L"\x0E2A\x0E36", L"\x0E01", L" ",
+  };
+  std::vector<string16> characters;
+  string16 text;
+  for (size_t i = 0; i < arraysize(kCharacters); ++i) {
+    characters.push_back(WideToUTF16(kCharacters[i]));
+    text.append(characters.back());
+  }
+  BreakIterator iter(text, BreakIterator::BREAK_CHARACTER);
+  ASSERT_TRUE(iter.Init());
+  for (size_t i = 0; i < arraysize(kCharacters); ++i) {
+    EXPECT_TRUE(iter.Advance());
+    EXPECT_EQ(characters[i], iter.GetString());
+  }
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/case_conversion.cc b/base/i18n/case_conversion.cc
new file mode 100644
index 0000000..d3b06c9
--- /dev/null
+++ b/base/i18n/case_conversion.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/case_conversion.h"
+
+#include "base/string16.h"
+#include "unicode/unistr.h"
+
+namespace base {
+namespace i18n {
+
+string16 ToLower(const StringPiece16& string) {
+  icu::UnicodeString unicode_string(string.data(), string.size());
+  unicode_string.toLower();
+  return string16(unicode_string.getBuffer(), unicode_string.length());
+}
+
+string16 ToUpper(const StringPiece16& string) {
+  icu::UnicodeString unicode_string(string.data(), string.size());
+  unicode_string.toUpper();
+  return string16(unicode_string.getBuffer(), unicode_string.length());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/case_conversion.h b/base/i18n/case_conversion.h
new file mode 100644
index 0000000..14fef00
--- /dev/null
+++ b/base/i18n/case_conversion.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_CASE_CONVERSION_H_
+#define BASE_I18N_CASE_CONVERSION_H_
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/string16.h"
+#include "base/string_piece.h"
+
+namespace base {
+namespace i18n {
+
+// Returns the lower case equivalent of string. Uses ICU's default locale.
+BASE_I18N_EXPORT string16 ToLower(const StringPiece16& string);
+
+// Returns the upper case equivalent of string. Uses ICU's default locale.
+BASE_I18N_EXPORT string16 ToUpper(const StringPiece16& string);
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_CASE_CONVERSION_H_
diff --git a/base/i18n/case_conversion_unittest.cc b/base/i18n/case_conversion_unittest.cc
new file mode 100644
index 0000000..63900ec
--- /dev/null
+++ b/base/i18n/case_conversion_unittest.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/case_conversion.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Test upper and lower case string conversion.
+TEST(CaseConversionTest, UpperLower) {
+  string16 mixed(ASCIIToUTF16("Text with UPPer & lowER casE."));
+  const string16 expected_lower(ASCIIToUTF16("text with upper & lower case."));
+  const string16 expected_upper(ASCIIToUTF16("TEXT WITH UPPER & LOWER CASE."));
+
+  string16 result = base::i18n::ToLower(mixed);
+  EXPECT_EQ(expected_lower, result);
+
+  result = base::i18n::ToUpper(mixed);
+  EXPECT_EQ(expected_upper, result);
+}
+
+// TODO(jshin): More tests are needed, especially with non-ASCII characters.
+
+}  // namespace
diff --git a/base/i18n/char_iterator.cc b/base/i18n/char_iterator.cc
new file mode 100644
index 0000000..ce4d513
--- /dev/null
+++ b/base/i18n/char_iterator.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/char_iterator.h"
+
+#include "unicode/utf8.h"
+#include "unicode/utf16.h"
+
+namespace base {
+namespace i18n {
+
+UTF8CharIterator::UTF8CharIterator(const std::string* str)
+    : str_(reinterpret_cast<const uint8_t*>(str->data())),
+      len_(str->size()),
+      array_pos_(0),
+      next_pos_(0),
+      char_pos_(0),
+      char_(0) {
+  if (len_)
+    U8_NEXT(str_, next_pos_, len_, char_);
+}
+
+UTF8CharIterator::~UTF8CharIterator() {
+}
+
+bool UTF8CharIterator::Advance() {
+  if (array_pos_ >= len_)
+    return false;
+
+  array_pos_ = next_pos_;
+  char_pos_++;
+  if (next_pos_ < len_)
+    U8_NEXT(str_, next_pos_, len_, char_);
+
+  return true;
+}
+
+UTF16CharIterator::UTF16CharIterator(const string16* str)
+    : str_(reinterpret_cast<const char16*>(str->data())),
+      len_(str->size()),
+      array_pos_(0),
+      next_pos_(0),
+      char_pos_(0),
+      char_(0) {
+  if (len_)
+    ReadChar();
+}
+
+UTF16CharIterator::UTF16CharIterator(const char16* str, size_t str_len)
+    : str_(str),
+      len_(str_len),
+      array_pos_(0),
+      next_pos_(0),
+      char_pos_(0),
+      char_(0) {
+  if (len_)
+    ReadChar();
+}
+
+UTF16CharIterator::~UTF16CharIterator() {
+}
+
+bool UTF16CharIterator::Advance() {
+  if (array_pos_ >= len_)
+    return false;
+
+  array_pos_ = next_pos_;
+  char_pos_++;
+  if (next_pos_ < len_)
+    ReadChar();
+
+  return true;
+}
+
+void UTF16CharIterator::ReadChar() {
+  // This is actually a huge macro, so is worth having in a separate function.
+  U16_NEXT(str_, next_pos_, len_, char_);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/char_iterator.h b/base/i18n/char_iterator.h
new file mode 100644
index 0000000..431e350
--- /dev/null
+++ b/base/i18n/char_iterator.h
@@ -0,0 +1,130 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_CHAR_ITERATOR_H_
+#define BASE_I18N_CHAR_ITERATOR_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/string16.h"
+
+// The CharIterator classes iterate through the characters in UTF8 and
+// UTF16 strings.  Example usage:
+//
+//   UTF8CharIterator iter(&str);
+//   while (!iter.End()) {
+//     VLOG(1) << iter.get();
+//     iter.Advance();
+//   }
+
+#if defined(OS_WIN)
+typedef unsigned char uint8_t;
+#endif
+
+namespace base {
+namespace i18n {
+
+class BASE_I18N_EXPORT UTF8CharIterator {
+ public:
+  // Requires |str| to live as long as the UTF8CharIterator does.
+  UTF8CharIterator(const std::string* str);
+  ~UTF8CharIterator();
+
+  // Return the starting array index of the current character within the
+  // string.
+  int32 array_pos() const { return array_pos_; }
+
+  // Return the logical index of the current character, independent of the
+  // number of bytes each character takes.
+  int32 char_pos() const { return char_pos_; }
+
+  // Return the current char.
+  int32 get() const { return char_; }
+
+  // Returns true if we're at the end of the string.
+  bool end() const { return array_pos_ == len_; }
+
+  // Advance to the next actual character.  Returns false if we're at the
+  // end of the string.
+  bool Advance();
+
+ private:
+  // The string we're iterating over.
+  const uint8_t* str_;
+
+  // The length of the encoded string.
+  int32 len_;
+
+  // Array index.
+  int32 array_pos_;
+
+  // The next array index.
+  int32 next_pos_;
+
+  // Character index.
+  int32 char_pos_;
+
+  // The current character.
+  int32 char_;
+
+  DISALLOW_COPY_AND_ASSIGN(UTF8CharIterator);
+};
+
+class BASE_I18N_EXPORT UTF16CharIterator {
+ public:
+  // Requires |str| to live as long as the UTF16CharIterator does.
+  UTF16CharIterator(const string16* str);
+  UTF16CharIterator(const char16* str, size_t str_len);
+  ~UTF16CharIterator();
+
+  // Return the starting array index of the current character within the
+  // string.
+  int32 array_pos() const { return array_pos_; }
+
+  // Return the logical index of the current character, independent of the
+  // number of codewords each character takes.
+  int32 char_pos() const { return char_pos_; }
+
+  // Return the current char.
+  int32 get() const { return char_; }
+
+  // Returns true if we're at the end of the string.
+  bool end() const { return array_pos_ == len_; }
+
+  // Advance to the next actual character.  Returns false if we're at the
+  // end of the string.
+  bool Advance();
+
+ private:
+  // Fills in the current character we found and advances to the next
+  // character, updating all flags as necessary.
+  void ReadChar();
+
+  // The string we're iterating over.
+  const char16* str_;
+
+  // The length of the encoded string.
+  int32 len_;
+
+  // Array index.
+  int32 array_pos_;
+
+  // The next array index.
+  int32 next_pos_;
+
+  // Character index.
+  int32 char_pos_;
+
+  // The current character.
+  int32 char_;
+
+  DISALLOW_COPY_AND_ASSIGN(UTF16CharIterator);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_CHAR_ITERATOR_H_
diff --git a/base/i18n/char_iterator_unittest.cc b/base/i18n/char_iterator_unittest.cc
new file mode 100644
index 0000000..6d1294e
--- /dev/null
+++ b/base/i18n/char_iterator_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/char_iterator.h"
+
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace i18n {
+
+TEST(CharIteratorsTest, TestUTF8) {
+  std::string empty("");
+  UTF8CharIterator empty_iter(&empty);
+  ASSERT_TRUE(empty_iter.end());
+  ASSERT_EQ(0, empty_iter.array_pos());
+  ASSERT_EQ(0, empty_iter.char_pos());
+  ASSERT_FALSE(empty_iter.Advance());
+
+  std::string str("s\303\273r");  // [u with circumflex]
+  UTF8CharIterator iter(&str);
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(0, iter.array_pos());
+  ASSERT_EQ(0, iter.char_pos());
+  ASSERT_EQ('s', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(1, iter.array_pos());
+  ASSERT_EQ(1, iter.char_pos());
+  ASSERT_EQ(251, iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(3, iter.array_pos());
+  ASSERT_EQ(2, iter.char_pos());
+  ASSERT_EQ('r', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_TRUE(iter.end());
+  ASSERT_EQ(4, iter.array_pos());
+  ASSERT_EQ(3, iter.char_pos());
+
+  // Don't care what it returns, but this shouldn't crash
+  iter.get();
+
+  ASSERT_FALSE(iter.Advance());
+}
+
+TEST(CharIteratorsTest, TestUTF16) {
+  string16 empty = UTF8ToUTF16("");
+  UTF16CharIterator empty_iter(&empty);
+  ASSERT_TRUE(empty_iter.end());
+  ASSERT_EQ(0, empty_iter.array_pos());
+  ASSERT_EQ(0, empty_iter.char_pos());
+  ASSERT_FALSE(empty_iter.Advance());
+
+  // This test string contains 4 characters:
+  //   x
+  //   u with circumflex - 2 bytes in UTF8, 1 codeword in UTF16
+  //   math double-struck A - 4 bytes in UTF8, 2 codewords in UTF16
+  //   z
+  string16 str = UTF8ToUTF16("x\303\273\360\235\224\270z");
+  UTF16CharIterator iter(&str);
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(0, iter.array_pos());
+  ASSERT_EQ(0, iter.char_pos());
+  ASSERT_EQ('x', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(1, iter.array_pos());
+  ASSERT_EQ(1, iter.char_pos());
+  ASSERT_EQ(251, iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(2, iter.array_pos());
+  ASSERT_EQ(2, iter.char_pos());
+  ASSERT_EQ(120120, iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(4, iter.array_pos());
+  ASSERT_EQ(3, iter.char_pos());
+  ASSERT_EQ('z', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_TRUE(iter.end());
+  ASSERT_EQ(5, iter.array_pos());
+  ASSERT_EQ(4, iter.char_pos());
+
+  // Don't care what it returns, but this shouldn't crash
+  iter.get();
+
+  ASSERT_FALSE(iter.Advance());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/file_util_icu.cc b/base/i18n/file_util_icu.cc
new file mode 100644
index 0000000..f44af10
--- /dev/null
+++ b/base/i18n/file_util_icu.cc
@@ -0,0 +1,214 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// File utilities that use the ICU library go in this file.
+
+#include "base/i18n/file_util_icu.h"
+
+#include "base/file_path.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/sys_string_conversions.h"
+#include "build/build_config.h"
+#include "unicode/coll.h"
+#include "unicode/uniset.h"
+
+namespace {
+
+class IllegalCharacters {
+ public:
+  static IllegalCharacters* GetInstance() {
+    return Singleton<IllegalCharacters>::get();
+  }
+
+  bool contains(UChar32 ucs4) {
+    return !!set->contains(ucs4);
+  }
+
+  bool containsNone(const string16 &s) {
+    return !!set->containsNone(icu::UnicodeString(s.c_str(), s.size()));
+  }
+
+ private:
+  friend class Singleton<IllegalCharacters>;
+  friend struct DefaultSingletonTraits<IllegalCharacters>;
+
+  IllegalCharacters();
+  ~IllegalCharacters() { }
+
+  scoped_ptr<icu::UnicodeSet> set;
+
+  DISALLOW_COPY_AND_ASSIGN(IllegalCharacters);
+};
+
+IllegalCharacters::IllegalCharacters() {
+  UErrorCode status = U_ZERO_ERROR;
+  // Control characters, formatting characters, non-characters, and
+  // some printable ASCII characters regarded as dangerous ('"*/:<>?\\').
+  // See  http://blogs.msdn.com/michkap/archive/2006/11/03/941420.aspx
+  // and http://msdn2.microsoft.com/en-us/library/Aa365247.aspx
+  // TODO(jungshik): Revisit the set. ZWJ and ZWNJ are excluded because they
+  // are legitimate in Arabic and some S/SE Asian scripts. However, when used
+  // elsewhere, they can be confusing/problematic.
+  // Also, consider wrapping the set with our Singleton class to create and
+  // freeze it only once. Note that there's a trade-off between memory and
+  // speed.
+#if defined(WCHAR_T_IS_UTF16)
+  set.reset(new icu::UnicodeSet(icu::UnicodeString(
+      L"[[\"*/:<>?\\\\|][:Cc:][:Cf:] - [\u200c\u200d]]"), status));
+#else
+  set.reset(new icu::UnicodeSet(UNICODE_STRING_SIMPLE(
+      "[[\"*/:<>?\\\\|][:Cc:][:Cf:] - [\\u200c\\u200d]]").unescape(),
+      status));
+#endif
+  DCHECK(U_SUCCESS(status));
+  // Add non-characters. If this becomes a performance bottleneck by
+  // any chance, do not add these to |set| and change IsFilenameLegal()
+  // to check |ucs4 & 0xFFFEu == 0xFFFEu|, in addiition to calling
+  // containsNone().
+  set->add(0xFDD0, 0xFDEF);
+  for (int i = 0; i <= 0x10; ++i) {
+    int plane_base = 0x10000 * i;
+    set->add(plane_base + 0xFFFE, plane_base + 0xFFFF);
+  }
+  set->freeze();
+}
+
+class LocaleAwareComparator {
+ public:
+  static LocaleAwareComparator* GetInstance() {
+    return Singleton<LocaleAwareComparator,
+                     LeakySingletonTraits<LocaleAwareComparator> >::get();
+  }
+
+  // Note: A similar function is available in l10n_util.
+  // We cannot use it because base should not depend on l10n_util.
+  // TODO(yuzo): Move some of l10n_util to base.
+  int Compare(const string16& a, const string16& b) {
+    // We are not sure if Collator::compare is thread-safe.
+    // Use an AutoLock just in case.
+    base::AutoLock auto_lock(lock_);
+
+    UErrorCode error_code = U_ZERO_ERROR;
+    UCollationResult result = collator_->compare(
+        static_cast<const UChar*>(a.c_str()),
+        static_cast<int>(a.length()),
+        static_cast<const UChar*>(b.c_str()),
+        static_cast<int>(b.length()),
+        error_code);
+    DCHECK(U_SUCCESS(error_code));
+    return result;
+  }
+
+ private:
+  friend struct DefaultSingletonTraits<LocaleAwareComparator>;
+
+  LocaleAwareComparator() {
+    UErrorCode error_code = U_ZERO_ERROR;
+    // Use the default collator. The default locale should have been properly
+    // set by the time this constructor is called.
+    collator_.reset(icu::Collator::createInstance(error_code));
+    DCHECK(U_SUCCESS(error_code));
+    // Make it case-sensitive.
+    collator_->setStrength(icu::Collator::TERTIARY);
+    // Note: We do not set UCOL_NORMALIZATION_MODE attribute. In other words, we
+    // do not pay performance penalty to guarantee sort order correctness for
+    // non-FCD (http://unicode.org/notes/tn5/#FCD) file names. This should be a
+    // reasonable tradeoff because such file names should be rare and the sort
+    // order doesn't change much anyway.
+  }
+
+  scoped_ptr<icu::Collator> collator_;
+  base::Lock lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocaleAwareComparator);
+};
+
+}  // namespace
+
+namespace file_util {
+
+bool IsFilenameLegal(const string16& file_name) {
+  return IllegalCharacters::GetInstance()->containsNone(file_name);
+}
+
+void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name,
+                                    char replace_char) {
+  DCHECK(file_name);
+
+  DCHECK(!(IllegalCharacters::GetInstance()->contains(replace_char)));
+
+  // Remove leading and trailing whitespace.
+  TrimWhitespace(*file_name, TRIM_ALL, file_name);
+
+  IllegalCharacters* illegal = IllegalCharacters::GetInstance();
+  int cursor = 0;  // The ICU macros expect an int.
+  while (cursor < static_cast<int>(file_name->size())) {
+    int char_begin = cursor;
+    uint32 code_point;
+#if defined(OS_MACOSX)
+    // Mac uses UTF-8 encoding for filenames.
+    U8_NEXT(file_name->data(), cursor, static_cast<int>(file_name->length()),
+            code_point);
+#elif defined(OS_WIN)
+    // Windows uses UTF-16 encoding for filenames.
+    U16_NEXT(file_name->data(), cursor, static_cast<int>(file_name->length()),
+             code_point);
+#elif defined(OS_POSIX)
+    // Linux doesn't actually define an encoding. It basically allows anything
+    // except for a few special ASCII characters.
+    unsigned char cur_char = static_cast<unsigned char>((*file_name)[cursor++]);
+    if (cur_char >= 0x80)
+      continue;
+    code_point = cur_char;
+#else
+    NOTREACHED();
+#endif
+
+    if (illegal->contains(code_point)) {
+      file_name->replace(char_begin, cursor - char_begin, 1, replace_char);
+      // We just made the potentially multi-byte/word char into one that only
+      // takes one byte/word, so need to adjust the cursor to point to the next
+      // character again.
+      cursor = char_begin + 1;
+    }
+  }
+}
+
+bool LocaleAwareCompareFilenames(const FilePath& a, const FilePath& b) {
+#if defined(OS_WIN)
+  return LocaleAwareComparator::GetInstance()->Compare(a.value().c_str(),
+                                                       b.value().c_str()) < 0;
+
+#elif defined(OS_POSIX)
+  // On linux, the file system encoding is not defined. We assume
+  // SysNativeMBToWide takes care of it.
+  //
+  // ICU's collator can take strings in OS native encoding. But we convert the
+  // strings to UTF-16 ourselves to ensure conversion consistency.
+  // TODO(yuzo): Perhaps we should define SysNativeMBToUTF16?
+  return LocaleAwareComparator::GetInstance()->Compare(
+      WideToUTF16(base::SysNativeMBToWide(a.value().c_str())),
+      WideToUTF16(base::SysNativeMBToWide(b.value().c_str()))) < 0;
+#else
+  #error Not implemented on your system
+#endif
+}
+
+void NormalizeFileNameEncoding(FilePath* file_name) {
+#if defined(OS_CHROMEOS)
+  std::string normalized_str;
+  if (base::ConvertToUtf8AndNormalize(file_name->BaseName().value(),
+                                      base::kCodepageUTF8,
+                                      &normalized_str)) {
+    *file_name = file_name->DirName().Append(FilePath(normalized_str));
+  }
+#endif
+}
+
+}  // namespace
diff --git a/base/i18n/file_util_icu.h b/base/i18n/file_util_icu.h
new file mode 100644
index 0000000..4672135
--- /dev/null
+++ b/base/i18n/file_util_icu.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_I18N_FILE_UTIL_ICU_H_
+#define BASE_I18N_FILE_UTIL_ICU_H_
+
+// File utilities that use the ICU library go in this file.
+
+#include "base/file_path.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/string16.h"
+
+namespace file_util {
+
+// Returns true if file_name does not have any illegal character. The input
+// param has the same restriction as that for ReplaceIllegalCharacters.
+BASE_I18N_EXPORT bool IsFilenameLegal(const string16& file_name);
+
+// Replaces characters in 'file_name' that are illegal for file names with
+// 'replace_char'. 'file_name' must not be a full or relative path, but just the
+// file name component (since slashes are considered illegal). Any leading or
+// trailing whitespace in 'file_name' is removed.
+// Example:
+//   file_name == "bad:file*name?.txt", changed to: "bad-file-name-.txt" when
+//   'replace_char' is '-'.
+BASE_I18N_EXPORT void ReplaceIllegalCharactersInPath(
+    FilePath::StringType* file_name,
+    char replace_char);
+
+// Compares two filenames using the current locale information. This can be
+// used to sort directory listings. It behaves like "operator<" for use in
+// std::sort.
+BASE_I18N_EXPORT bool LocaleAwareCompareFilenames(const FilePath& a,
+                                                  const FilePath& b);
+
+// Calculates the canonical file-system representation of |file_name| base name.
+// Modifies |file_name| in place. No-op if not on ChromeOS.
+BASE_I18N_EXPORT void NormalizeFileNameEncoding(FilePath* file_name);
+
+}  // namespace file_util
+
+#endif  // BASE_I18N_FILE_UTIL_ICU_H_
diff --git a/base/i18n/file_util_icu_unittest.cc b/base/i18n/file_util_icu_unittest.cc
new file mode 100644
index 0000000..dfc4943
--- /dev/null
+++ b/base/i18n/file_util_icu_unittest.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/file_util_icu.h"
+
+#include "base/file_util.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest
+class FileUtilICUTest : public PlatformTest {
+};
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+
+// Linux disallows some evil ASCII characters, but passes all non-ASCII.
+static const struct goodbad_pair {
+  const char* bad_name;
+  const char* good_name;
+} kIllegalCharacterCases[] = {
+  {"bad*file:name?.jpg", "bad-file-name-.jpg"},
+  {"**********::::.txt", "--------------.txt"},
+  {"\xe9\xf0zzzz.\xff", "\xe9\xf0zzzz.\xff"},
+};
+
+TEST_F(FileUtilICUTest, ReplaceIllegalCharacersInPathLinuxTest) {
+  for (size_t i = 0; i < arraysize(kIllegalCharacterCases); ++i) {
+    std::string bad_name(kIllegalCharacterCases[i].bad_name);
+    file_util::ReplaceIllegalCharactersInPath(&bad_name, '-');
+    EXPECT_EQ(kIllegalCharacterCases[i].good_name, bad_name);
+  }
+}
+
+#else
+
+// For Mac & Windows, which both do Unicode validation on filenames. These
+// characters are given as wide strings since its more convenient to specify
+// unicode characters. For Mac they should be converted to UTF-8.
+static const struct goodbad_pair {
+  const wchar_t* bad_name;
+  const wchar_t* good_name;
+} kIllegalCharacterCases[] = {
+  {L"bad*file:name?.jpg", L"bad-file-name-.jpg"},
+  {L"**********::::.txt", L"--------------.txt"},
+  // We can't use UCNs (universal character names) for C0/C1 characters and
+  // U+007F, but \x escape is interpreted by MSVC and gcc as we intend.
+  {L"bad\x0003\x0091 file\u200E\u200Fname.png", L"bad-- file--name.png"},
+#if defined(OS_WIN)
+  {L"bad*file\\name.jpg", L"bad-file-name.jpg"},
+  {L"\t  bad*file\\name/.jpg ", L"bad-file-name-.jpg"},
+#elif defined(OS_MACOSX)
+  {L"bad*file?name.jpg", L"bad-file-name.jpg"},
+  {L"\t  bad*file?name/.jpg ", L"bad-file-name-.jpg"},
+#endif
+  {L"this_file_name is okay!.mp3", L"this_file_name is okay!.mp3"},
+  {L"\u4E00\uAC00.mp3", L"\u4E00\uAC00.mp3"},
+  {L"\u0635\u200C\u0644.mp3", L"\u0635\u200C\u0644.mp3"},
+  {L"\U00010330\U00010331.mp3", L"\U00010330\U00010331.mp3"},
+  // Unassigned codepoints are ok.
+  {L"\u0378\U00040001.mp3", L"\u0378\U00040001.mp3"},
+  // Non-characters are not allowed.
+  {L"bad\uFFFFfile\U0010FFFEname.jpg ", L"bad-file-name.jpg"},
+  {L"bad\uFDD0file\uFDEFname.jpg ", L"bad-file-name.jpg"},
+};
+
+TEST_F(FileUtilICUTest, ReplaceIllegalCharactersInPathTest) {
+  for (size_t i = 0; i < arraysize(kIllegalCharacterCases); ++i) {
+#if defined(OS_WIN)
+    std::wstring bad_name(kIllegalCharacterCases[i].bad_name);
+    file_util::ReplaceIllegalCharactersInPath(&bad_name, '-');
+    EXPECT_EQ(kIllegalCharacterCases[i].good_name, bad_name);
+#elif defined(OS_MACOSX)
+    std::string bad_name(WideToUTF8(kIllegalCharacterCases[i].bad_name));
+    file_util::ReplaceIllegalCharactersInPath(&bad_name, '-');
+    EXPECT_EQ(WideToUTF8(kIllegalCharacterCases[i].good_name), bad_name);
+#endif
+  }
+}
+
+#endif
+
+#if defined(OS_CHROMEOS)
+static const struct normalize_name_encoding_test_cases {
+  const char* original_path;
+  const char* normalized_path;
+} kNormalizeFileNameEncodingTestCases[] = {
+  { "foo_na\xcc\x88me.foo", "foo_n\xc3\xa4me.foo"},
+  { "foo_dir_na\xcc\x88me/foo_na\xcc\x88me.foo",
+    "foo_dir_na\xcc\x88me/foo_n\xc3\xa4me.foo"},
+  { "", ""},
+  { "foo_dir_na\xcc\x88me/", "foo_dir_n\xc3\xa4me"}
+};
+
+TEST_F(FileUtilICUTest, NormalizeFileNameEncoding) {
+  for (size_t i = 0; i < arraysize(kNormalizeFileNameEncodingTestCases); i++) {
+    FilePath path(kNormalizeFileNameEncodingTestCases[i].original_path);
+    file_util::NormalizeFileNameEncoding(&path);
+    EXPECT_EQ(FilePath(kNormalizeFileNameEncodingTestCases[i].normalized_path),
+              path);
+  }
+}
+
+#endif
diff --git a/base/i18n/icu_encoding_detection.cc b/base/i18n/icu_encoding_detection.cc
new file mode 100644
index 0000000..2081c7a
--- /dev/null
+++ b/base/i18n/icu_encoding_detection.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/icu_encoding_detection.h"
+
+#include <set>
+
+#include "base/string_util.h"
+#include "unicode/ucsdet.h"
+
+namespace base {
+
+bool DetectEncoding(const std::string& text, std::string* encoding) {
+  if (IsStringASCII(text)) {
+    *encoding = std::string();
+    return true;
+  }
+
+  UErrorCode status = U_ZERO_ERROR;
+  UCharsetDetector* detector = ucsdet_open(&status);
+  ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()),
+                 &status);
+  const UCharsetMatch* match = ucsdet_detect(detector, &status);
+  if (match == NULL)
+    return false;
+  const char* detected_encoding = ucsdet_getName(match, &status);
+  ucsdet_close(detector);
+
+  if (U_FAILURE(status))
+    return false;
+
+  *encoding = detected_encoding;
+  return true;
+}
+
+bool DetectAllEncodings(const std::string& text,
+                        std::vector<std::string>* encodings) {
+  UErrorCode status = U_ZERO_ERROR;
+  UCharsetDetector* detector = ucsdet_open(&status);
+  ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()),
+                 &status);
+  int matches_count = 0;
+  const UCharsetMatch** matches = ucsdet_detectAll(detector,
+                                                   &matches_count,
+                                                   &status);
+  if (U_FAILURE(status)) {
+    ucsdet_close(detector);
+    return false;
+  }
+
+  // ICU has some heuristics for encoding detection, such that the more likely
+  // encodings should be returned first. However, it doesn't always return
+  // all encodings that properly decode |text|, so we'll append more encodings
+  // later. To make that efficient, keep track of encodings sniffed in this
+  // first phase.
+  std::set<std::string> sniffed_encodings;
+
+  encodings->clear();
+  for (int i = 0; i < matches_count; i++) {
+    UErrorCode get_name_status = U_ZERO_ERROR;
+    const char* encoding_name = ucsdet_getName(matches[i], &get_name_status);
+
+    // If we failed to get the encoding's name, ignore the error.
+    if (U_FAILURE(get_name_status))
+      continue;
+
+    int32_t confidence = ucsdet_getConfidence(matches[i], &get_name_status);
+
+    // We also treat this error as non-fatal.
+    if (U_FAILURE(get_name_status))
+      continue;
+
+    // A confidence level >= 10 means that the encoding is expected to properly
+    // decode the text. Drop all encodings with lower confidence level.
+    if (confidence < 10)
+      continue;
+
+    encodings->push_back(encoding_name);
+    sniffed_encodings.insert(encoding_name);
+  }
+
+  // Append all encodings not included earlier, in arbitrary order.
+  // TODO(jshin): This shouldn't be necessary, possible ICU bug.
+  // See also http://crbug.com/65917.
+  UEnumeration* detectable_encodings = ucsdet_getAllDetectableCharsets(detector,
+                                                                       &status);
+  int detectable_count = uenum_count(detectable_encodings, &status);
+  for (int i = 0; i < detectable_count; i++) {
+    int name_length;
+    const char* name_raw = uenum_next(detectable_encodings,
+                                      &name_length,
+                                      &status);
+    std::string name(name_raw, name_length);
+    if (sniffed_encodings.find(name) == sniffed_encodings.end())
+      encodings->push_back(name);
+  }
+  uenum_close(detectable_encodings);
+
+  ucsdet_close(detector);
+  return !encodings->empty();
+}
+
+}  // namespace base
diff --git a/base/i18n/icu_encoding_detection.h b/base/i18n/icu_encoding_detection.h
new file mode 100644
index 0000000..6d1e71c
--- /dev/null
+++ b/base/i18n/icu_encoding_detection.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_ICU_ENCODING_DETECTION_H_
+#define BASE_I18N_ICU_ENCODING_DETECTION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/i18n/base_i18n_export.h"
+
+namespace base {
+
+// Detect encoding of |text| and put the name of encoding (as returned by ICU)
+// in |encoding|. For ASCII texts |encoding| will be set to an empty string.
+// Returns true on success.
+BASE_I18N_EXPORT bool DetectEncoding(const std::string& text,
+                                     std::string* encoding);
+
+// Detect all possible encodings of |text| and put their names
+// (as returned by ICU) in |encodings|. Returns true on success.
+// Note: this function may return encodings that may fail to decode |text|,
+// the caller is responsible for handling that.
+BASE_I18N_EXPORT bool DetectAllEncodings(const std::string& text,
+                                         std::vector<std::string>* encodings);
+
+}  // namespace base
+
+#endif  // BASE_I18N_ICU_ENCODING_DETECTION_H_
diff --git a/base/i18n/icu_string_conversions.cc b/base/i18n/icu_string_conversions.cc
new file mode 100644
index 0000000..5ebadf3
--- /dev/null
+++ b/base/i18n/icu_string_conversions.cc
@@ -0,0 +1,297 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/icu_string_conversions.h"
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "unicode/ucnv.h"
+#include "unicode/ucnv_cb.h"
+#include "unicode/ucnv_err.h"
+#include "unicode/unorm.h"
+#include "unicode/ustring.h"
+
+namespace base {
+
+namespace {
+// ToUnicodeCallbackSubstitute() is based on UCNV_TO_U_CALLBACK_SUBSTITUTE
+// in source/common/ucnv_err.c.
+
+// Copyright (c) 1995-2006 International Business Machines Corporation
+// and others
+//
+// All rights reserved.
+//
+
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, and/or
+// sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, provided that the above copyright notice(s) and
+// this permission notice appear in all copies of the Software and that
+// both the above copyright notice(s) and this permission notice appear in
+// supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+// INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
+// OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+// OR PERFORMANCE OF THIS SOFTWARE.
+//
+// Except as contained in this notice, the name of a copyright holder
+// shall not be used in advertising or otherwise to promote the sale, use
+// or other dealings in this Software without prior written authorization
+// of the copyright holder.
+
+//  ___________________________________________________________________________
+//
+// All trademarks and registered trademarks mentioned herein are the property
+// of their respective owners.
+
+void ToUnicodeCallbackSubstitute(const void* context,
+                                 UConverterToUnicodeArgs *to_args,
+                                 const char* code_units,
+                                 int32_t length,
+                                 UConverterCallbackReason reason,
+                                 UErrorCode * err) {
+  static const UChar kReplacementChar = 0xFFFD;
+  if (reason <= UCNV_IRREGULAR) {
+      if (context == NULL ||
+          (*(reinterpret_cast<const char*>(context)) == 'i' &&
+           reason == UCNV_UNASSIGNED)) {
+        *err = U_ZERO_ERROR;
+        ucnv_cbToUWriteUChars(to_args, &kReplacementChar, 1, 0, err);
+      }
+      // else the caller must have set the error code accordingly.
+  }
+  // else ignore the reset, close and clone calls.
+}
+
+bool ConvertFromUTF16(UConverter* converter, const UChar* uchar_src,
+                      int uchar_len, OnStringConversionError::Type on_error,
+                      std::string* encoded) {
+  int encoded_max_length = UCNV_GET_MAX_BYTES_FOR_STRING(uchar_len,
+      ucnv_getMaxCharSize(converter));
+  encoded->resize(encoded_max_length);
+
+  UErrorCode status = U_ZERO_ERROR;
+
+  // Setup our error handler.
+  switch (on_error) {
+    case OnStringConversionError::FAIL:
+      ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_STOP, 0,
+                            NULL, NULL, &status);
+      break;
+    case OnStringConversionError::SKIP:
+    case OnStringConversionError::SUBSTITUTE:
+      ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SKIP, 0,
+                            NULL, NULL, &status);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  // ucnv_fromUChars returns size not including terminating null
+  int actual_size = ucnv_fromUChars(converter, &(*encoded)[0],
+      encoded_max_length, uchar_src, uchar_len, &status);
+  encoded->resize(actual_size);
+  ucnv_close(converter);
+  if (U_SUCCESS(status))
+    return true;
+  encoded->clear();  // Make sure the output is empty on error.
+  return false;
+}
+
+// Set up our error handler for ToUTF-16 converters
+void SetUpErrorHandlerForToUChars(OnStringConversionError::Type on_error,
+                                  UConverter* converter, UErrorCode* status) {
+  switch (on_error) {
+    case OnStringConversionError::FAIL:
+      ucnv_setToUCallBack(converter, UCNV_TO_U_CALLBACK_STOP, 0,
+                          NULL, NULL, status);
+      break;
+    case OnStringConversionError::SKIP:
+      ucnv_setToUCallBack(converter, UCNV_TO_U_CALLBACK_SKIP, 0,
+                          NULL, NULL, status);
+      break;
+    case OnStringConversionError::SUBSTITUTE:
+      ucnv_setToUCallBack(converter, ToUnicodeCallbackSubstitute, 0,
+                          NULL, NULL, status);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+inline UConverterType utf32_platform_endian() {
+#if U_IS_BIG_ENDIAN
+  return UCNV_UTF32_BigEndian;
+#else
+  return UCNV_UTF32_LittleEndian;
+#endif
+}
+
+}  // namespace
+
+const char kCodepageLatin1[] = "ISO-8859-1";
+const char kCodepageUTF8[] = "UTF-8";
+const char kCodepageUTF16BE[] = "UTF-16BE";
+const char kCodepageUTF16LE[] = "UTF-16LE";
+
+// Codepage <-> Wide/UTF-16  ---------------------------------------------------
+
+bool UTF16ToCodepage(const string16& utf16,
+                     const char* codepage_name,
+                     OnStringConversionError::Type on_error,
+                     std::string* encoded) {
+  encoded->clear();
+
+  UErrorCode status = U_ZERO_ERROR;
+  UConverter* converter = ucnv_open(codepage_name, &status);
+  if (!U_SUCCESS(status))
+    return false;
+
+  return ConvertFromUTF16(converter, utf16.c_str(),
+                          static_cast<int>(utf16.length()), on_error, encoded);
+}
+
+bool CodepageToUTF16(const std::string& encoded,
+                     const char* codepage_name,
+                     OnStringConversionError::Type on_error,
+                     string16* utf16) {
+  utf16->clear();
+
+  UErrorCode status = U_ZERO_ERROR;
+  UConverter* converter = ucnv_open(codepage_name, &status);
+  if (!U_SUCCESS(status))
+    return false;
+
+  // Even in the worst case, the maximum length in 2-byte units of UTF-16
+  // output would be at most the same as the number of bytes in input. There
+  // is no single-byte encoding in which a character is mapped to a
+  // non-BMP character requiring two 2-byte units.
+  //
+  // Moreover, non-BMP characters in legacy multibyte encodings
+  // (e.g. EUC-JP, GB18030) take at least 2 bytes. The only exceptions are
+  // BOCU and SCSU, but we don't care about them.
+  size_t uchar_max_length = encoded.length() + 1;
+
+  SetUpErrorHandlerForToUChars(on_error, converter, &status);
+  scoped_array<char16> buffer(new char16[uchar_max_length]);
+  int actual_size = ucnv_toUChars(converter, buffer.get(),
+      static_cast<int>(uchar_max_length), encoded.data(),
+      static_cast<int>(encoded.length()), &status);
+  ucnv_close(converter);
+  if (!U_SUCCESS(status)) {
+    utf16->clear();  // Make sure the output is empty on error.
+    return false;
+  }
+
+  utf16->assign(buffer.get(), actual_size);
+  return true;
+}
+
+bool WideToCodepage(const std::wstring& wide,
+                    const char* codepage_name,
+                    OnStringConversionError::Type on_error,
+                    std::string* encoded) {
+#if defined(WCHAR_T_IS_UTF16)
+  return UTF16ToCodepage(wide, codepage_name, on_error, encoded);
+#elif defined(WCHAR_T_IS_UTF32)
+  encoded->clear();
+
+  UErrorCode status = U_ZERO_ERROR;
+  UConverter* converter = ucnv_open(codepage_name, &status);
+  if (!U_SUCCESS(status))
+    return false;
+
+  int utf16_len;
+  // When wchar_t is wider than UChar (16 bits), transform |wide| into a
+  // UChar* string.  Size the UChar* buffer to be large enough to hold twice
+  // as many UTF-16 code units (UChar's) as there are Unicode code points,
+  // in case each code points translates to a UTF-16 surrogate pair,
+  // and leave room for a NUL terminator.
+  std::vector<UChar> utf16(wide.length() * 2 + 1);
+  u_strFromUTF32(&utf16[0], utf16.size(), &utf16_len,
+                 reinterpret_cast<const UChar32*>(wide.c_str()),
+                 wide.length(), &status);
+  DCHECK(U_SUCCESS(status)) << "failed to convert wstring to UChar*";
+
+  return ConvertFromUTF16(converter, &utf16[0], utf16_len, on_error, encoded);
+#endif  // defined(WCHAR_T_IS_UTF32)
+}
+
+bool CodepageToWide(const std::string& encoded,
+                    const char* codepage_name,
+                    OnStringConversionError::Type on_error,
+                    std::wstring* wide) {
+#if defined(WCHAR_T_IS_UTF16)
+  return CodepageToUTF16(encoded, codepage_name, on_error, wide);
+#elif defined(WCHAR_T_IS_UTF32)
+  wide->clear();
+
+  UErrorCode status = U_ZERO_ERROR;
+  UConverter* converter = ucnv_open(codepage_name, &status);
+  if (!U_SUCCESS(status))
+    return false;
+
+  // The maximum length in 4 byte unit of UTF-32 output would be
+  // at most the same as the number of bytes in input. In the worst
+  // case of GB18030 (excluding escaped-based encodings like ISO-2022-JP),
+  // this can be 4 times larger than actually needed.
+  size_t wchar_max_length = encoded.length() + 1;
+
+  SetUpErrorHandlerForToUChars(on_error, converter, &status);
+  scoped_array<wchar_t> buffer(new wchar_t[wchar_max_length]);
+  int actual_size = ucnv_toAlgorithmic(utf32_platform_endian(), converter,
+      reinterpret_cast<char*>(buffer.get()),
+      static_cast<int>(wchar_max_length) * sizeof(wchar_t), encoded.data(),
+      static_cast<int>(encoded.length()), &status);
+  ucnv_close(converter);
+  if (!U_SUCCESS(status)) {
+    wide->clear();  // Make sure the output is empty on error.
+    return false;
+  }
+
+  // actual_size is # of bytes.
+  wide->assign(buffer.get(), actual_size / sizeof(wchar_t));
+  return true;
+#endif  // defined(WCHAR_T_IS_UTF32)
+}
+
+bool ConvertToUtf8AndNormalize(const std::string& text,
+                               const std::string& charset,
+                               std::string* result) {
+  result->clear();
+  string16 utf16;
+  if (!CodepageToUTF16(
+      text, charset.c_str(), OnStringConversionError::FAIL, &utf16))
+    return false;
+
+  UErrorCode status = U_ZERO_ERROR;
+  size_t max_length = utf16.length() + 1;
+  string16 normalized_utf16;
+  scoped_array<char16> buffer(new char16[max_length]);
+  int actual_length = unorm_normalize(
+      utf16.c_str(), utf16.length(), UNORM_NFC, 0,
+      buffer.get(), static_cast<int>(max_length), &status);
+  if (!U_SUCCESS(status))
+    return false;
+  normalized_utf16.assign(buffer.get(), actual_length);
+
+  return UTF16ToUTF8(normalized_utf16.data(),
+                     normalized_utf16.length(), result);
+}
+
+}  // namespace base
diff --git a/base/i18n/icu_string_conversions.h b/base/i18n/icu_string_conversions.h
new file mode 100644
index 0000000..31a57df
--- /dev/null
+++ b/base/i18n/icu_string_conversions.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_I18N_ICU_STRING_CONVERSIONS_H_
+#define BASE_I18N_ICU_STRING_CONVERSIONS_H_
+
+#include <string>
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/string16.h"
+
+namespace base {
+
+// Defines the error handling modes of UTF16ToCodepage, CodepageToUTF16,
+// WideToCodepage and CodepageToWide.
+class OnStringConversionError {
+ public:
+  enum Type {
+    // The function will return failure. The output buffer will be empty.
+    FAIL,
+
+    // The offending characters are skipped and the conversion will proceed as
+    // if they did not exist.
+    SKIP,
+
+    // When converting to Unicode, the offending byte sequences are substituted
+    // by Unicode replacement character (U+FFFD). When converting from Unicode,
+    // this is the same as SKIP.
+    SUBSTITUTE,
+  };
+
+ private:
+  OnStringConversionError();
+};
+
+// Names of codepages (charsets) understood by icu.
+BASE_I18N_EXPORT extern const char kCodepageLatin1[];  // a.k.a. ISO 8859-1
+BASE_I18N_EXPORT extern const char kCodepageUTF8[];
+BASE_I18N_EXPORT extern const char kCodepageUTF16BE[];
+BASE_I18N_EXPORT extern const char kCodepageUTF16LE[];
+
+// Converts between UTF-16 strings and the encoding specified.  If the
+// encoding doesn't exist or the encoding fails (when on_error is FAIL),
+// returns false.
+BASE_I18N_EXPORT bool UTF16ToCodepage(const string16& utf16,
+                                      const char* codepage_name,
+                                      OnStringConversionError::Type on_error,
+                                      std::string* encoded);
+BASE_I18N_EXPORT bool CodepageToUTF16(const std::string& encoded,
+                                      const char* codepage_name,
+                                      OnStringConversionError::Type on_error,
+                                      string16* utf16);
+
+// Converts between wide strings and the encoding specified.  If the
+// encoding doesn't exist or the encoding fails (when on_error is FAIL),
+// returns false.
+BASE_I18N_EXPORT bool WideToCodepage(const std::wstring& wide,
+                                     const char* codepage_name,
+                                     OnStringConversionError::Type on_error,
+                                     std::string* encoded);
+BASE_I18N_EXPORT bool CodepageToWide(const std::string& encoded,
+                                     const char* codepage_name,
+                                     OnStringConversionError::Type on_error,
+                                     std::wstring* wide);
+
+// Converts from any codepage to UTF-8 and ensures the resulting UTF-8 is
+// normalized.
+BASE_I18N_EXPORT bool ConvertToUtf8AndNormalize(const std::string& text,
+                                                const std::string& charset,
+                                                std::string* result);
+
+}  // namespace base
+
+#endif  // BASE_I18N_ICU_STRING_CONVERSIONS_H_
diff --git a/base/i18n/icu_string_conversions_unittest.cc b/base/i18n/icu_string_conversions_unittest.cc
new file mode 100644
index 0000000..af2d709
--- /dev/null
+++ b/base/i18n/icu_string_conversions_unittest.cc
@@ -0,0 +1,386 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <math.h>
+#include <stdarg.h>
+
+#include <limits>
+#include <sstream>
+
+#include "base/basictypes.h"
+#include "base/format_macros.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Given a null-terminated string of wchar_t with each wchar_t representing
+// a UTF-16 code unit, returns a string16 made up of wchar_t's in the input.
+// Each wchar_t should be <= 0xFFFF and a non-BMP character (> U+FFFF)
+// should be represented as a surrogate pair (two UTF-16 units)
+// *even* where wchar_t is 32-bit (Linux and Mac).
+//
+// This is to help write tests for functions with string16 params until
+// the C++ 0x UTF-16 literal is well-supported by compilers.
+string16 BuildString16(const wchar_t* s) {
+#if defined(WCHAR_T_IS_UTF16)
+  return string16(s);
+#elif defined(WCHAR_T_IS_UTF32)
+  string16 u16;
+  while (*s != 0) {
+    DCHECK_LE(static_cast<unsigned int>(*s), 0xFFFFu);
+    u16.push_back(*s++);
+  }
+  return u16;
+#endif
+}
+
+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(ICUStringConversionsTest, ConvertCodepageUTF8) {
+  // Make sure WideToCodepage works like WideToUTF8.
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %ls",
+                                    i, kConvertRoundtripCases[i]));
+
+    std::string expected(WideToUTF8(kConvertRoundtripCases[i]));
+    std::string utf8;
+    EXPECT_TRUE(WideToCodepage(kConvertRoundtripCases[i], kCodepageUTF8,
+                               OnStringConversionError::SKIP, &utf8));
+    EXPECT_EQ(expected, utf8);
+  }
+}
+
+// kConverterCodepageCases is not comprehensive. There are a number of cases
+// to add if we really want to have a comprehensive coverage of various
+// codepages and their 'idiosyncrasies'. Currently, the only implementation
+// for CodepageTo* and *ToCodepage uses ICU, which has a very extensive
+// set of tests for the charset conversion. So, we can get away with a
+// relatively small number of cases listed below.
+//
+// Note about |u16_wide| in the following struct.
+// On Windows, the field is always identical to |wide|. On Mac and Linux,
+// it's identical as long as there's no character outside the
+// BMP (<= U+FFFF). When there is, it is different from |wide| and
+// is not a real wide string (UTF-32 string) in that each wchar_t in
+// the string is a UTF-16 code unit zero-extended to be 32-bit
+// even when the code unit belongs to a surrogate pair.
+// For instance, a Unicode string (U+0041 U+010000) is represented as
+// L"\x0041\xD800\xDC00" instead of L"\x0041\x10000".
+// To avoid the clutter, |u16_wide| will be set to NULL
+// if it's identical to |wide| on *all* platforms.
+
+static const struct {
+  const char* codepage_name;
+  const char* encoded;
+  OnStringConversionError::Type on_error;
+  bool success;
+  const wchar_t* wide;
+  const wchar_t* u16_wide;
+} kConvertCodepageCases[] = {
+  // Test a case where the input cannot be decoded, using SKIP, FAIL
+  // and SUBSTITUTE error handling rules. "A7 41" is valid, but "A6" isn't.
+  {"big5",
+   "\xA7\x41\xA6",
+   OnStringConversionError::FAIL,
+   false,
+   L"",
+   NULL},
+  {"big5",
+   "\xA7\x41\xA6",
+   OnStringConversionError::SKIP,
+   true,
+   L"\x4F60",
+   NULL},
+  {"big5",
+   "\xA7\x41\xA6",
+   OnStringConversionError::SUBSTITUTE,
+   true,
+   L"\x4F60\xFFFD",
+   NULL},
+  // Arabic (ISO-8859)
+  {"iso-8859-6",
+   "\xC7\xEE\xE4\xD3\xF1\xEE\xE4\xC7\xE5\xEF" " "
+   "\xD9\xEE\xE4\xEE\xEA\xF2\xE3\xEF\xE5\xF2",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0627\x064E\x0644\x0633\x0651\x064E\x0644\x0627\x0645\x064F" L" "
+   L"\x0639\x064E\x0644\x064E\x064A\x0652\x0643\x064F\x0645\x0652",
+   NULL},
+  // Chinese Simplified (GB2312)
+  {"gb2312",
+   "\xC4\xE3\xBA\xC3",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x4F60\x597D",
+   NULL},
+  // Chinese (GB18030) : 4 byte sequences mapped to BMP characters
+  {"gb18030",
+   "\x81\x30\x84\x36\xA1\xA7",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x00A5\x00A8",
+   NULL},
+  // Chinese (GB18030) : A 4 byte sequence mapped to plane 2 (U+20000)
+  {"gb18030",
+   "\x95\x32\x82\x36\xD2\xBB",
+   OnStringConversionError::FAIL,
+   true,
+#if defined(WCHAR_T_IS_UTF16)
+   L"\xD840\xDC00\x4E00",
+#elif defined(WCHAR_T_IS_UTF32)
+   L"\x20000\x4E00",
+#endif
+   L"\xD840\xDC00\x4E00"},
+  {"big5",
+   "\xA7\x41\xA6\x6E",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x4F60\x597D",
+   NULL},
+  // Greek (ISO-8859)
+  {"iso-8859-7",
+   "\xE3\xE5\xE9\xDC" " " "\xF3\xEF\xF5",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5",
+   NULL},
+  // Hebrew (Windows)
+  {"windows-1255",
+   "\xF9\xD1\xC8\xEC\xE5\xC9\xED",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x05E9\x05C1\x05B8\x05DC\x05D5\x05B9\x05DD",
+   NULL},
+  // Hindi Devanagari (ISCII)
+  {"iscii-dev",
+   "\xEF\x42" "\xC6\xCC\xD7\xE8\xB3\xDA\xCF",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0928\x092E\x0938\x094D\x0915\x093E\x0930",
+   NULL},
+  // Korean (EUC)
+  {"euc-kr",
+   "\xBE\xC8\xB3\xE7\xC7\xCF\xBC\xBC\xBF\xE4",
+   OnStringConversionError::FAIL,
+   true,
+   L"\xC548\xB155\xD558\xC138\xC694",
+   NULL},
+  // Japanese (EUC)
+  {"euc-jp",
+   "\xA4\xB3\xA4\xF3\xA4\xCB\xA4\xC1\xA4\xCF\xB0\xEC\x8F\xB0\xA1\x8E\xA6",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00\x4E02\xFF66",
+   NULL},
+  // Japanese (ISO-2022)
+  {"iso-2022-jp",
+   "\x1B$B" "\x24\x33\x24\x73\x24\x4B\x24\x41\x24\x4F\x30\x6C" "\x1B(B"
+   "ab" "\x1B(J" "\x5C\x7E#$" "\x1B(B",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00" L"ab\x00A5\x203E#$",
+   NULL},
+  // Japanese (Shift-JIS)
+  {"sjis",
+   "\x82\xB1\x82\xF1\x82\xC9\x82\xBF\x82\xCD\x88\xEA\xA6",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00\xFF66",
+   NULL},
+  // Russian (KOI8)
+  {"koi8-r",
+   "\xDA\xC4\xD2\xC1\xD7\xD3\xD4\xD7\xD5\xCA\xD4\xC5",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0437\x0434\x0440\x0430\x0432\x0441\x0442\x0432"
+   L"\x0443\x0439\x0442\x0435",
+   NULL},
+  // Thai (windows-874)
+  {"windows-874",
+   "\xCA\xC7\xD1\xCA\xB4\xD5" "\xA4\xC3\xD1\xBA",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0E2A\x0E27\x0E31\x0E2A\x0E14\x0E35"
+   L"\x0E04\x0E23\x0e31\x0E1A",
+   NULL},
+  // Empty text
+  {"iscii-dev",
+   "",
+   OnStringConversionError::FAIL,
+   true,
+   L"",
+   NULL},
+};
+
+TEST(ICUStringConversionsTest, ConvertBetweenCodepageAndWide) {
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kConvertCodepageCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf(
+                     "Test[%" PRIuS "]: <encoded: %s> <codepage: %s>", i,
+                     kConvertCodepageCases[i].encoded,
+                     kConvertCodepageCases[i].codepage_name));
+
+    std::wstring wide;
+    bool success = CodepageToWide(kConvertCodepageCases[i].encoded,
+                                  kConvertCodepageCases[i].codepage_name,
+                                  kConvertCodepageCases[i].on_error,
+                                  &wide);
+    EXPECT_EQ(kConvertCodepageCases[i].success, success);
+    EXPECT_EQ(kConvertCodepageCases[i].wide, wide);
+
+    // When decoding was successful and nothing was skipped, we also check the
+    // reverse conversion. Not all conversions are round-trippable, but
+    // kConverterCodepageCases does not have any one-way conversion at the
+    // moment.
+    if (success &&
+        kConvertCodepageCases[i].on_error ==
+            OnStringConversionError::FAIL) {
+      std::string encoded;
+      success = WideToCodepage(wide, kConvertCodepageCases[i].codepage_name,
+                               kConvertCodepageCases[i].on_error, &encoded);
+      EXPECT_EQ(kConvertCodepageCases[i].success, success);
+      EXPECT_EQ(kConvertCodepageCases[i].encoded, encoded);
+    }
+  }
+
+  // The above cases handled codepage->wide errors, but not wide->codepage.
+  // Test that here.
+  std::string encoded("Temp data");  // Make sure the string gets cleared.
+
+  // First test going to an encoding that can not represent that character.
+  EXPECT_FALSE(WideToCodepage(L"Chinese\xff27", "iso-8859-1",
+                              OnStringConversionError::FAIL, &encoded));
+  EXPECT_TRUE(encoded.empty());
+  EXPECT_TRUE(WideToCodepage(L"Chinese\xff27", "iso-8859-1",
+                             OnStringConversionError::SKIP, &encoded));
+  EXPECT_STREQ("Chinese", encoded.c_str());
+  // From Unicode, SUBSTITUTE is the same as SKIP for now.
+  EXPECT_TRUE(WideToCodepage(L"Chinese\xff27", "iso-8859-1",
+                             OnStringConversionError::SUBSTITUTE,
+                             &encoded));
+  EXPECT_STREQ("Chinese", encoded.c_str());
+
+#if defined(WCHAR_T_IS_UTF16)
+  // When we're in UTF-16 mode, test an invalid UTF-16 character in the input.
+  EXPECT_FALSE(WideToCodepage(L"a\xd800z", "iso-8859-1",
+                              OnStringConversionError::FAIL, &encoded));
+  EXPECT_TRUE(encoded.empty());
+  EXPECT_TRUE(WideToCodepage(L"a\xd800z", "iso-8859-1",
+                             OnStringConversionError::SKIP, &encoded));
+  EXPECT_STREQ("az", encoded.c_str());
+#endif  // WCHAR_T_IS_UTF16
+
+  // Invalid characters should fail.
+  EXPECT_TRUE(WideToCodepage(L"a\xffffz", "iso-8859-1",
+                             OnStringConversionError::SKIP, &encoded));
+  EXPECT_STREQ("az", encoded.c_str());
+
+  // Invalid codepages should fail.
+  EXPECT_FALSE(WideToCodepage(L"Hello, world", "awesome-8571-2",
+                              OnStringConversionError::SKIP, &encoded));
+}
+
+TEST(ICUStringConversionsTest, ConvertBetweenCodepageAndUTF16) {
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kConvertCodepageCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf(
+                     "Test[%" PRIuS "]: <encoded: %s> <codepage: %s>", i,
+                     kConvertCodepageCases[i].encoded,
+                     kConvertCodepageCases[i].codepage_name));
+
+    string16 utf16;
+    bool success = CodepageToUTF16(kConvertCodepageCases[i].encoded,
+                                   kConvertCodepageCases[i].codepage_name,
+                                   kConvertCodepageCases[i].on_error,
+                                   &utf16);
+    string16 utf16_expected;
+    if (kConvertCodepageCases[i].u16_wide == NULL)
+      utf16_expected = BuildString16(kConvertCodepageCases[i].wide);
+    else
+      utf16_expected = BuildString16(kConvertCodepageCases[i].u16_wide);
+    EXPECT_EQ(kConvertCodepageCases[i].success, success);
+    EXPECT_EQ(utf16_expected, utf16);
+
+    // When decoding was successful and nothing was skipped, we also check the
+    // reverse conversion. See also the corresponding comment in
+    // ConvertBetweenCodepageAndWide.
+    if (success &&
+        kConvertCodepageCases[i].on_error == OnStringConversionError::FAIL) {
+      std::string encoded;
+      success = UTF16ToCodepage(utf16, kConvertCodepageCases[i].codepage_name,
+                                kConvertCodepageCases[i].on_error, &encoded);
+      EXPECT_EQ(kConvertCodepageCases[i].success, success);
+      EXPECT_EQ(kConvertCodepageCases[i].encoded, encoded);
+    }
+  }
+}
+
+static const struct {
+  const char* encoded;
+  const char* codepage_name;
+  bool expected_success;
+  const char* expected_value;
+} kConvertAndNormalizeCases[] = {
+  {"foo-\xe4.html", "iso-8859-1", true, "foo-\xc3\xa4.html"},
+  {"foo-\xe4.html", "iso-8859-7", true, "foo-\xce\xb4.html"},
+  {"foo-\xe4.html", "foo-bar", false, ""},
+  {"foo-\xff.html", "ascii", false, ""},
+  {"foo.html", "ascii", true, "foo.html"},
+  {"foo-a\xcc\x88.html", "utf-8", true, "foo-\xc3\xa4.html"},
+  {"\x95\x32\x82\x36\xD2\xBB", "gb18030", true, "\xF0\xA0\x80\x80\xE4\xB8\x80"},
+  {"\xA7\x41\xA6\x6E", "big5", true, "\xE4\xBD\xA0\xE5\xA5\xBD"},
+  // Windows-1258 does have a combining character at xD2 (which is U+0309).
+  // The sequence of (U+00E2, U+0309) is also encoded as U+1EA9.
+  {"foo\xE2\xD2", "windows-1258", true, "foo\xE1\xBA\xA9"},
+  {"", "iso-8859-1", true, ""},
+};
+TEST(ICUStringConversionsTest, ConvertToUtf8AndNormalize) {
+  std::string result;
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kConvertAndNormalizeCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf(
+                     "Test[%" PRIuS "]: <encoded: %s> <codepage: %s>", i,
+                     kConvertAndNormalizeCases[i].encoded,
+                     kConvertAndNormalizeCases[i].codepage_name));
+
+    bool success = ConvertToUtf8AndNormalize(
+        kConvertAndNormalizeCases[i].encoded,
+        kConvertAndNormalizeCases[i].codepage_name, &result);
+    EXPECT_EQ(kConvertAndNormalizeCases[i].expected_success, success);
+    EXPECT_EQ(kConvertAndNormalizeCases[i].expected_value, result);
+  }
+}
+
+}  // namespace base
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
new file mode 100644
index 0000000..43db690
--- /dev/null
+++ b/base/i18n/icu_util.cc
@@ -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.
+
+#include "base/i18n/icu_util.h"
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include <string>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "unicode/putil.h"
+#include "unicode/udata.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif
+
+#define ICU_UTIL_DATA_FILE   0
+#define ICU_UTIL_DATA_SHARED 1
+#define ICU_UTIL_DATA_STATIC 2
+
+#ifndef ICU_UTIL_DATA_IMPL
+
+#if defined(OS_WIN)
+#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_SHARED
+#elif defined(OS_IOS)
+#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_FILE
+#else
+#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_STATIC
+#endif
+
+#endif  // ICU_UTIL_DATA_IMPL
+
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#define ICU_UTIL_DATA_FILE_NAME "icudt" U_ICU_VERSION_SHORT "l.dat"
+#elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED
+#define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
+#if defined(OS_WIN)
+#define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt.dll"
+#endif
+#endif
+
+namespace icu_util {
+
+bool Initialize() {
+#ifndef NDEBUG
+  // Assert that we are not called more than once.  Even though calling this
+  // function isn't harmful (ICU can handle it), being called twice probably
+  // indicates a programming error.
+  static bool called_once = false;
+  DCHECK(!called_once);
+  called_once = true;
+#endif
+
+#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED)
+  // We expect to find the ICU data module alongside the current module.
+  FilePath data_path;
+  PathService::Get(base::DIR_MODULE, &data_path);
+  data_path = data_path.AppendASCII(ICU_UTIL_DATA_SHARED_MODULE_NAME);
+
+  HMODULE module = LoadLibrary(data_path.value().c_str());
+  if (!module) {
+    DLOG(ERROR) << "Failed to load " << ICU_UTIL_DATA_SHARED_MODULE_NAME;
+    return false;
+  }
+
+  FARPROC addr = GetProcAddress(module, ICU_UTIL_DATA_SYMBOL);
+  if (!addr) {
+    DLOG(ERROR) << ICU_UTIL_DATA_SYMBOL << ": not found in "
+               << ICU_UTIL_DATA_SHARED_MODULE_NAME;
+    return false;
+  }
+
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(reinterpret_cast<void*>(addr), &err);
+  return err == U_ZERO_ERROR;
+#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
+  // Mac/Linux bundle the ICU data in.
+  return true;
+#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
+#if !defined(OS_MACOSX)
+  // For now, expect the data file to be alongside the executable.
+  // This is sufficient while we work on unit tests, but will eventually
+  // likely live in a data directory.
+  FilePath data_path;
+  bool path_ok = PathService::Get(base::DIR_EXE, &data_path);
+  DCHECK(path_ok);
+  u_setDataDirectory(data_path.value().c_str());
+  // Only look for the packaged data file;
+  // the default behavior is to look for individual files.
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setFileAccess(UDATA_ONLY_PACKAGES, &err);
+  return err == U_ZERO_ERROR;
+#else
+  // If the ICU data directory is set, ICU won't actually load the data until
+  // it is needed.  This can fail if the process is sandboxed at that time.
+  // Instead, Mac maps the file in and hands off the data so the sandbox won't
+  // cause any problems.
+
+  // Chrome doesn't normally shut down ICU, so the mapped data shouldn't ever
+  // be released.
+  static file_util::MemoryMappedFile mapped_file;
+  if (!mapped_file.IsValid()) {
+    // Assume it is in the framework bundle's Resources directory.
+    FilePath data_path =
+      base::mac::PathForFrameworkBundleResource(CFSTR(ICU_UTIL_DATA_FILE_NAME));
+    if (data_path.empty()) {
+      DLOG(ERROR) << ICU_UTIL_DATA_FILE_NAME << " not found in bundle";
+      return false;
+    }
+    if (!mapped_file.Initialize(data_path)) {
+      DLOG(ERROR) << "Couldn't mmap " << data_path.value();
+      return false;
+    }
+  }
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
+  return err == U_ZERO_ERROR;
+#endif  // OS check
+#endif
+}
+
+}  // namespace icu_util
diff --git a/base/i18n/icu_util.h b/base/i18n/icu_util.h
new file mode 100644
index 0000000..f6356f1
--- /dev/null
+++ b/base/i18n/icu_util.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_ICU_UTIL_H_
+#define BASE_I18N_ICU_UTIL_H_
+
+#include "base/i18n/base_i18n_export.h"
+
+namespace icu_util {
+
+// Call this function to load ICU's data tables for the current process.  This
+// function should be called before ICU is used.
+BASE_I18N_EXPORT bool Initialize();
+
+}  // namespace icu_util
+
+#endif  // BASE_I18N_ICU_UTIL_H_
diff --git a/base/i18n/icu_util_nacl_win64.cc b/base/i18n/icu_util_nacl_win64.cc
new file mode 100644
index 0000000..6e0bb6b
--- /dev/null
+++ b/base/i18n/icu_util_nacl_win64.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/icu_util.h"
+
+namespace icu_util {
+
+bool Initialize() {
+  return true;
+}
+
+}  // namespace icu_util
diff --git a/base/i18n/number_formatting.cc b/base/i18n/number_formatting.cc
new file mode 100644
index 0000000..35ff08d
--- /dev/null
+++ b/base/i18n/number_formatting.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/number_formatting.h"
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stringprintf.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "unicode/numfmt.h"
+#include "unicode/ustring.h"
+
+namespace base {
+
+namespace {
+
+// A simple wrapper around icu::NumberFormat that allows for resetting it
+// (as LazyInstance does not).
+struct NumberFormatWrapper {
+  NumberFormatWrapper() {
+    Reset();
+  }
+
+  void Reset() {
+    // There's no ICU call to destroy a NumberFormat object other than
+    // operator delete, so use the default Delete, which calls operator delete.
+    // This can cause problems if a different allocator is used by this file
+    // than by ICU.
+    UErrorCode status = U_ZERO_ERROR;
+    number_format.reset(icu::NumberFormat::createInstance(status));
+    DCHECK(U_SUCCESS(status));
+  }
+
+  scoped_ptr<icu::NumberFormat> number_format;
+};
+
+LazyInstance<NumberFormatWrapper> g_number_format_int =
+    LAZY_INSTANCE_INITIALIZER;
+LazyInstance<NumberFormatWrapper> g_number_format_float =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+string16 FormatNumber(int64 number) {
+  icu::NumberFormat* number_format =
+      g_number_format_int.Get().number_format.get();
+
+  if (!number_format) {
+    // As a fallback, just return the raw number in a string.
+    return UTF8ToUTF16(StringPrintf("%" PRId64, number));
+  }
+  icu::UnicodeString ustr;
+  number_format->format(number, ustr);
+
+  return string16(ustr.getBuffer(), static_cast<size_t>(ustr.length()));
+}
+
+string16 FormatDouble(double number, int fractional_digits) {
+  icu::NumberFormat* number_format =
+      g_number_format_float.Get().number_format.get();
+
+  if (!number_format) {
+    // As a fallback, just return the raw number in a string.
+    return UTF8ToUTF16(StringPrintf("%f", number));
+  }
+  number_format->setMaximumFractionDigits(fractional_digits);
+  number_format->setMinimumFractionDigits(fractional_digits);
+  icu::UnicodeString ustr;
+  number_format->format(number, ustr);
+
+  return string16(ustr.getBuffer(), static_cast<size_t>(ustr.length()));
+}
+
+namespace testing {
+
+void ResetFormatters() {
+  g_number_format_int.Get().Reset();
+  g_number_format_float.Get().Reset();
+}
+
+}  // namespace testing
+
+}  // namespace base
diff --git a/base/i18n/number_formatting.h b/base/i18n/number_formatting.h
new file mode 100644
index 0000000..cfc4e12
--- /dev/null
+++ b/base/i18n/number_formatting.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_NUMBER_FORMATTING_H_
+#define BASE_I18N_NUMBER_FORMATTING_H_
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/string16.h"
+
+namespace base {
+
+// Return a number formatted with separators in the user's locale.
+// Ex: FormatNumber(1234567)
+//         => "1,234,567" in English, "1.234.567" in German
+BASE_I18N_EXPORT string16 FormatNumber(int64 number);
+
+// Return a number formatted with separators in the user's locale.
+// Ex: FormatDouble(1234567.8, 1)
+//         => "1,234,567.8" in English, "1.234.567,8" in German
+BASE_I18N_EXPORT string16 FormatDouble(double number, int fractional_digits);
+
+namespace testing {
+
+// Causes cached formatters to be discarded and recreated. Only useful for
+// testing.
+BASE_I18N_EXPORT void ResetFormatters();
+
+}  // namespace testing
+
+}  // namespace base
+
+#endif  // BASE_I18N_NUMBER_FORMATTING_H_
diff --git a/base/i18n/number_formatting_unittest.cc b/base/i18n/number_formatting_unittest.cc
new file mode 100644
index 0000000..c40ab34
--- /dev/null
+++ b/base/i18n/number_formatting_unittest.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "base/i18n/number_formatting.h"
+#include "base/i18n/rtl.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(NumberFormattingTest, FormatNumber) {
+  static const struct {
+    int64 number;
+    const char* expected_english;
+    const char* expected_german;
+  } cases[] = {
+    {0, "0", "0"},
+    {1024, "1,024", "1.024"},
+    {std::numeric_limits<int64>::max(),
+        "9,223,372,036,854,775,807", "9.223.372.036.854.775.807"},
+    {std::numeric_limits<int64>::min(),
+        "-9,223,372,036,854,775,808", "-9.223.372.036.854.775.808"},
+    {-42, "-42", "-42"},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    i18n::SetICUDefaultLocale("en");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_english,
+              UTF16ToUTF8(FormatNumber(cases[i].number)));
+    i18n::SetICUDefaultLocale("de");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_german,
+              UTF16ToUTF8(FormatNumber(cases[i].number)));
+  }
+}
+
+TEST(NumberFormattingTest, FormatDouble) {
+  static const struct {
+    double number;
+    int frac_digits;
+    const char* expected_english;
+    const char* expected_german;
+  } cases[] = {
+    {0.0, 0, "0", "0"},
+#if !defined(OS_ANDROID)
+    // Bionic can't printf negative zero correctly.
+    {-0.0, 4, "-0.0000", "-0,0000"},
+#endif
+    {1024.2, 0, "1,024", "1.024"},
+    {-1024.223, 2, "-1,024.22", "-1.024,22"},
+    {std::numeric_limits<double>::max(), 6,
+        "179,769,313,486,232,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000.000000",
+        "179.769.313.486.232.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000,000000"},
+    {std::numeric_limits<double>::min(), 2, "0.00", "0,00"},
+    {-42.7, 3, "-42.700", "-42,700"},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    i18n::SetICUDefaultLocale("en");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_english,
+              UTF16ToUTF8(FormatDouble(cases[i].number, cases[i].frac_digits)));
+    i18n::SetICUDefaultLocale("de");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_german,
+              UTF16ToUTF8(FormatDouble(cases[i].number, cases[i].frac_digits)));
+  }
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
new file mode 100644
index 0000000..cbbb63f
--- /dev/null
+++ b/base/i18n/rtl.cc
@@ -0,0 +1,349 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/rtl.h"
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/sys_string_conversions.h"
+#include "unicode/coll.h"
+#include "unicode/locid.h"
+#include "unicode/uchar.h"
+#include "unicode/uscript.h"
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+#endif
+
+namespace {
+
+// Extract language, country and variant, but ignore keywords.  For example,
+// en-US, ca@valencia, ca-ES@valencia.
+std::string GetLocaleString(const icu::Locale& locale) {
+  const char* language = locale.getLanguage();
+  const char* country = locale.getCountry();
+  const char* variant = locale.getVariant();
+
+  std::string result =
+      (language != NULL && *language != '\0') ? language : "und";
+
+  if (country != NULL && *country != '\0') {
+    result += '-';
+    result += country;
+  }
+
+  if (variant != NULL && *variant != '\0') {
+    std::string variant_str(variant);
+    StringToLowerASCII(&variant_str);
+    result += '@' + variant_str;
+  }
+
+  return result;
+}
+
+}  // namespace
+
+namespace base {
+namespace i18n {
+
+// Represents the locale-specific ICU text direction.
+static TextDirection g_icu_text_direction = UNKNOWN_DIRECTION;
+
+// Convert the ICU default locale to a string.
+std::string GetConfiguredLocale() {
+  return GetLocaleString(icu::Locale::getDefault());
+}
+
+// Convert the ICU canonicalized locale to a string.
+std::string GetCanonicalLocale(const char* locale) {
+  return GetLocaleString(icu::Locale::createCanonical(locale));
+}
+
+// Convert Chrome locale name to ICU locale name
+std::string ICULocaleName(const std::string& locale_string) {
+  // If not Spanish, just return it.
+  if (locale_string.substr(0, 2) != "es")
+    return locale_string;
+  // Expand es to es-ES.
+  if (LowerCaseEqualsASCII(locale_string, "es"))
+    return "es-ES";
+  // Map es-419 (Latin American Spanish) to es-FOO depending on the system
+  // locale.  If it's es-RR other than es-ES, map to es-RR. Otherwise, map
+  // to es-MX (the most populous in Spanish-speaking Latin America).
+  if (LowerCaseEqualsASCII(locale_string, "es-419")) {
+    const icu::Locale& locale = icu::Locale::getDefault();
+    std::string language = locale.getLanguage();
+    const char* country = locale.getCountry();
+    if (LowerCaseEqualsASCII(language, "es") &&
+      !LowerCaseEqualsASCII(country, "es")) {
+        language += '-';
+        language += country;
+        return language;
+    }
+    return "es-MX";
+  }
+  // Currently, Chrome has only "es" and "es-419", but later we may have
+  // more specific "es-RR".
+  return locale_string;
+}
+
+void SetICUDefaultLocale(const std::string& locale_string) {
+  icu::Locale locale(ICULocaleName(locale_string).c_str());
+  UErrorCode error_code = U_ZERO_ERROR;
+  icu::Locale::setDefault(locale, error_code);
+  // This return value is actually bogus because Locale object is
+  // an ID and setDefault seems to always succeed (regardless of the
+  // presence of actual locale data). However,
+  // it does not hurt to have it as a sanity check.
+  DCHECK(U_SUCCESS(error_code));
+  g_icu_text_direction = UNKNOWN_DIRECTION;
+}
+
+bool IsRTL() {
+#if defined(TOOLKIT_GTK)
+  GtkTextDirection gtk_dir = gtk_widget_get_default_direction();
+  return gtk_dir == GTK_TEXT_DIR_RTL;
+#else
+  return ICUIsRTL();
+#endif
+}
+
+bool ICUIsRTL() {
+  if (g_icu_text_direction == UNKNOWN_DIRECTION) {
+    const icu::Locale& locale = icu::Locale::getDefault();
+    g_icu_text_direction = GetTextDirectionForLocale(locale.getName());
+  }
+  return g_icu_text_direction == RIGHT_TO_LEFT;
+}
+
+TextDirection GetTextDirectionForLocale(const char* locale_name) {
+  UErrorCode status = U_ZERO_ERROR;
+  ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status);
+  DCHECK(U_SUCCESS(status));
+  // Treat anything other than RTL as LTR.
+  return (layout_dir != ULOC_LAYOUT_RTL) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT;
+}
+
+TextDirection GetFirstStrongCharacterDirection(const string16& text) {
+  const UChar* string = text.c_str();
+  size_t length = text.length();
+  size_t position = 0;
+  while (position < length) {
+    UChar32 character;
+    size_t next_position = position;
+    U16_NEXT(string, next_position, length, character);
+
+    // Now that we have the character, we use ICU in order to query for the
+    // appropriate Unicode BiDi character type.
+    int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
+    if ((property == U_RIGHT_TO_LEFT) ||
+        (property == U_RIGHT_TO_LEFT_ARABIC) ||
+        (property == U_RIGHT_TO_LEFT_EMBEDDING) ||
+        (property == U_RIGHT_TO_LEFT_OVERRIDE)) {
+      return RIGHT_TO_LEFT;
+    } else if ((property == U_LEFT_TO_RIGHT) ||
+               (property == U_LEFT_TO_RIGHT_EMBEDDING) ||
+               (property == U_LEFT_TO_RIGHT_OVERRIDE)) {
+      return LEFT_TO_RIGHT;
+    }
+
+    position = next_position;
+  }
+
+  return LEFT_TO_RIGHT;
+}
+
+#if defined(OS_WIN)
+bool AdjustStringForLocaleDirection(string16* text) {
+  if (!IsRTL() || text->empty())
+    return false;
+
+  // Marking the string as LTR if the locale is RTL and the string does not
+  // contain strong RTL characters. Otherwise, mark the string as RTL.
+  bool has_rtl_chars = StringContainsStrongRTLChars(*text);
+  if (!has_rtl_chars)
+    WrapStringWithLTRFormatting(text);
+  else
+    WrapStringWithRTLFormatting(text);
+
+  return true;
+}
+
+bool UnadjustStringForLocaleDirection(string16* text) {
+  if (!IsRTL() || text->empty())
+    return false;
+
+  *text = StripWrappingBidiControlCharacters(*text);
+  return true;
+}
+#else
+bool AdjustStringForLocaleDirection(string16* text) {
+  // On OS X & GTK the directionality of a label is determined by the first
+  // strongly directional character.
+  // However, we want to make sure that in an LTR-language-UI all strings are
+  // left aligned and vice versa.
+  // A problem can arise if we display a string which starts with user input.
+  // User input may be of the opposite directionality to the UI. So the whole
+  // string will be displayed in the opposite directionality, e.g. if we want to
+  // display in an LTR UI [such as US English]:
+  //
+  // EMAN_NOISNETXE is now installed.
+  //
+  // Since EXTENSION_NAME begins with a strong RTL char, the label's
+  // directionality will be set to RTL and the string will be displayed visually
+  // as:
+  //
+  // .is now installed EMAN_NOISNETXE
+  //
+  // In order to solve this issue, we prepend an LRM to the string. An LRM is a
+  // strongly directional LTR char.
+  // We also append an LRM at the end, which ensures that we're in an LTR
+  // context.
+
+  // Unlike Windows, Linux and OS X can correctly display RTL glyphs out of the
+  // box so there is no issue with displaying zero-width bidi control characters
+  // on any system.  Thus no need for the !IsRTL() check here.
+  if (text->empty())
+    return false;
+
+  bool ui_direction_is_rtl = IsRTL();
+
+  bool has_rtl_chars = StringContainsStrongRTLChars(*text);
+  if (!ui_direction_is_rtl && has_rtl_chars) {
+    WrapStringWithRTLFormatting(text);
+    text->insert(0U, 1U, kLeftToRightMark);
+    text->push_back(kLeftToRightMark);
+  } else if (ui_direction_is_rtl && has_rtl_chars) {
+    WrapStringWithRTLFormatting(text);
+    text->insert(0U, 1U, kRightToLeftMark);
+    text->push_back(kRightToLeftMark);
+  } else if (ui_direction_is_rtl) {
+    WrapStringWithLTRFormatting(text);
+    text->insert(0U, 1U, kRightToLeftMark);
+    text->push_back(kRightToLeftMark);
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+bool UnadjustStringForLocaleDirection(string16* text) {
+  if (text->empty())
+    return false;
+
+  size_t begin_index = 0;
+  char16 begin = text->at(begin_index);
+  if (begin == kLeftToRightMark ||
+      begin == kRightToLeftMark) {
+    ++begin_index;
+  }
+
+  size_t end_index = text->length() - 1;
+  char16 end = text->at(end_index);
+  if (end == kLeftToRightMark ||
+      end == kRightToLeftMark) {
+    --end_index;
+  }
+
+  string16 unmarked_text =
+      text->substr(begin_index, end_index - begin_index + 1);
+  *text = StripWrappingBidiControlCharacters(unmarked_text);
+  return true;
+}
+
+#endif  // !OS_WIN
+
+bool StringContainsStrongRTLChars(const string16& text) {
+  const UChar* string = text.c_str();
+  size_t length = text.length();
+  size_t position = 0;
+  while (position < length) {
+    UChar32 character;
+    size_t next_position = position;
+    U16_NEXT(string, next_position, length, character);
+
+    // Now that we have the character, we use ICU in order to query for the
+    // appropriate Unicode BiDi character type.
+    int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
+    if ((property == U_RIGHT_TO_LEFT) || (property == U_RIGHT_TO_LEFT_ARABIC))
+      return true;
+
+    position = next_position;
+  }
+
+  return false;
+}
+
+void WrapStringWithLTRFormatting(string16* text) {
+  if (text->empty())
+    return;
+
+  // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
+  text->insert(0U, 1U, kLeftToRightEmbeddingMark);
+
+  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+  text->push_back(kPopDirectionalFormatting);
+}
+
+void WrapStringWithRTLFormatting(string16* text) {
+  if (text->empty())
+    return;
+
+  // Inserting an RLE (Right-To-Left Embedding) mark as the first character.
+  text->insert(0U, 1U, kRightToLeftEmbeddingMark);
+
+  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+  text->push_back(kPopDirectionalFormatting);
+}
+
+void WrapPathWithLTRFormatting(const FilePath& path,
+                               string16* rtl_safe_path) {
+  // Wrap the overall path with LRE-PDF pair which essentialy marks the
+  // string as a Left-To-Right string.
+  // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
+  rtl_safe_path->push_back(kLeftToRightEmbeddingMark);
+#if defined(OS_MACOSX)
+    rtl_safe_path->append(UTF8ToUTF16(path.value()));
+#elif defined(OS_WIN)
+    rtl_safe_path->append(path.value());
+#else  // defined(OS_POSIX) && !defined(OS_MACOSX)
+    std::wstring wide_path = base::SysNativeMBToWide(path.value());
+    rtl_safe_path->append(WideToUTF16(wide_path));
+#endif
+  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+  rtl_safe_path->push_back(kPopDirectionalFormatting);
+}
+
+string16 GetDisplayStringInLTRDirectionality(const string16& text) {
+  // Always wrap the string in RTL UI (it may be appended to RTL string).
+  // Also wrap strings with an RTL first strong character direction in LTR UI.
+  if (IsRTL() || GetFirstStrongCharacterDirection(text) == RIGHT_TO_LEFT) {
+    string16 text_mutable(text);
+    WrapStringWithLTRFormatting(&text_mutable);
+    return text_mutable;
+  }
+  return text;
+}
+
+string16 StripWrappingBidiControlCharacters(const string16& text) {
+  if (text.empty())
+    return text;
+  size_t begin_index = 0;
+  char16 begin = text[begin_index];
+  if (begin == kLeftToRightEmbeddingMark ||
+      begin == kRightToLeftEmbeddingMark ||
+      begin == kLeftToRightOverride ||
+      begin == kRightToLeftOverride)
+    ++begin_index;
+  size_t end_index = text.length() - 1;
+  if (text[end_index] == kPopDirectionalFormatting)
+    --end_index;
+  return text.substr(begin_index, end_index - begin_index + 1);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
new file mode 100644
index 0000000..202a126
--- /dev/null
+++ b/base/i18n/rtl.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_I18N_RTL_H_
+#define BASE_I18N_RTL_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/string16.h"
+#include "build/build_config.h"
+
+class FilePath;
+
+namespace base {
+namespace i18n {
+
+const char16 kRightToLeftMark = 0x200F;
+const char16 kLeftToRightMark = 0x200E;
+const char16 kLeftToRightEmbeddingMark = 0x202A;
+const char16 kRightToLeftEmbeddingMark = 0x202B;
+const char16 kPopDirectionalFormatting = 0x202C;
+const char16 kLeftToRightOverride = 0x202D;
+const char16 kRightToLeftOverride = 0x202E;
+
+enum TextDirection {
+  UNKNOWN_DIRECTION,
+  RIGHT_TO_LEFT,
+  LEFT_TO_RIGHT,
+};
+
+// Get the locale that the currently running process has been configured to use.
+// The return value is of the form language[-country] (e.g., en-US) where the
+// language is the 2 or 3 letter code from ISO-639.
+BASE_I18N_EXPORT std::string GetConfiguredLocale();
+
+// Canonicalize a string (eg. a POSIX locale string) to a Chrome locale name.
+BASE_I18N_EXPORT std::string GetCanonicalLocale(const char* locale);
+
+// Sets the default locale of ICU.
+// Once the application locale of Chrome in GetApplicationLocale is determined,
+// the default locale of ICU need to be changed to match the application locale
+// so that ICU functions work correctly in a locale-dependent manner.
+// This is handy in that we don't have to call GetApplicationLocale()
+// everytime we call locale-dependent ICU APIs as long as we make sure
+// that this is called before any locale-dependent API is called.
+BASE_I18N_EXPORT void SetICUDefaultLocale(const std::string& locale_string);
+
+// Returns true if the application text direction is right-to-left.
+BASE_I18N_EXPORT bool IsRTL();
+
+// Returns whether the text direction for the default ICU locale is RTL.  This
+// assumes that SetICUDefaultLocale has been called to set the default locale to
+// the UI locale of Chrome.
+// NOTE: Generally, you should call IsRTL() instead of this.
+BASE_I18N_EXPORT bool ICUIsRTL();
+
+// Returns the text direction for |locale_name|.
+BASE_I18N_EXPORT TextDirection GetTextDirectionForLocale(
+    const char* locale_name);
+
+// Given the string in |text|, returns the directionality of the first
+// character with strong directionality in the string. If no character in the
+// text has strong directionality, LEFT_TO_RIGHT is returned. The Bidi
+// character types L, LRE, LRO, R, AL, RLE, and RLO are considered as strong
+// directionality characters. Please refer to http://unicode.org/reports/tr9/
+// for more information.
+BASE_I18N_EXPORT TextDirection GetFirstStrongCharacterDirection(
+    const string16& text);
+
+// Given the string in |text|, this function modifies the string in place with
+// the appropriate Unicode formatting marks that mark the string direction
+// (either left-to-right or right-to-left). The function checks both the current
+// locale and the contents of the string in order to determine the direction of
+// the returned string. The function returns true if the string in |text| was
+// properly adjusted.
+//
+// Certain LTR strings are not rendered correctly when the context is RTL. For
+// example, the string "Foo!" will appear as "!Foo" if it is rendered as is in
+// an RTL context. Calling this function will make sure the returned localized
+// string is always treated as a right-to-left string. This is done by
+// inserting certain Unicode formatting marks into the returned string.
+//
+// ** Notes about the Windows version of this function:
+// TODO(idana) bug 6806: this function adjusts the string in question only
+// if the current locale is right-to-left. The function does not take care of
+// the opposite case (an RTL string displayed in an LTR context) since
+// adjusting the string involves inserting Unicode formatting characters that
+// Windows does not handle well unless right-to-left language support is
+// installed. Since the English version of Windows doesn't have right-to-left
+// language support installed by default, inserting the direction Unicode mark
+// results in Windows displaying squares.
+BASE_I18N_EXPORT bool AdjustStringForLocaleDirection(string16* text);
+
+// Undoes the actions of the above function (AdjustStringForLocaleDirection).
+BASE_I18N_EXPORT bool UnadjustStringForLocaleDirection(string16* text);
+
+// Returns true if the string contains at least one character with strong right
+// to left directionality; that is, a character with either R or AL Unicode
+// BiDi character type.
+BASE_I18N_EXPORT bool StringContainsStrongRTLChars(const string16& text);
+
+// Wraps a string with an LRE-PDF pair which essentialy marks the string as a
+// Left-To-Right string. Doing this is useful in order to make sure LTR
+// strings are rendered properly in an RTL context.
+BASE_I18N_EXPORT void WrapStringWithLTRFormatting(string16* text);
+
+// Wraps a string with an RLE-PDF pair which essentialy marks the string as a
+// Right-To-Left string. Doing this is useful in order to make sure RTL
+// strings are rendered properly in an LTR context.
+BASE_I18N_EXPORT void WrapStringWithRTLFormatting(string16* text);
+
+// Wraps file path to get it to display correctly in RTL UI. All filepaths
+// should be passed through this function before display in UI for RTL locales.
+BASE_I18N_EXPORT void WrapPathWithLTRFormatting(const FilePath& path,
+                                                string16* rtl_safe_path);
+
+// Return the string in |text| wrapped with LRE (Left-To-Right Embedding) and
+// PDF (Pop Directional Formatting) marks, if needed for UI display purposes.
+BASE_I18N_EXPORT string16 GetDisplayStringInLTRDirectionality(
+    const string16& text) WARN_UNUSED_RESULT;
+
+// Strip the beginning (U+202A..U+202B, U+202D..U+202E) and/or ending (U+202C)
+// explicit bidi control characters from |text|, if there are any. Otherwise,
+// return the text itself. Explicit bidi control characters display and have
+// semantic effect. They can be deleted so they might not always appear in a
+// pair.
+BASE_I18N_EXPORT string16 StripWrappingBidiControlCharacters(
+    const string16& text) WARN_UNUSED_RESULT;
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_RTL_H_
diff --git a/base/i18n/rtl_unittest.cc b/base/i18n/rtl_unittest.cc
new file mode 100644
index 0000000..829b1ab
--- /dev/null
+++ b/base/i18n/rtl_unittest.cc
@@ -0,0 +1,307 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/rtl.h"
+
+#include <algorithm>
+
+#include "base/file_path.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "unicode/usearch.h"
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+#endif
+
+namespace base {
+namespace i18n {
+
+namespace {
+
+// A test utility function to set the application default text direction.
+void SetRTL(bool rtl) {
+  // Override the current locale/direction.
+  SetICUDefaultLocale(rtl ? "he" : "en");
+#if defined(TOOLKIT_GTK)
+  // Do the same for GTK, which does not rely on the ICU default locale.
+  gtk_widget_set_default_direction(rtl ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
+#endif
+  EXPECT_EQ(rtl, IsRTL());
+}
+
+}  // namespace
+
+class RTLTest : public PlatformTest {
+};
+
+TEST_F(RTLTest, GetFirstStrongCharacterDirection) {
+  struct {
+    const wchar_t* text;
+    TextDirection direction;
+  } cases[] = {
+    // Test pure LTR string.
+    { L"foo bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type L.
+    { L"foo \x05d0 bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type R.
+    { L"\x05d0 foo bar", RIGHT_TO_LEFT },
+    // Test bidi string which starts with a character with weak directionality
+    // and in which the first character with strong directionality is a
+    // character with type L.
+    { L"!foo \x05d0 bar", LEFT_TO_RIGHT },
+    // Test bidi string which starts with a character with weak directionality
+    // and in which the first character with strong directionality is a
+    // character with type R.
+    { L",\x05d0 foo bar", RIGHT_TO_LEFT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type LRE.
+    { L"\x202a \x05d0 foo  bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type LRO.
+    { L"\x202d \x05d0 foo  bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type RLE.
+    { L"\x202b foo \x05d0 bar", RIGHT_TO_LEFT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type RLO.
+    { L"\x202e foo \x05d0 bar", RIGHT_TO_LEFT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type AL.
+    { L"\x0622 foo \x05d0 bar", RIGHT_TO_LEFT },
+    // Test a string without strong directionality characters.
+    { L",!.{}", LEFT_TO_RIGHT },
+    // Test empty string.
+    { L"", LEFT_TO_RIGHT },
+    // Test characters in non-BMP (e.g. Phoenician letters. Please refer to
+    // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more
+    // information).
+    {
+#if defined(WCHAR_T_IS_UTF32)
+      L" ! \x10910" L"abc 123",
+#elif defined(WCHAR_T_IS_UTF16)
+      L" ! \xd802\xdd10" L"abc 123",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      RIGHT_TO_LEFT },
+    {
+#if defined(WCHAR_T_IS_UTF32)
+      L" ! \x10401" L"abc 123",
+#elif defined(WCHAR_T_IS_UTF16)
+      L" ! \xd801\xdc01" L"abc 123",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      LEFT_TO_RIGHT },
+   };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i)
+    EXPECT_EQ(cases[i].direction,
+              GetFirstStrongCharacterDirection(WideToUTF16(cases[i].text)));
+}
+
+TEST_F(RTLTest, WrapPathWithLTRFormatting) {
+  const wchar_t* cases[] = {
+    // Test common path, such as "c:\foo\bar".
+    L"c:/foo/bar",
+    // Test path with file name, such as "c:\foo\bar\test.jpg".
+    L"c:/foo/bar/test.jpg",
+    // Test path ending with punctuation, such as "c:\(foo)\bar.".
+    L"c:/(foo)/bar.",
+    // Test path ending with separator, such as "c:\foo\bar\".
+    L"c:/foo/bar/",
+    // Test path with RTL character.
+    L"c:/\x05d0",
+    // Test path with 2 level RTL directory names.
+    L"c:/\x05d0/\x0622",
+    // Test path with mixed RTL/LTR directory names and ending with punctuation.
+    L"c:/\x05d0/\x0622/(foo)/b.a.r.",
+    // Test path without driver name, such as "/foo/bar/test/jpg".
+    L"/foo/bar/test.jpg",
+    // Test path start with current directory, such as "./foo".
+    L"./foo",
+    // Test path start with parent directory, such as "../foo/bar.jpg".
+    L"../foo/bar.jpg",
+    // Test absolute path, such as "//foo/bar.jpg".
+    L"//foo/bar.jpg",
+    // Test path with mixed RTL/LTR directory names.
+    L"c:/foo/\x05d0/\x0622/\x05d1.jpg",
+    // Test empty path.
+    L""
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath path;
+#if defined(OS_WIN)
+    std::wstring win_path(cases[i]);
+    std::replace(win_path.begin(), win_path.end(), '/', '\\');
+    path = FilePath(win_path);
+    std::wstring wrapped_expected =
+        std::wstring(L"\x202a") + win_path + L"\x202c";
+#else
+    path = FilePath(base::SysWideToNativeMB(cases[i]));
+    std::wstring wrapped_expected =
+        std::wstring(L"\x202a") + cases[i] + L"\x202c";
+#endif
+    string16 localized_file_path_string;
+    WrapPathWithLTRFormatting(path, &localized_file_path_string);
+
+    std::wstring wrapped_actual = UTF16ToWide(localized_file_path_string);
+    EXPECT_EQ(wrapped_expected, wrapped_actual);
+  }
+}
+
+TEST_F(RTLTest, WrapString) {
+  const wchar_t* cases[] = {
+    L" . ",
+    L"abc",
+    L"a"L"\x5d0\x5d1",
+    L"a"L"\x5d1"L"b",
+    L"\x5d0\x5d1\x5d2",
+    L"\x5d0\x5d1"L"a",
+    L"\x5d0"L"a"L"\x5d1",
+  };
+
+  const bool was_rtl = IsRTL();
+
+  for (size_t i = 0; i < 2; ++i) {
+    // Toggle the application default text direction (to try each direction).
+    SetRTL(!IsRTL());
+
+    string16 empty;
+    WrapStringWithLTRFormatting(&empty);
+    EXPECT_TRUE(empty.empty());
+    WrapStringWithRTLFormatting(&empty);
+    EXPECT_TRUE(empty.empty());
+
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+      string16 input = WideToUTF16(cases[i]);
+      string16 ltr_wrap = input;
+      WrapStringWithLTRFormatting(&ltr_wrap);
+      EXPECT_EQ(ltr_wrap[0], kLeftToRightEmbeddingMark);
+      EXPECT_EQ(ltr_wrap.substr(1, ltr_wrap.length() - 2), input);
+      EXPECT_EQ(ltr_wrap[ltr_wrap.length() -1], kPopDirectionalFormatting);
+
+      string16 rtl_wrap = input;
+      WrapStringWithRTLFormatting(&rtl_wrap);
+      EXPECT_EQ(rtl_wrap[0], kRightToLeftEmbeddingMark);
+      EXPECT_EQ(rtl_wrap.substr(1, rtl_wrap.length() - 2), input);
+      EXPECT_EQ(rtl_wrap[rtl_wrap.length() -1], kPopDirectionalFormatting);
+    }
+  }
+
+  EXPECT_EQ(was_rtl, IsRTL());
+}
+
+TEST_F(RTLTest, GetDisplayStringInLTRDirectionality) {
+  struct {
+    const wchar_t* path;
+    bool wrap_ltr;
+    bool wrap_rtl;
+  } cases[] = {
+    { L"test",                   false, true },
+    { L"test.html",              false, true },
+    { L"\x05d0\x05d1\x05d2",     true,  true },
+    { L"\x05d0\x05d1\x05d2.txt", true,  true },
+    { L"\x05d0"L"abc",           true,  true },
+    { L"\x05d0"L"abc.txt",       true,  true },
+    { L"abc\x05d0\x05d1",        false, true },
+    { L"abc\x05d0\x05d1.jpg",    false, true },
+  };
+
+  const bool was_rtl = IsRTL();
+
+  for (size_t i = 0; i < 2; ++i) {
+    // Toggle the application default text direction (to try each direction).
+    SetRTL(!IsRTL());
+    for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+      string16 input = WideToUTF16(cases[i].path);
+      string16 output = GetDisplayStringInLTRDirectionality(input);
+      // Test the expected wrapping behavior for the current UI directionality.
+      if (IsRTL() ? cases[i].wrap_rtl : cases[i].wrap_ltr)
+        EXPECT_NE(output, input);
+      else
+        EXPECT_EQ(output, input);
+    }
+  }
+
+  EXPECT_EQ(was_rtl, IsRTL());
+}
+
+TEST_F(RTLTest, GetTextDirection) {
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar_EG"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he_IL"));
+  // iw is an obsolete code for Hebrew.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("iw"));
+  // Although we're not yet localized to Farsi and Urdu, we
+  // do have the text layout direction information for them.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("fa"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ur"));
+#if 0
+  // Enable these when we include the minimal locale data for Azerbaijani
+  // written in Arabic and Dhivehi. At the moment, our copy of
+  // ICU data does not have entries for them.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("az_Arab"));
+  // Dhivehi that uses Thaana script.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("dv"));
+#endif
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("en"));
+  // Chinese in China with '-'.
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("zh-CN"));
+  // Filipino : 3-letter code
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("fil"));
+  // Russian
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ru"));
+  // Japanese that uses multiple scripts
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ja"));
+}
+
+TEST_F(RTLTest, UnadjustStringForLocaleDirection) {
+  // These test strings are borrowed from WrapPathWithLTRFormatting
+  const wchar_t* cases[] = {
+    L"foo bar",
+    L"foo \x05d0 bar",
+    L"\x05d0 foo bar",
+    L"!foo \x05d0 bar",
+    L",\x05d0 foo bar",
+    L"\x202a \x05d0 foo  bar",
+    L"\x202d \x05d0 foo  bar",
+    L"\x202b foo \x05d0 bar",
+    L"\x202e foo \x05d0 bar",
+    L"\x0622 foo \x05d0 bar",
+  };
+
+  const bool was_rtl = IsRTL();
+
+  for (size_t i = 0; i < 2; ++i) {
+    // Toggle the application default text direction (to try each direction).
+    SetRTL(!IsRTL());
+
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+      string16 test_case = WideToUTF16(cases[i]);
+      string16 adjusted_string = test_case;
+
+      if (!AdjustStringForLocaleDirection(&adjusted_string))
+        continue;
+
+      EXPECT_NE(test_case, adjusted_string);
+      EXPECT_TRUE(UnadjustStringForLocaleDirection(&adjusted_string));
+      EXPECT_EQ(test_case, adjusted_string) << " for test case [" << test_case
+                                            << "] with IsRTL() == " << IsRTL();
+    }
+  }
+
+  EXPECT_EQ(was_rtl, IsRTL());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/string_search.cc b/base/i18n/string_search.cc
new file mode 100644
index 0000000..9dc84ca
--- /dev/null
+++ b/base/i18n/string_search.cc
@@ -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.
+
+#include "base/i18n/string_search.h"
+#include "base/logging.h"
+
+#include "unicode/usearch.h"
+
+namespace {
+
+bool CollationSensitiveStringSearch(const string16& find_this,
+                                    const string16& in_this,
+                                    UCollationStrength strength,
+                                    size_t* match_index,
+                                    size_t* match_length) {
+  UErrorCode status = U_ZERO_ERROR;
+
+  UStringSearch* search = usearch_open(find_this.data(), -1,
+                                       in_this.data(), -1,
+                                       uloc_getDefault(),
+                                       NULL,  // breakiter
+                                       &status);
+
+  // Default to basic substring search if usearch fails. According to
+  // http://icu-project.org/apiref/icu4c/usearch_8h.html, usearch_open will fail
+  // if either |find_this| or |in_this| are empty. In either case basic
+  // substring search will give the correct return value.
+  if (!U_SUCCESS(status)) {
+    size_t index = in_this.find(find_this);
+    if (index == string16::npos) {
+      return false;
+    } else {
+      if (match_index)
+        *match_index = index;
+      if (match_length)
+        *match_length = find_this.size();
+      return true;
+    }
+  }
+
+  UCollator* collator = usearch_getCollator(search);
+  ucol_setStrength(collator, strength);
+  usearch_reset(search);
+
+  int32_t index = usearch_first(search, &status);
+  if (!U_SUCCESS(status) || index == USEARCH_DONE) {
+    usearch_close(search);
+    return false;
+  }
+
+  if (match_index)
+    *match_index = static_cast<size_t>(index);
+  if (match_length)
+    *match_length = static_cast<size_t>(usearch_getMatchedLength(search));
+
+  usearch_close(search);
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+namespace i18n {
+
+bool StringSearchIgnoringCaseAndAccents(const string16& find_this,
+                                        const string16& in_this,
+                                        size_t* match_index,
+                                        size_t* match_length) {
+  return CollationSensitiveStringSearch(find_this,
+                                        in_this,
+                                        UCOL_PRIMARY,
+                                        match_index,
+                                        match_length);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/string_search.h b/base/i18n/string_search.h
new file mode 100644
index 0000000..2069b0f
--- /dev/null
+++ b/base/i18n/string_search.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_STRING_SEARCH_H_
+#define BASE_I18N_STRING_SEARCH_H_
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/string16.h"
+
+namespace base {
+namespace i18n {
+
+// Returns true if |in_this| contains |find_this|. If |match_index| or
+// |match_length| are non-NULL, they are assigned the start position and total
+// length of the match.
+//
+// Only differences between base letters are taken into consideration. Case and
+// accent differences are ignored. Please refer to 'primary level' in
+// http://userguide.icu-project.org/collation/concepts for additional details.
+BASE_I18N_EXPORT
+    bool StringSearchIgnoringCaseAndAccents(const string16& find_this,
+                                            const string16& in_this,
+                                            size_t* match_index,
+                                            size_t* match_length);
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_STRING_SEARCH_H_
diff --git a/base/i18n/string_search_unittest.cc b/base/i18n/string_search_unittest.cc
new file mode 100644
index 0000000..e6ca1c5
--- /dev/null
+++ b/base/i18n/string_search_unittest.cc
@@ -0,0 +1,203 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/i18n/rtl.h"
+#include "base/i18n/string_search.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "unicode/usearch.h"
+
+namespace base {
+namespace i18n {
+
+// Note on setting default locale for testing: The current default locale on
+// the Mac trybot is en_US_POSIX, with which primary-level collation strength
+// string search is case-sensitive, when normally it should be
+// case-insensitive. In other locales (including en_US which English speakers
+// in the U.S. use), this search would be case-insensitive as expected.
+
+TEST(StringSearchTest, ASCII) {
+  std::string default_locale(uloc_getDefault());
+  bool locale_is_posix = (default_locale == "en_US_POSIX");
+  if (locale_is_posix)
+    SetICUDefaultLocale("en_US");
+
+  size_t index = 0;
+  size_t length = 0;
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("hello"), ASCIIToUTF16("hello world"), &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(5U, length);
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("h    e l l o"), ASCIIToUTF16("h   e l l o"),
+      &index, &length));
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("aabaaa"), ASCIIToUTF16("aaabaabaaa"), &index, &length));
+  EXPECT_EQ(4U, index);
+  EXPECT_EQ(6U, length);
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("searching within empty string"), string16(),
+      &index, &length));
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      string16(), ASCIIToUTF16("searching for empty string"), &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(0U, length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("case insensitivity"), ASCIIToUTF16("CaSe InSeNsItIvItY"),
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(18U, length);
+
+  if (locale_is_posix)
+    SetICUDefaultLocale(default_locale.data());
+}
+
+TEST(StringSearchTest, UnicodeLocaleIndependent) {
+  // Base characters
+  const string16 e_base = WideToUTF16(L"e");
+  const string16 E_base = WideToUTF16(L"E");
+  const string16 a_base = WideToUTF16(L"a");
+
+  // Composed characters
+  const string16 e_with_acute_accent = WideToUTF16(L"\u00e9");
+  const string16 E_with_acute_accent = WideToUTF16(L"\u00c9");
+  const string16 e_with_grave_accent = WideToUTF16(L"\u00e8");
+  const string16 E_with_grave_accent = WideToUTF16(L"\u00c8");
+  const string16 a_with_acute_accent = WideToUTF16(L"\u00e1");
+
+  // Decomposed characters
+  const string16 e_with_acute_combining_mark = WideToUTF16(L"e\u0301");
+  const string16 E_with_acute_combining_mark = WideToUTF16(L"E\u0301");
+  const string16 e_with_grave_combining_mark = WideToUTF16(L"e\u0300");
+  const string16 E_with_grave_combining_mark = WideToUTF16(L"E\u0300");
+  const string16 a_with_acute_combining_mark = WideToUTF16(L"a\u0301");
+
+  std::string default_locale(uloc_getDefault());
+  bool locale_is_posix = (default_locale == "en_US_POSIX");
+  if (locale_is_posix)
+    SetICUDefaultLocale("en_US");
+
+  size_t index = 0;
+  size_t length = 0;
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_base, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_accent, e_base, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_base.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_base, e_with_acute_combining_mark, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_base, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_base.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_with_acute_accent,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_accent, e_with_acute_combining_mark,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_with_grave_combining_mark,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_grave_combining_mark, e_with_acute_combining_mark,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_with_grave_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_grave_accent, e_with_acute_combining_mark, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_acute_accent, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_grave_accent, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_acute_combining_mark, e_with_grave_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_grave_combining_mark, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_base, e_with_grave_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_accent.size(), length);
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      a_with_acute_accent, e_with_acute_accent, &index, &length));
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      a_with_acute_combining_mark, e_with_acute_combining_mark,
+      &index, &length));
+
+  if (locale_is_posix)
+    SetICUDefaultLocale(default_locale.data());
+}
+
+TEST(StringSearchTest, UnicodeLocaleDependent) {
+  // Base characters
+  const string16 a_base = WideToUTF16(L"a");
+
+  // Composed characters
+  const string16 a_with_ring = WideToUTF16(L"\u00e5");
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      a_base, a_with_ring, NULL, NULL));
+
+  const char* default_locale = uloc_getDefault();
+  SetICUDefaultLocale("da");
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      a_base, a_with_ring, NULL, NULL));
+
+  SetICUDefaultLocale(default_locale);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc
new file mode 100644
index 0000000..9906dba
--- /dev/null
+++ b/base/i18n/time_formatting.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/time_formatting.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
+#include "base/time.h"
+#include "unicode/datefmt.h"
+#include "unicode/dtptngen.h"
+#include "unicode/smpdtfmt.h"
+
+using base::Time;
+
+namespace {
+
+string16 TimeFormat(const icu::DateFormat* formatter,
+                    const Time& time) {
+  DCHECK(formatter);
+  icu::UnicodeString date_string;
+
+  formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
+  return string16(date_string.getBuffer(),
+                  static_cast<size_t>(date_string.length()));
+}
+
+string16 TimeFormatWithoutAmPm(const icu::DateFormat* formatter,
+                               const Time& time) {
+  DCHECK(formatter);
+  icu::UnicodeString time_string;
+
+  icu::FieldPosition ampm_field(icu::DateFormat::kAmPmField);
+  formatter->format(
+      static_cast<UDate>(time.ToDoubleT() * 1000), time_string, ampm_field);
+  int ampm_length = ampm_field.getEndIndex() - ampm_field.getBeginIndex();
+  if (ampm_length) {
+    int begin = ampm_field.getBeginIndex();
+    // Doesn't include any spacing before the field.
+    if (begin)
+      begin--;
+    time_string.removeBetween(begin, ampm_field.getEndIndex());
+  }
+  return string16(time_string.getBuffer(),
+                  static_cast<size_t>(time_string.length()));
+}
+
+}  // namespace
+
+namespace base {
+
+string16 TimeFormatTimeOfDay(const Time& time) {
+  // We can omit the locale parameter because the default should match
+  // Chrome's application locale.
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createTimeInstance(icu::DateFormat::kShort));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatTimeOfDayWithHourClockType(const Time& time,
+                                              HourClockType type,
+                                              AmPmClockType ampm) {
+  // Just redirect to the normal function if the default type matches the
+  // given type.
+  HourClockType default_type = GetHourClockType();
+  if (default_type == type && (type == k24HourClock || ampm == kKeepAmPm)) {
+    return TimeFormatTimeOfDay(time);
+  }
+
+  // Generate a locale-dependent format pattern. The generator will take
+  // care of locale-dependent formatting issues like which separator to
+  // use (some locales use '.' instead of ':'), and where to put the am/pm
+  // marker.
+  UErrorCode status = U_ZERO_ERROR;
+  scoped_ptr<icu::DateTimePatternGenerator> generator(
+      icu::DateTimePatternGenerator::createInstance(status));
+  DCHECK(U_SUCCESS(status));
+  const char* base_pattern = (type == k12HourClock ? "ahm" : "Hm");
+  icu::UnicodeString generated_pattern =
+      generator->getBestPattern(icu::UnicodeString(base_pattern), status);
+  DCHECK(U_SUCCESS(status));
+
+  // Then, format the time using the generated pattern.
+  icu::SimpleDateFormat formatter(generated_pattern, status);
+  DCHECK(U_SUCCESS(status));
+  if (ampm == kKeepAmPm) {
+    return TimeFormat(&formatter, time);
+  } else {
+    return TimeFormatWithoutAmPm(&formatter, time);
+  }
+}
+
+string16 TimeFormatShortDate(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateInstance(icu::DateFormat::kMedium));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatShortDateNumeric(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateInstance(icu::DateFormat::kShort));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatShortDateAndTime(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateTimeInstance(icu::DateFormat::kShort));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatFriendlyDateAndTime(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateTimeInstance(icu::DateFormat::kFull));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatFriendlyDate(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(icu::DateFormat::createDateInstance(
+      icu::DateFormat::kFull));
+  return TimeFormat(formatter.get(), time);
+}
+
+HourClockType GetHourClockType() {
+  // TODO(satorux,jshin): Rework this with ures_getByKeyWithFallback()
+  // once it becomes public. The short time format can be found at
+  // "calendar/gregorian/DateTimePatterns/3" in the resources.
+  scoped_ptr<icu::SimpleDateFormat> formatter(
+      static_cast<icu::SimpleDateFormat*>(
+          icu::DateFormat::createTimeInstance(icu::DateFormat::kShort)));
+  // Retrieve the short time format.
+  icu::UnicodeString pattern_unicode;
+  formatter->toPattern(pattern_unicode);
+
+  // Determine what hour clock type the current locale uses, by checking
+  // "a" (am/pm marker) in the short time format. This is reliable as "a"
+  // is used by all of 12-hour clock formats, but not any of 24-hour clock
+  // formats, as shown below.
+  //
+  // % grep -A4 DateTimePatterns third_party/icu/source/data/locales/*.txt |
+  //   grep -B1 -- -- |grep -v -- '--' |
+  //   perl -nle 'print $1 if /^\S+\s+"(.*)"/' |sort -u
+  //
+  // H.mm
+  // H:mm
+  // HH.mm
+  // HH:mm
+  // a h:mm
+  // ah:mm
+  // ahh:mm
+  // h-mm a
+  // h:mm a
+  // hh:mm a
+  //
+  // See http://userguide.icu-project.org/formatparse/datetime for details
+  // about the date/time format syntax.
+  if (pattern_unicode.indexOf('a') == -1) {
+    return k24HourClock;
+  } else {
+    return k12HourClock;
+  }
+}
+
+}  // namespace base
diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h
new file mode 100644
index 0000000..91b79c6
--- /dev/null
+++ b/base/i18n/time_formatting.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.
+
+// Basic time formatting methods.  These methods use the current locale
+// formatting for displaying the time.
+
+#ifndef BASE_I18N_TIME_FORMATTING_H_
+#define BASE_I18N_TIME_FORMATTING_H_
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/string16.h"
+
+namespace base {
+
+class Time;
+
+// Argument type used to specify the hour clock type.
+enum HourClockType {
+  k12HourClock,  // Uses 1-12. e.g., "3:07 PM"
+  k24HourClock,  // Uses 0-23. e.g., "15:07"
+};
+
+// Argument type used to specify whether or not to include AM/PM sign.
+enum AmPmClockType {
+  kDropAmPm,  // Drops AM/PM sign. e.g., "3:07"
+  kKeepAmPm,  // Keeps AM/PM sign. e.g., "3:07 PM"
+};
+
+// Returns the time of day, e.g., "3:07 PM".
+BASE_I18N_EXPORT string16 TimeFormatTimeOfDay(const Time& time);
+
+// Returns the time of day in the specified hour clock type. e.g.
+// "3:07 PM" (type == k12HourClock, ampm == kKeepAmPm).
+// "3:07"    (type == k12HourClock, ampm == kDropAmPm).
+// "15:07"   (type == k24HourClock).
+BASE_I18N_EXPORT string16 TimeFormatTimeOfDayWithHourClockType(
+    const Time& time,
+    HourClockType type,
+    AmPmClockType ampm);
+
+// Returns a shortened date, e.g. "Nov 7, 2007"
+BASE_I18N_EXPORT string16 TimeFormatShortDate(const Time& time);
+
+// Returns a numeric date such as 12/13/52.
+BASE_I18N_EXPORT string16 TimeFormatShortDateNumeric(const Time& time);
+
+// Returns a numeric date and time such as "12/13/52 2:44:30 PM".
+BASE_I18N_EXPORT string16 TimeFormatShortDateAndTime(const Time& time);
+
+// Formats a time in a friendly sentence format, e.g.
+// "Monday, March 6, 2008 2:44:30 PM".
+BASE_I18N_EXPORT string16 TimeFormatFriendlyDateAndTime(const Time& time);
+
+// Formats a time in a friendly sentence format, e.g.
+// "Monday, March 6, 2008".
+BASE_I18N_EXPORT string16 TimeFormatFriendlyDate(const Time& time);
+
+// Gets the hour clock type of the current locale. e.g.
+// k12HourClock (en-US).
+// k24HourClock (en-GB).
+BASE_I18N_EXPORT HourClockType GetHourClockType();
+
+}  // namespace base
+
+#endif  // BASE_I18N_TIME_FORMATTING_H_
diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc
new file mode 100644
index 0000000..76ffa5d
--- /dev/null
+++ b/base/i18n/time_formatting_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/i18n/time_formatting.h"
+
+#include "base/i18n/rtl.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+const Time::Exploded kTestDateTimeExploded = {
+  2011, 4, 6, 30, // Sat, Apr 30, 2011
+  15, 42, 7, 0    // 15:42:07.000
+};
+
+TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault12h) {
+  // Test for a locale defaulted to 12h clock.
+  // As an instance, we use third_party/icu/source/data/locales/en.txt.
+  i18n::SetICUDefaultLocale("en_US");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+  string16 clock24h(ASCIIToUTF16("15:42"));
+  string16 clock12h_pm(ASCIIToUTF16("3:42 PM"));
+  string16 clock12h(ASCIIToUTF16("3:42"));
+
+  // The default is 12h clock.
+  EXPECT_EQ(clock12h_pm, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(k12HourClock, GetHourClockType());
+  // k{Keep,Drop}AmPm should not affect for 24h clock.
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kDropAmPm));
+  // k{Keep,Drop}AmPm affects for 12h clock.
+  EXPECT_EQ(clock12h_pm,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock12h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kDropAmPm));
+}
+
+TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault24h) {
+  // Test for a locale defaulted to 24h clock.
+  // As an instance, we use third_party/icu/source/data/locales/en_GB.txt.
+  i18n::SetICUDefaultLocale("en_GB");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+  string16 clock24h(ASCIIToUTF16("15:42"));
+  string16 clock12h_pm(ASCIIToUTF16("3:42 PM"));
+  string16 clock12h(ASCIIToUTF16("3:42"));
+
+  // The default is 24h clock.
+  EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(k24HourClock, GetHourClockType());
+  // k{Keep,Drop}AmPm should not affect for 24h clock.
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kDropAmPm));
+  // k{Keep,Drop}AmPm affects for 12h clock.
+  EXPECT_EQ(clock12h_pm,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock12h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kDropAmPm));
+}
+
+TEST(TimeFormattingTest, TimeFormatTimeOfDayJP) {
+  // Test for a locale that uses different mark than "AM" and "PM".
+  // As an instance, we use third_party/icu/source/data/locales/ja.txt.
+  i18n::SetICUDefaultLocale("ja_JP");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+  string16 clock24h(ASCIIToUTF16("15:42"));
+  string16 clock12h_pm(WideToUTF16(L"\x5348\x5f8c"L"3:42"));
+  string16 clock12h(ASCIIToUTF16("3:42"));
+
+  // The default is 24h clock.
+  EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(k24HourClock, GetHourClockType());
+  // k{Keep,Drop}AmPm should not affect for 24h clock.
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kDropAmPm));
+  // k{Keep,Drop}AmPm affects for 12h clock.
+  EXPECT_EQ(clock12h_pm,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock12h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kDropAmPm));
+}
+
+TEST(TimeFormattingTest, TimeFormatDateUS) {
+  // See third_party/icu/source/data/locales/en.txt.
+  // The date patterns are "EEEE, MMMM d, y", "MMM d, y", and "M/d/yy".
+  i18n::SetICUDefaultLocale("en_US");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+
+  EXPECT_EQ(ASCIIToUTF16("Apr 30, 2011"), TimeFormatShortDate(time));
+  EXPECT_EQ(ASCIIToUTF16("4/30/11"), TimeFormatShortDateNumeric(time));
+  EXPECT_EQ(ASCIIToUTF16("4/30/11 3:42:07 PM"),
+            TimeFormatShortDateAndTime(time));
+  EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011 3:42:07 PM"),
+            TimeFormatFriendlyDateAndTime(time));
+  EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011"),
+            TimeFormatFriendlyDate(time));
+}
+
+TEST(TimeFormattingTest, TimeFormatDateGB) {
+  // See third_party/icu/source/data/locales/en_GB.txt.
+  // The date patterns are "EEEE, d MMMM y", "d MMM y", and "dd/MM/yyyy".
+  i18n::SetICUDefaultLocale("en_GB");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+
+  EXPECT_EQ(ASCIIToUTF16("30 Apr 2011"), TimeFormatShortDate(time));
+  EXPECT_EQ(ASCIIToUTF16("30/04/2011"), TimeFormatShortDateNumeric(time));
+  EXPECT_EQ(ASCIIToUTF16("30/04/2011 15:42:07"),
+            TimeFormatShortDateAndTime(time));
+  EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 15:42:07"),
+            TimeFormatFriendlyDateAndTime(time));
+  EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011"),
+            TimeFormatFriendlyDate(time));
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/id_map.h b/base/id_map.h
new file mode 100644
index 0000000..d3fc7b8
--- /dev/null
+++ b/base/id_map.h
@@ -0,0 +1,257 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ID_MAP_H_
+#define BASE_ID_MAP_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/logging.h"
+#include "base/threading/non_thread_safe.h"
+
+// Ownership semantics - own pointer means the pointer is deleted in Remove()
+// & during destruction
+enum IDMapOwnershipSemantics {
+  IDMapExternalPointer,
+  IDMapOwnPointer
+};
+
+// This object maintains a list of IDs that can be quickly converted to
+// pointers to objects. It is implemented as a hash table, optimized for
+// relatively small data sets (in the common case, there will be exactly one
+// item in the list).
+//
+// Items can be inserted into the container with arbitrary ID, but the caller
+// must ensure they are unique. Inserting IDs and relying on automatically
+// generated ones is not allowed because they can collide.
+//
+// This class does not have a virtual destructor, do not inherit from it when
+// ownership semantics are set to own because pointers will leak.
+template<typename T, IDMapOwnershipSemantics OS = IDMapExternalPointer>
+class IDMap : public base::NonThreadSafe {
+ private:
+  typedef int32 KeyType;
+  typedef base::hash_map<KeyType, T*> HashTable;
+
+ public:
+  IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) {
+    // A number of consumers of IDMap create it on one thread but always access
+    // it from a different, but consitent, thread post-construction.
+    DetachFromThread();
+  }
+
+  ~IDMap() {
+    // Many IDMap's are static, and hence will be destroyed on the main thread.
+    // However, all the accesses may take place on another thread, such as the
+    // IO thread. Detaching again to clean this up.
+    DetachFromThread();
+    Releaser<OS, 0>::release_all(&data_);
+  }
+
+  // Sets whether Add should CHECK if passed in NULL data. Default is false.
+  void set_check_on_null_data(bool value) { check_on_null_data_ = value; }
+
+  // Adds a view with an automatically generated unique ID. See AddWithID.
+  KeyType Add(T* data) {
+    DCHECK(CalledOnValidThread());
+    CHECK(!check_on_null_data_ || data);
+    KeyType this_id = next_id_;
+    DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item";
+    data_[this_id] = data;
+    next_id_++;
+    return this_id;
+  }
+
+  // Adds a new data member with the specified ID. The ID must not be in
+  // the list. The caller either must generate all unique IDs itself and use
+  // this function, or allow this object to generate IDs and call Add. These
+  // two methods may not be mixed, or duplicate IDs may be generated
+  void AddWithID(T* data, KeyType id) {
+    DCHECK(CalledOnValidThread());
+    CHECK(!check_on_null_data_ || data);
+    DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
+    data_[id] = data;
+  }
+
+  void Remove(KeyType id) {
+    DCHECK(CalledOnValidThread());
+    typename HashTable::iterator i = data_.find(id);
+    if (i == data_.end()) {
+      NOTREACHED() << "Attempting to remove an item not in the list";
+      return;
+    }
+
+    if (iteration_depth_ == 0) {
+      Releaser<OS, 0>::release(i->second);
+      data_.erase(i);
+    } else {
+      removed_ids_.insert(id);
+    }
+  }
+
+  void Clear() {
+    DCHECK(CalledOnValidThread());
+    if (iteration_depth_ == 0) {
+      Releaser<OS, 0>::release_all(&data_);
+    } else {
+      for (typename HashTable::iterator i = data_.begin();
+           i != data_.end(); ++i)
+        removed_ids_.insert(i->first);
+    }
+  }
+
+  bool IsEmpty() const {
+    DCHECK(CalledOnValidThread());
+    return size() == 0u;
+  }
+
+  T* Lookup(KeyType id) const {
+    DCHECK(CalledOnValidThread());
+    typename HashTable::const_iterator i = data_.find(id);
+    if (i == data_.end())
+      return NULL;
+    return i->second;
+  }
+
+  size_t size() const {
+    DCHECK(CalledOnValidThread());
+    return data_.size() - removed_ids_.size();
+  }
+
+#if defined(UNIT_TEST)
+  int iteration_depth() const {
+    return iteration_depth_;
+  }
+#endif  // defined(UNIT_TEST)
+
+  // It is safe to remove elements from the map during iteration. All iterators
+  // will remain valid.
+  template<class ReturnType>
+  class Iterator {
+   public:
+    Iterator(IDMap<T, OS>* map)
+        : map_(map),
+          iter_(map_->data_.begin()) {
+      Init();
+    }
+
+    Iterator(const Iterator& iter)
+        : map_(iter.map_),
+          iter_(iter.iter_) {
+      Init();
+    }
+
+    const Iterator& operator=(const Iterator& iter) {
+      map_ = iter.map;
+      iter_ = iter.iter;
+      Init();
+      return *this;
+    }
+
+    ~Iterator() {
+      DCHECK(map_->CalledOnValidThread());
+
+      // We're going to decrement iteration depth. Make sure it's greater than
+      // zero so that it doesn't become negative.
+      DCHECK_LT(0, map_->iteration_depth_);
+
+      if (--map_->iteration_depth_ == 0)
+        map_->Compact();
+    }
+
+    bool IsAtEnd() const {
+      DCHECK(map_->CalledOnValidThread());
+      return iter_ == map_->data_.end();
+    }
+
+    KeyType GetCurrentKey() const {
+      DCHECK(map_->CalledOnValidThread());
+      return iter_->first;
+    }
+
+    ReturnType* GetCurrentValue() const {
+      DCHECK(map_->CalledOnValidThread());
+      return iter_->second;
+    }
+
+    void Advance() {
+      DCHECK(map_->CalledOnValidThread());
+      ++iter_;
+      SkipRemovedEntries();
+    }
+
+   private:
+    void Init() {
+      DCHECK(map_->CalledOnValidThread());
+      ++map_->iteration_depth_;
+      SkipRemovedEntries();
+    }
+
+    void SkipRemovedEntries() {
+      while (iter_ != map_->data_.end() &&
+             map_->removed_ids_.find(iter_->first) !=
+             map_->removed_ids_.end()) {
+        ++iter_;
+      }
+    }
+
+    IDMap<T, OS>* map_;
+    typename HashTable::const_iterator iter_;
+  };
+
+  typedef Iterator<T> iterator;
+  typedef Iterator<const T> const_iterator;
+
+ private:
+
+  // The dummy parameter is there because C++ standard does not allow
+  // explicitly specialized templates inside classes
+  template<IDMapOwnershipSemantics OI, int dummy> struct Releaser {
+    static inline void release(T* ptr) {}
+    static inline void release_all(HashTable* table) {}
+  };
+
+  template<int dummy> struct Releaser<IDMapOwnPointer, dummy> {
+    static inline void release(T* ptr) { delete ptr;}
+    static inline void release_all(HashTable* table) {
+      for (typename HashTable::iterator i = table->begin();
+           i != table->end(); ++i) {
+        delete i->second;
+      }
+      table->clear();
+    }
+  };
+
+  void Compact() {
+    DCHECK_EQ(0, iteration_depth_);
+    for (std::set<KeyType>::const_iterator i = removed_ids_.begin();
+         i != removed_ids_.end(); ++i) {
+      Remove(*i);
+    }
+    removed_ids_.clear();
+  }
+
+  // Keep track of how many iterators are currently iterating on us to safely
+  // handle removing items during iteration.
+  int iteration_depth_;
+
+  // Keep set of IDs that should be removed after the outermost iteration has
+  // finished. This way we manage to not invalidate the iterator when an element
+  // is removed.
+  std::set<KeyType> removed_ids_;
+
+  // The next ID that we will return from Add()
+  KeyType next_id_;
+
+  HashTable data_;
+
+  // See description above setter.
+  bool check_on_null_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(IDMap);
+};
+
+#endif  // BASE_ID_MAP_H_
diff --git a/base/id_map_unittest.cc b/base/id_map_unittest.cc
new file mode 100644
index 0000000..80c4c66
--- /dev/null
+++ b/base/id_map_unittest.cc
@@ -0,0 +1,337 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/id_map.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class IDMapTest : public testing::Test {
+};
+
+class TestObject {
+};
+
+class DestructorCounter {
+ public:
+  explicit DestructorCounter(int* counter) : counter_(counter) {}
+  ~DestructorCounter() { ++(*counter_); }
+ private:
+  int* counter_;
+};
+
+TEST_F(IDMapTest, Basic) {
+  IDMap<TestObject> map;
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  TestObject obj1;
+  TestObject obj2;
+
+  int32 id1 = map.Add(&obj1);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(1U, map.size());
+  EXPECT_EQ(&obj1, map.Lookup(id1));
+
+  int32 id2 = map.Add(&obj2);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(2U, map.size());
+
+  EXPECT_EQ(&obj1, map.Lookup(id1));
+  EXPECT_EQ(&obj2, map.Lookup(id2));
+
+  map.Remove(id1);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(1U, map.size());
+
+  map.Remove(id2);
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  map.AddWithID(&obj1, 1);
+  map.AddWithID(&obj2, 2);
+  EXPECT_EQ(&obj1, map.Lookup(1));
+  EXPECT_EQ(&obj2, map.Lookup(2));
+
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST_F(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_F(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) {
+  IDMap<TestObject> map;
+
+  const int kCount = 5;
+  TestObject obj[kCount];
+  int32 ids[kCount];
+
+  for (int i = 0; i < kCount; i++)
+    ids[i] = map.Add(&obj[i]);
+
+  int 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[0], iter.GetCurrentKey());
+        EXPECT_EQ(&obj[0], iter.GetCurrentValue());
+        map.Remove(ids[1]);
+        break;
+      case 1:
+        EXPECT_EQ(ids[2], iter.GetCurrentKey());
+        EXPECT_EQ(&obj[2], iter.GetCurrentValue());
+        map.Remove(ids[3]);
+        break;
+      case 2:
+        EXPECT_EQ(ids[4], iter.GetCurrentKey());
+        EXPECT_EQ(&obj[4], iter.GetCurrentValue());
+        map.Remove(ids[0]);
+        break;
+      default:
+        FAIL() << "should not have that many elements";
+        break;
+    }
+
+    counter++;
+  }
+
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST_F(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_F(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_F(IDMapTest, IteratorRemainsValidWhenClearing) {
+  IDMap<TestObject> map;
+
+  const int kCount = 5;
+  TestObject obj[kCount];
+  int32 ids[kCount];
+
+  for (int i = 0; i < kCount; i++)
+    ids[i] = map.Add(&obj[i]);
+
+  int counter = 0;
+  for (IDMap<TestObject>::const_iterator iter(&map);
+       !iter.IsAtEnd(); iter.Advance()) {
+    switch (counter) {
+      case 0:
+        EXPECT_EQ(ids[0], iter.GetCurrentKey());
+        EXPECT_EQ(&obj[0], iter.GetCurrentValue());
+        break;
+      case 1:
+        EXPECT_EQ(ids[1], iter.GetCurrentKey());
+        EXPECT_EQ(&obj[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_F(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_F(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_F(IDMapTest, OwningPointersDeletesThemOnDestruct) {
+  const int kCount = 3;
+
+  int external_del_count = 0;
+  DestructorCounter* external_obj[kCount];
+
+  int owned_del_count = 0;
+  DestructorCounter* owned_obj[kCount];
+
+  {
+    IDMap<DestructorCounter> map_external;
+    IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+    for (int i = 0; i < kCount; ++i) {
+      external_obj[i] = new DestructorCounter(&external_del_count);
+      map_external.Add(external_obj[i]);
+
+      owned_obj[i] = new DestructorCounter(&owned_del_count);
+      map_owned.Add(owned_obj[i]);
+    }
+  }
+
+  EXPECT_EQ(external_del_count, 0);
+
+  for (int i = 0; i < kCount; ++i) {
+    delete external_obj[i];
+  }
+
+  EXPECT_EQ(external_del_count, kCount);
+  EXPECT_EQ(owned_del_count, kCount);
+}
+
+}  // namespace
diff --git a/base/ios/OWNERS b/base/ios/OWNERS
new file mode 100644
index 0000000..6256400
--- /dev/null
+++ b/base/ios/OWNERS
@@ -0,0 +1,3 @@
+qsr@chromium.org
+rohitrao@chromium.org
+stuartmorgan@chromium.org
diff --git a/base/ios/device_util.h b/base/ios/device_util.h
new file mode 100644
index 0000000..fe4833d
--- /dev/null
+++ b/base/ios/device_util.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_DEVICE_UTIL_H_
+#define BASE_IOS_DEVICE_UTIL_H_
+
+#include <string>
+
+namespace ios {
+namespace device_util {
+
+// Returns the hardware version of the device the app is running on.
+//
+// The returned string is the string returned by sysctlbyname() with name
+// "hw.machine". Possible (known) values include:
+//
+// iPhone1,1 -> iPhone 1G
+// iPhone1,2 -> iPhone 3G
+// iPhone2,1 -> iPhone 3GS
+// iPhone3,1 -> iPhone 4/AT&T
+// iPhone3,2 -> iPhone 4/Other Carrier?
+// iPhone3,3 -> iPhone 4/Other Carrier?
+// iPhone4,1 -> iPhone 4S
+//
+// iPod1,1   -> iPod touch 1G
+// iPod2,1   -> iPod touch 2G
+// iPod2,2   -> ?
+// iPod3,1   -> iPod touch 3G
+// iPod4,1   -> iPod touch 4G
+// iPod5,1   -> ?
+//
+// iPad1,1   -> iPad 1G, WiFi
+// iPad1,?   -> iPad 1G, 3G <- needs 3G owner to test
+// iPad2,1   -> iPad 2G, WiFi
+//
+// AppleTV2,1 -> AppleTV 2
+//
+// i386       -> Simulator
+// x86_64     -> Simulator
+std::string GetPlatform();
+
+// Returns true if the application is running on a high-ram device. (>=250M).
+bool IsRunningOnHighRamDevice();
+
+// Returns true if the device has only one core.
+bool IsSingleCoreDevice();
+
+// Returns the MAC address of the interface with name |interface_name|.
+std::string GetMacAddress(const std::string& interface_name);
+
+// Returns a random UUID.
+std::string GetRandomId();
+
+// Returns an identifier for the device, using the given |salt|. A global
+// identifier is generated the first time this method is called, and the salt
+// is used to be able to generate distinct identifiers for the same device. If
+// |salt| is NULL, a default value is used. Unless you are using this value for
+// something that should be anonymous, you should probably pass NULL.
+std::string GetDeviceIdentifier(const char* salt);
+
+}  // namespace device_util
+}  // namespace ios
+
+#endif  // BASE_IOS_DEVICE_UTIL_H_
diff --git a/base/ios/device_util.mm b/base/ios/device_util.mm
new file mode 100644
index 0000000..e6801ab
--- /dev/null
+++ b/base/ios/device_util.mm
@@ -0,0 +1,130 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/ios/device_util.h"
+
+#include <CommonCrypto/CommonDigest.h>
+#import <UIKit/UIKit.h>
+
+#include <ifaddrs.h>
+#include <net/if_dl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include "base/ios/ios_util.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/sys_string_conversions.h"
+
+namespace {
+
+// Client ID key in the user preferences.
+NSString* const kClientIdPreferenceKey = @"ChromiumClientID";
+// Default salt for device ids.
+const char kDefaultSalt[] = "Salt";
+
+}  // namespace
+
+namespace ios {
+namespace device_util {
+
+std::string GetPlatform() {
+  std::string platform;
+  size_t size = 0;
+  sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+  sysctlbyname("hw.machine", WriteInto(&platform, size), &size, NULL, 0);
+  return platform;
+}
+
+bool IsRunningOnHighRamDevice() {
+  uint64_t memory_size = 0;
+  size_t size = sizeof(memory_size);
+  if (sysctlbyname("hw.memsize", &memory_size, &size, NULL, 0) == 0) {
+    // Anything >= 250M, call high ram.
+    return memory_size >= 250 * 1024 * 1024;
+  }
+  return false;
+}
+
+bool IsSingleCoreDevice() {
+  uint64_t cpu_number = 0;
+  size_t sizes = sizeof(cpu_number);
+  sysctlbyname("hw.physicalcpu", &cpu_number, &sizes, NULL, 0);
+  return cpu_number == 1;
+}
+
+std::string GetMacAddress(const std::string& interface_name) {
+  std::string mac_string;
+  struct ifaddrs* addresses;
+  if (getifaddrs(&addresses) == 0) {
+    for (struct ifaddrs* address = addresses; address;
+         address = address->ifa_next) {
+      if ((address->ifa_addr->sa_family == AF_LINK) &&
+          strcmp(interface_name.c_str(), address->ifa_name) == 0) {
+        const struct sockaddr_dl* found_address_struct =
+            reinterpret_cast<const struct sockaddr_dl*>(address->ifa_addr);
+
+        // |found_address_struct->sdl_data| contains the interface name followed
+        // by the interface address. The address part can be accessed based on
+        // the length of the name, that is, |found_address_struct->sdl_nlen|.
+        const unsigned char* found_address =
+            reinterpret_cast<const unsigned char*>(
+                &found_address_struct->sdl_data[
+                    found_address_struct->sdl_nlen]);
+
+        int found_address_length = found_address_struct->sdl_alen;
+        for (int i = 0; i < found_address_length; ++i) {
+          if (i != 0)
+            mac_string.push_back(':');
+          base::StringAppendF(&mac_string, "%02X", found_address[i]);
+        }
+        break;
+      }
+    }
+    freeifaddrs(addresses);
+  }
+  return mac_string;
+}
+
+std::string GetRandomId() {
+  base::mac::ScopedCFTypeRef<CFUUIDRef>
+      uuid_object(CFUUIDCreate(kCFAllocatorDefault));
+  base::mac::ScopedCFTypeRef<CFStringRef> uuid_string(
+      CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
+  return base::SysCFStringRefToUTF8(uuid_string);
+}
+
+std::string GetDeviceIdentifier(const char* salt) {
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  NSString* client_id = [defaults stringForKey:kClientIdPreferenceKey];
+
+  if (!client_id) {
+    if (base::ios::IsRunningOnIOS6OrLater())
+      client_id = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
+    else
+      client_id = base::SysUTF8ToNSString(GetRandomId());
+    [defaults setObject:client_id forKey:kClientIdPreferenceKey];
+    [defaults synchronize];
+  }
+
+  NSData* hash_data = [[NSString stringWithFormat:@"%@%s", client_id,
+      salt ? salt : kDefaultSalt] dataUsingEncoding:NSUTF8StringEncoding];
+
+  unsigned char hash[CC_SHA256_DIGEST_LENGTH];
+  CC_SHA256([hash_data bytes], [hash_data length], hash);
+  CFUUIDBytes* uuid_bytes = reinterpret_cast<CFUUIDBytes*>(hash);
+
+  base::mac::ScopedCFTypeRef<CFUUIDRef>
+      uuid_object(CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *uuid_bytes));
+  base::mac::ScopedCFTypeRef<CFStringRef> device_id(
+      CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
+  return base::SysCFStringRefToUTF8(device_id);
+}
+
+}  // namespace device_util
+}  // namespace ios
diff --git a/base/ios/device_util_unittest.mm b/base/ios/device_util_unittest.mm
new file mode 100644
index 0000000..b8ba10f
--- /dev/null
+++ b/base/ios/device_util_unittest.mm
@@ -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.
+
+#import <Foundation/Foundation.h>
+
+#include "base/ios/device_util.h"
+#include "base/ios/ios_util.h"
+#include "base/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+namespace {
+// The behavior of most of these utility functions depends on what they are run
+// on, so there is not much to unittest them. The APIs are run to make sure they
+// don't choke. Additional checks are added for particular APIs when needed.
+
+typedef PlatformTest DeviceUtilTest;
+
+TEST_F(DeviceUtilTest, GetPlatform) {
+  GTEST_ASSERT_GT(ios::device_util::GetPlatform().length(), 0U);
+}
+
+TEST_F(DeviceUtilTest, IsRunningOnHighRamDevice) {
+  ios::device_util::IsRunningOnHighRamDevice();
+}
+
+TEST_F(DeviceUtilTest, IsSingleCoreDevice) {
+  ios::device_util::IsSingleCoreDevice();
+}
+
+TEST_F(DeviceUtilTest, GetMacAddress) {
+  GTEST_ASSERT_GT(ios::device_util::GetMacAddress("en0").length(), 0U);
+}
+
+TEST_F(DeviceUtilTest, GetRandomId) {
+  GTEST_ASSERT_GT(ios::device_util::GetRandomId().length(), 0U);
+}
+
+TEST_F(DeviceUtilTest, GetDeviceIdentifier) {
+  std::string default_id = ios::device_util::GetDeviceIdentifier(NULL);
+  std::string other_id = ios::device_util::GetDeviceIdentifier("ForTest");
+  EXPECT_NE(default_id, other_id);
+
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults removeObjectForKey:@"ChromiumClientID"];
+  [defaults synchronize];
+
+  std::string new_default_id = ios::device_util::GetDeviceIdentifier(NULL);
+  if (base::ios::IsRunningOnIOS6OrLater())
+    EXPECT_EQ(default_id, new_default_id);
+  else
+    EXPECT_NE(default_id, new_default_id);
+}
+
+}  // namespace
diff --git a/base/ios/ios_util.h b/base/ios/ios_util.h
new file mode 100644
index 0000000..e8f9806
--- /dev/null
+++ b/base/ios/ios_util.h
@@ -0,0 +1,26 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_IOS_UTIL_H_
+#define BASE_IOS_IOS_UTIL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace ios {
+
+// Returns whether the operation system is iOS 5 or later.
+BASE_EXPORT bool IsRunningOnIOS5OrLater();
+
+// Returns whether the operation system is iOS 6 or later.
+BASE_EXPORT bool IsRunningOnIOS6OrLater();
+
+// Returns whether the operation system is at the given version or later.
+BASE_EXPORT bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix);
+
+}  // namespace ios
+}  // namespace base
+
+#endif  // BASE_IOS_IOS_UTIL_H_
diff --git a/base/ios/ios_util.mm b/base/ios/ios_util.mm
new file mode 100644
index 0000000..37f386d
--- /dev/null
+++ b/base/ios/ios_util.mm
@@ -0,0 +1,42 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/ios/ios_util.h"
+
+#include "base/sys_info.h"
+
+namespace {
+// Return a 3 elements array containing the major, minor and bug fix version of
+// the OS.
+const int32* OSVersionAsArray() {
+  int32* digits = new int32[3];
+  base::SysInfo::OperatingSystemVersionNumbers(
+      &digits[0], &digits[1], &digits[2]);
+  return digits;
+}
+}  // namespace
+
+namespace base {
+namespace ios {
+
+bool IsRunningOnIOS5OrLater() {
+  return IsRunningOnOrLater(5, 0, 0);
+}
+
+bool IsRunningOnIOS6OrLater() {
+  return IsRunningOnOrLater(6, 0, 0);
+}
+
+bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix) {
+  static const int32* current_version = OSVersionAsArray();
+  int32 version[] = { major, minor, bug_fix };
+  for (size_t i = 0; i < arraysize(version); i++) {
+    if (current_version[i] != version[i])
+      return current_version[i] > version[i];
+  }
+  return true;
+}
+
+}  // namespace ios
+}  // namespace base
diff --git a/base/ios/scoped_critical_action.h b/base/ios/scoped_critical_action.h
new file mode 100644
index 0000000..660a83a
--- /dev/null
+++ b/base/ios/scoped_critical_action.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_SCOPED_CRITICAL_ACTION_H_
+#define BASE_IOS_SCOPED_CRITICAL_ACTION_H_
+
+#include "base/synchronization/lock.h"
+
+namespace base {
+namespace ios {
+
+// This class attempts to allow the application to continue to run for a period
+// of time after it transitions to the background. The construction of an
+// instance of this class marks the beginning of a task that needs background
+// running time when the application is moved to the background and the
+// destruction marks the end of such a task.
+//
+// Note there is no guarantee that the task will continue to finish when the
+// application is moved to the background.
+//
+// This class should be used at times where leaving a task unfinished might be
+// detrimental to user experience. For example, it should be used to ensure that
+// the application has enough time to save important data or at least attempt to
+// save such data.
+class ScopedCriticalAction {
+ public:
+  ScopedCriticalAction();
+  ~ScopedCriticalAction();
+
+ private:
+  // Informs the OS that the background task has completed.
+  void EndBackgroundTask();
+
+  // |UIBackgroundTaskIdentifier| returned by
+  // |beginBackgroundTaskWithExpirationHandler:| when marking the beginning of
+  // a long-running background task. It is defined as an |unsigned int| instead
+  // of a |UIBackgroundTaskIdentifier| so this class can be used in .cc files.
+  unsigned int background_task_id_;
+  Lock background_task_id_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCriticalAction);
+};
+
+}  // namespace ios
+}  // namespace base
+
+#endif  // BASE_IOS_SCOPED_CRITICAL_ACTION_H_
diff --git a/base/ios/scoped_critical_action.mm b/base/ios/scoped_critical_action.mm
new file mode 100644
index 0000000..734c0a2
--- /dev/null
+++ b/base/ios/scoped_critical_action.mm
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/ios/scoped_critical_action.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+namespace ios {
+
+// This implementation calls |beginBackgroundTaskWithExpirationHandler:| when
+// instantiated and |endBackgroundTask:| when destroyed, creating a scope whose
+// execution will continue (temporarily) even after the app is backgrounded.
+ScopedCriticalAction::ScopedCriticalAction() {
+  background_task_id_ = [[UIApplication sharedApplication]
+      beginBackgroundTaskWithExpirationHandler:^{
+        DLOG(WARNING) << "Background task with id " << background_task_id_
+                      << " expired.";
+        // Note if |endBackgroundTask:| is not called for each task before time
+        // expires, the system kills the application.
+        EndBackgroundTask();
+      }];
+  if (background_task_id_ == UIBackgroundTaskInvalid) {
+    DLOG(WARNING) <<
+        "beginBackgroundTaskWithExpirationHandler: returned an invalid ID";
+  } else {
+    VLOG(3) << "Beginning background task with id " << background_task_id_;
+  }
+}
+
+ScopedCriticalAction::~ScopedCriticalAction() {
+  EndBackgroundTask();
+}
+
+void ScopedCriticalAction::EndBackgroundTask() {
+  UIBackgroundTaskIdentifier task_id;
+  {
+    AutoLock lock_scope(background_task_id_lock_);
+    if (background_task_id_ == UIBackgroundTaskInvalid)
+      return;
+    task_id = background_task_id_;
+    background_task_id_ = UIBackgroundTaskInvalid;
+  }
+
+  VLOG(3) << "Ending background task with id " << task_id;
+  [[UIApplication sharedApplication] endBackgroundTask:task_id];
+}
+
+}  // namespace ios
+}  // namespace base
diff --git a/base/json/json_file_value_serializer.cc b/base/json/json_file_value_serializer.cc
new file mode 100644
index 0000000..2fac451
--- /dev/null
+++ b/base/json/json_file_value_serializer.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_file_value_serializer.h"
+
+#include "base/file_util.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+
+const char* JSONFileValueSerializer::kAccessDenied = "Access denied.";
+const char* JSONFileValueSerializer::kCannotReadFile = "Can't read file.";
+const char* JSONFileValueSerializer::kFileLocked = "File locked.";
+const char* JSONFileValueSerializer::kNoSuchFile = "File doesn't exist.";
+
+bool JSONFileValueSerializer::Serialize(const Value& root) {
+  return SerializeInternal(root, false);
+}
+
+bool JSONFileValueSerializer::SerializeAndOmitBinaryValues(const Value& root) {
+  return SerializeInternal(root, true);
+}
+
+bool JSONFileValueSerializer::SerializeInternal(const 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 (file_util::WriteFile(json_file_path_,
+                           json_string.data(),
+                           data_size) != data_size)
+    return false;
+
+  return true;
+}
+
+int JSONFileValueSerializer::ReadFileToString(std::string* json_string) {
+  DCHECK(json_string);
+  if (!file_util::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 (!file_util::PathExists(json_file_path_))
+      return JSON_NO_SUCH_FILE;
+    else
+      return JSON_CANNOT_READ_FILE;
+  }
+  return JSON_NO_ERROR;
+}
+
+const char* JSONFileValueSerializer::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 "";
+  }
+}
+
+Value* JSONFileValueSerializer::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;
+  }
+
+  JSONStringValueSerializer serializer(json_string);
+  serializer.set_allow_trailing_comma(allow_trailing_comma_);
+  return serializer.Deserialize(error_code, error_str);
+}
diff --git a/base/json/json_file_value_serializer.h b/base/json/json_file_value_serializer.h
new file mode 100644
index 0000000..633db5d
--- /dev/null
+++ b/base/json/json_file_value_serializer.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+#define BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/values.h"
+
+class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
+ public:
+  // json_file_patch is the path of a file that will be source of the
+  // deserialization or the destination of the serialization.
+  // When deserializing, the file should exist, but when serializing, the
+  // serializer will attempt to create the file at the specified location.
+  explicit JSONFileValueSerializer(const FilePath& json_file_path)
+    : json_file_path_(json_file_path),
+      allow_trailing_comma_(false) {}
+
+  virtual ~JSONFileValueSerializer() {}
+
+  // 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.
+  virtual bool Serialize(const Value& root) OVERRIDE;
+
+  // Equivalent to Serialize(root) except binary values are omitted from the
+  // output.
+  bool SerializeAndOmitBinaryValues(const Value& root);
+
+  // 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.
+  virtual 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;
+  }
+
+ private:
+  bool SerializeInternal(const Value& root, bool omit_binary_values);
+
+  FilePath json_file_path_;
+  bool allow_trailing_comma_;
+
+  // A wrapper for file_util::ReadFileToString which returns a non-zero
+  // JsonFileError if there were file errors.
+  int ReadFileToString(std::string* json_string);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer);
+};
+
+#endif  // BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc
new file mode 100644
index 0000000..02295de
--- /dev/null
+++ b/base/json/json_parser.cc
@@ -0,0 +1,962 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_parser.h"
+
+#include "base/float_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "base/utf_string_conversion_utils.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+const int kStackMaxDepth = 100;
+
+const int32 kExtendedASCIIStart = 0x80;
+
+// This and the class below are used to own the JSON input string for when
+// string tokens are stored as StringPiece instead of std::string. This
+// optimization avoids about 2/3rds of string memory copies. The constructor
+// takes ownership of the input string. The real root value is Swap()ed into
+// the new instance.
+class DictionaryHiddenRootValue : public base::DictionaryValue {
+ public:
+  DictionaryHiddenRootValue(std::string* json, Value* root) : json_(json) {
+    DCHECK(root->IsType(Value::TYPE_DICTIONARY));
+    DictionaryValue::Swap(static_cast<DictionaryValue*>(root));
+  }
+
+  virtual void Swap(DictionaryValue* other) OVERRIDE {
+    DVLOG(1) << "Swap()ing a DictionaryValue inefficiently.";
+
+    // First deep copy to convert JSONStringValue to std::string and swap that
+    // copy with |other|, which contains the new contents of |this|.
+    scoped_ptr<base::DictionaryValue> copy(DeepCopy());
+    copy->Swap(other);
+
+    // Then erase the contents of the current dictionary and swap in the
+    // new contents, originally from |other|.
+    Clear();
+    json_.reset();
+    DictionaryValue::Swap(copy.get());
+  }
+
+  // Not overriding DictionaryValue::Remove because it just calls through to
+  // the method below.
+
+  virtual bool RemoveWithoutPathExpansion(const std::string& key,
+                                          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.
+    Value* out_owned = NULL;
+    if (!DictionaryValue::RemoveWithoutPathExpansion(key, &out_owned))
+      return false;
+
+    *out = out_owned->DeepCopy();
+    delete out_owned;
+
+    return true;
+  }
+
+ private:
+  scoped_ptr<std::string> json_;
+
+  DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue);
+};
+
+class ListHiddenRootValue : public base::ListValue {
+ public:
+  ListHiddenRootValue(std::string* json, Value* root) : json_(json) {
+    DCHECK(root->IsType(Value::TYPE_LIST));
+    ListValue::Swap(static_cast<ListValue*>(root));
+  }
+
+  virtual void Swap(ListValue* other) OVERRIDE {
+    DVLOG(1) << "Swap()ing a ListValue inefficiently.";
+
+    // First deep copy to convert JSONStringValue to std::string and swap that
+    // copy with |other|, which contains the new contents of |this|.
+    scoped_ptr<base::ListValue> copy(DeepCopy());
+    copy->Swap(other);
+
+    // Then erase the contents of the current list and swap in the new contents,
+    // originally from |other|.
+    Clear();
+    json_.reset();
+    ListValue::Swap(copy.get());
+  }
+
+  virtual bool Remove(size_t index, 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.
+    Value* out_owned = NULL;
+    if (!ListValue::Remove(index, &out_owned))
+      return false;
+
+    *out = out_owned->DeepCopy();
+    delete out_owned;
+
+    return true;
+  }
+
+ private:
+  scoped_ptr<std::string> json_;
+
+  DISALLOW_COPY_AND_ASSIGN(ListHiddenRootValue);
+};
+
+// A variant on StringValue that uses StringPiece instead of copying the string
+// into the Value. This can only be stored in a child of hidden root (above),
+// otherwise the referenced string will not be guaranteed to outlive it.
+class JSONStringValue : public base::Value {
+ public:
+  explicit JSONStringValue(const base::StringPiece& piece)
+      : Value(TYPE_STRING),
+        string_piece_(piece) {
+  }
+
+  // Overridden from base::Value:
+  virtual bool GetAsString(std::string* out_value) const OVERRIDE {
+    string_piece_.CopyToString(out_value);
+    return true;
+  }
+  virtual bool GetAsString(string16* out_value) const OVERRIDE {
+    *out_value = UTF8ToUTF16(string_piece_);
+    return true;
+  }
+  virtual Value* DeepCopy() const OVERRIDE {
+    return Value::CreateStringValue(string_piece_.as_string());
+  }
+  virtual bool Equals(const Value* other) const OVERRIDE {
+    std::string other_string;
+    return other->IsType(TYPE_STRING) && other->GetAsString(&other_string) &&
+        StringPiece(other_string) == string_piece_;
+  }
+
+ private:
+  // The location in the original input stream.
+  base::StringPiece string_piece_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONStringValue);
+};
+
+// Simple class that checks for maximum recursion/"stack overflow."
+class StackMarker {
+ public:
+  explicit StackMarker(int* depth) : depth_(depth) {
+    ++(*depth_);
+    DCHECK_LE(*depth_, kStackMaxDepth);
+  }
+  ~StackMarker() {
+    --(*depth_);
+  }
+
+  bool IsTooDeep() const {
+    return *depth_ >= kStackMaxDepth;
+  }
+
+ private:
+  int* const depth_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackMarker);
+};
+
+}  // namespace
+
+JSONParser::JSONParser(int options)
+    : options_(options),
+      start_pos_(NULL),
+      pos_(NULL),
+      end_pos_(NULL),
+      index_(0),
+      stack_depth_(0),
+      line_number_(0),
+      index_last_line_(0),
+      error_code_(JSONReader::JSON_NO_ERROR),
+      error_line_(0),
+      error_column_(0) {
+}
+
+JSONParser::~JSONParser() {
+}
+
+Value* JSONParser::Parse(const StringPiece& input) {
+  scoped_ptr<std::string> input_copy;
+  // If the children of a JSON root can be detached, then hidden roots cannot
+  // be used, so do not bother copying the input because StringPiece will not
+  // be used anywhere.
+  if (!(options_ & JSON_DETACHABLE_CHILDREN)) {
+    input_copy.reset(new std::string(input.as_string()));
+    start_pos_ = input_copy->data();
+  } else {
+    start_pos_ = input.data();
+  }
+  pos_ = start_pos_;
+  end_pos_ = start_pos_ + input.length();
+  index_ = 0;
+  line_number_ = 1;
+  index_last_line_ = 0;
+
+  error_code_ = JSONReader::JSON_NO_ERROR;
+  error_line_ = 0;
+  error_column_ = 0;
+
+  // When the input JSON string starts with a UTF-8 Byte-Order-Mark
+  // <0xEF 0xBB 0xBF>, advance the start position to avoid the
+  // ParseNextToken function mis-treating a Unicode BOM as an invalid
+  // character and returning NULL.
+  if (CanConsume(3) && static_cast<uint8>(*pos_) == 0xEF &&
+      static_cast<uint8>(*(pos_ + 1)) == 0xBB &&
+      static_cast<uint8>(*(pos_ + 2)) == 0xBF) {
+    NextNChars(3);
+  }
+
+  // Parse the first and any nested tokens.
+  scoped_ptr<Value> root(ParseNextToken());
+  if (!root.get())
+    return NULL;
+
+  // Make sure the input stream is at an end.
+  if (GetNextToken() != T_END_OF_INPUT) {
+    if (!CanConsume(1) || (NextChar() && GetNextToken() != T_END_OF_INPUT)) {
+      ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 1);
+      return NULL;
+    }
+  }
+
+  // Dictionaries and lists can contain JSONStringValues, so wrap them in a
+  // hidden root.
+  if (!(options_ & JSON_DETACHABLE_CHILDREN)) {
+    if (root->IsType(Value::TYPE_DICTIONARY)) {
+      return new DictionaryHiddenRootValue(input_copy.release(), root.get());
+    } else if (root->IsType(Value::TYPE_LIST)) {
+      return new ListHiddenRootValue(input_copy.release(), root.get());
+    } else if (root->IsType(Value::TYPE_STRING)) {
+      // A string type could be a JSONStringValue, but because there's no
+      // corresponding HiddenRootValue, the memory will be lost. Deep copy to
+      // preserve it.
+      return root->DeepCopy();
+    }
+  }
+
+  // All other values can be returned directly.
+  return root.release();
+}
+
+JSONReader::JsonParseError JSONParser::error_code() const {
+  return error_code_;
+}
+
+std::string JSONParser::GetErrorMessage() const {
+  return FormatErrorMessage(error_line_, error_column_,
+      JSONReader::ErrorCodeToString(error_code_));
+}
+
+// StringBuilder ///////////////////////////////////////////////////////////////
+
+JSONParser::StringBuilder::StringBuilder()
+    : pos_(NULL),
+      length_(0),
+      string_(NULL) {
+}
+
+JSONParser::StringBuilder::StringBuilder(const char* pos)
+    : pos_(pos),
+      length_(0),
+      string_(NULL) {
+}
+
+void JSONParser::StringBuilder::Swap(StringBuilder* other) {
+  std::swap(other->string_, string_);
+  std::swap(other->pos_, pos_);
+  std::swap(other->length_, length_);
+}
+
+JSONParser::StringBuilder::~StringBuilder() {
+  delete string_;
+}
+
+void JSONParser::StringBuilder::Append(const char& c) {
+  DCHECK_GE(c, 0);
+  DCHECK_LT(c, 128);
+
+  if (string_)
+    string_->push_back(c);
+  else
+    ++length_;
+}
+
+void JSONParser::StringBuilder::AppendString(const std::string& str) {
+  DCHECK(string_);
+  string_->append(str);
+}
+
+void JSONParser::StringBuilder::Convert() {
+  if (string_)
+    return;
+  string_  = new std::string(pos_, length_);
+}
+
+bool JSONParser::StringBuilder::CanBeStringPiece() const {
+  return !string_;
+}
+
+StringPiece JSONParser::StringBuilder::AsStringPiece() {
+  if (string_)
+    return StringPiece();
+  return StringPiece(pos_, length_);
+}
+
+const std::string& JSONParser::StringBuilder::AsString() {
+  if (!string_)
+    Convert();
+  return *string_;
+}
+
+// JSONParser private //////////////////////////////////////////////////////////
+
+inline bool JSONParser::CanConsume(int length) {
+  return pos_ + length <= end_pos_;
+}
+
+const char* JSONParser::NextChar() {
+  DCHECK(CanConsume(1));
+  ++index_;
+  ++pos_;
+  return pos_;
+}
+
+void JSONParser::NextNChars(int n) {
+  DCHECK(CanConsume(n));
+  index_ += n;
+  pos_ += n;
+}
+
+JSONParser::Token JSONParser::GetNextToken() {
+  EatWhitespaceAndComments();
+  if (!CanConsume(1))
+    return T_END_OF_INPUT;
+
+  switch (*pos_) {
+    case '{':
+      return T_OBJECT_BEGIN;
+    case '}':
+      return T_OBJECT_END;
+    case '[':
+      return T_ARRAY_BEGIN;
+    case ']':
+      return T_ARRAY_END;
+    case '"':
+      return T_STRING;
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '-':
+      return T_NUMBER;
+    case 't':
+      return T_BOOL_TRUE;
+    case 'f':
+      return T_BOOL_FALSE;
+    case 'n':
+      return T_NULL;
+    case ',':
+      return T_LIST_SEPARATOR;
+    case ':':
+      return T_OBJECT_PAIR_SEPARATOR;
+    default:
+      return T_INVALID_TOKEN;
+  }
+}
+
+void JSONParser::EatWhitespaceAndComments() {
+  while (pos_ < end_pos_) {
+    switch (*pos_) {
+      case '\r':
+      case '\n':
+        index_last_line_ = index_;
+        ++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)) {
+      char next_char = *NextChar();
+      if (next_char == '\n' || next_char == '\r')
+        return true;
+    }
+  } else if (next_char == '*') {
+    // Block comment, read until end marker.
+    while (CanConsume(2)) {
+      if (*NextChar() == '*' && *NextChar() == '/') {
+        // 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;
+      }
+    }
+
+    // If the comment is unterminated, GetNextToken will report T_END_OF_INPUT.
+  }
+
+  return false;
+}
+
+Value* JSONParser::ParseNextToken() {
+  return ParseToken(GetNextToken());
+}
+
+Value* JSONParser::ParseToken(Token token) {
+  switch (token) {
+    case T_OBJECT_BEGIN:
+      return ConsumeDictionary();
+    case T_ARRAY_BEGIN:
+      return ConsumeList();
+    case T_STRING:
+      return ConsumeString();
+    case T_NUMBER:
+      return ConsumeNumber();
+    case T_BOOL_TRUE:
+    case T_BOOL_FALSE:
+    case T_NULL:
+      return ConsumeLiteral();
+    default:
+      ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+      return NULL;
+  }
+}
+
+Value* JSONParser::ConsumeDictionary() {
+  if (*pos_ != '{') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return NULL;
+  }
+
+  StackMarker depth_check(&stack_depth_);
+  if (depth_check.IsTooDeep()) {
+    ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1);
+    return NULL;
+  }
+
+  scoped_ptr<DictionaryValue> dict(new DictionaryValue);
+
+  NextChar();
+  Token token = GetNextToken();
+  while (token != T_OBJECT_END) {
+    if (token != T_STRING) {
+      ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 1);
+      return NULL;
+    }
+
+    // First consume the key.
+    StringBuilder key;
+    if (!ConsumeStringRaw(&key)) {
+      return NULL;
+    }
+
+    // Read the separator.
+    NextChar();
+    token = GetNextToken();
+    if (token != T_OBJECT_PAIR_SEPARATOR) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+
+    // The next token is the value. Ownership transfers to |dict|.
+    NextChar();
+    Value* value = ParseNextToken();
+    if (!value) {
+      // ReportError from deeper level.
+      return NULL;
+    }
+
+    dict->SetWithoutPathExpansion(key.AsString(), value);
+
+    NextChar();
+    token = GetNextToken();
+    if (token == T_LIST_SEPARATOR) {
+      NextChar();
+      token = GetNextToken();
+      if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) {
+        ReportError(JSONReader::JSON_TRAILING_COMMA, 1);
+        return NULL;
+      }
+    } else if (token != T_OBJECT_END) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+      return NULL;
+    }
+  }
+
+  return dict.release();
+}
+
+Value* JSONParser::ConsumeList() {
+  if (*pos_ != '[') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return NULL;
+  }
+
+  StackMarker depth_check(&stack_depth_);
+  if (depth_check.IsTooDeep()) {
+    ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1);
+    return NULL;
+  }
+
+  scoped_ptr<ListValue> list(new ListValue);
+
+  NextChar();
+  Token token = GetNextToken();
+  while (token != T_ARRAY_END) {
+    Value* item = ParseToken(token);
+    if (!item) {
+      // ReportError from deeper level.
+      return NULL;
+    }
+
+    list->Append(item);
+
+    NextChar();
+    token = GetNextToken();
+    if (token == T_LIST_SEPARATOR) {
+      NextChar();
+      token = GetNextToken();
+      if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) {
+        ReportError(JSONReader::JSON_TRAILING_COMMA, 1);
+        return NULL;
+      }
+    } else if (token != T_ARRAY_END) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+  }
+
+  return list.release();
+}
+
+Value* JSONParser::ConsumeString() {
+  StringBuilder string;
+  if (!ConsumeStringRaw(&string))
+    return NULL;
+
+  // Create the Value representation, using a hidden root, if configured
+  // to do so, and if the string can be represented by StringPiece.
+  if (string.CanBeStringPiece() && !(options_ & JSON_DETACHABLE_CHILDREN)) {
+    return new JSONStringValue(string.AsStringPiece());
+  } else {
+    if (string.CanBeStringPiece())
+      string.Convert();
+    return new StringValue(string.AsString());
+  }
+}
+
+bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
+  if (*pos_ != '"') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return false;
+  }
+
+  // StringBuilder will internally build a StringPiece unless a UTF-16
+  // conversion occurs, at which point it will perform a copy into a
+  // std::string.
+  StringBuilder string(NextChar());
+
+  int length = end_pos_ - start_pos_;
+  int32 next_char = 0;
+
+  while (CanConsume(1)) {
+    pos_ = start_pos_ + index_;  // CBU8_NEXT is postcrement.
+    CBU8_NEXT(start_pos_, index_, length, next_char);
+    if (next_char < 0 || !IsValidCharacter(next_char)) {
+      ReportError(JSONReader::JSON_UNSUPPORTED_ENCODING, 1);
+      return false;
+    }
+
+    // If this character is an escape sequence...
+    if (next_char == '\\') {
+      // The input string will be adjusted (either by combining the two
+      // characters of an encoded escape sequence, or with a UTF conversion),
+      // so using StringPiece isn't possible -- force a conversion.
+      string.Convert();
+
+      if (!CanConsume(1)) {
+        ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+        return false;
+      }
+
+      switch (*NextChar()) {
+        // Allowed esape sequences:
+        case 'x': {  // UTF-8 sequence.
+          // UTF-8 \x escape sequences are not allowed in the spec, but they
+          // are supported here for backwards-compatiblity with the old parser.
+          if (!CanConsume(2)) {
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, 1);
+            return false;
+          }
+
+          int hex_digit = 0;
+          if (!HexStringToInt(StringPiece(NextChar(), 2), &hex_digit)) {
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, -1);
+            return false;
+          }
+          NextChar();
+
+          if (hex_digit < kExtendedASCIIStart)
+            string.Append(hex_digit);
+          else
+            DecodeUTF8(hex_digit, &string);
+          break;
+        }
+        case 'u': {  // UTF-16 sequence.
+          // UTF units are of the form \uXXXX.
+          if (!CanConsume(5)) {  // 5 being 'u' and four HEX digits.
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+            return false;
+          }
+
+          // Skip the 'u'.
+          NextChar();
+
+          std::string utf8_units;
+          if (!DecodeUTF16(&utf8_units)) {
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, -1);
+            return false;
+          }
+
+          string.AppendString(utf8_units);
+          break;
+        }
+        case '"':
+          string.Append('"');
+          break;
+        case '\\':
+          string.Append('\\');
+          break;
+        case '/':
+          string.Append('/');
+          break;
+        case 'b':
+          string.Append('\b');
+          break;
+        case 'f':
+          string.Append('\f');
+          break;
+        case 'n':
+          string.Append('\n');
+          break;
+        case 'r':
+          string.Append('\r');
+          break;
+        case 't':
+          string.Append('\t');
+          break;
+        case 'v':  // Not listed as valid escape sequence in the RFC.
+          string.Append('\v');
+          break;
+        // All other escape squences are illegal.
+        default:
+          ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+          return false;
+      }
+    } else if (next_char == '"') {
+      --index_;  // Rewind by one because of CBU8_NEXT.
+      out->Swap(&string);
+      return true;
+    } else {
+      if (next_char < kExtendedASCIIStart)
+        string.Append(next_char);
+      else
+        DecodeUTF8(next_char, &string);
+    }
+  }
+
+  ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+  return false;
+}
+
+// Entry is at the first X in \uXXXX.
+bool JSONParser::DecodeUTF16(std::string* dest_string) {
+  if (!CanConsume(4))
+    return false;
+
+  // This is a 32-bit field because the shift operations in the
+  // conversion process below cause MSVC to error about "data loss."
+  // This only stores UTF-16 code units, though.
+  // Consume the UTF-16 code unit, which may be a high surrogate.
+  int code_unit16_high = 0;
+  if (!HexStringToInt(StringPiece(pos_, 4), &code_unit16_high))
+    return false;
+
+  // Only add 3, not 4, because at the end of this iteration, the parser has
+  // finished working with the last digit of the UTF sequence, meaning that
+  // the next iteration will advance to the next byte.
+  NextNChars(3);
+
+  // Used to convert the UTF-16 code units to a code point and then to a UTF-8
+  // code unit sequence.
+  char code_unit8[8] = { 0 };
+  size_t offset = 0;
+
+  // If this is a high surrogate, consume the next code unit to get the
+  // low surrogate.
+  if (CBU16_IS_SURROGATE(code_unit16_high)) {
+    // Make sure this is the high surrogate. If not, it's an encoding
+    // error.
+    if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high))
+      return false;
+
+    // Make sure that the token has more characters to consume the
+    // lower surrogate.
+    if (!CanConsume(6))  // 6 being '\' 'u' and four HEX digits.
+      return false;
+    if (*NextChar() != '\\' || *NextChar() != 'u')
+      return false;
+
+    NextChar();  // Read past 'u'.
+    int code_unit16_low = 0;
+    if (!HexStringToInt(StringPiece(pos_, 4), &code_unit16_low))
+      return false;
+
+    NextNChars(3);
+
+    if (!CBU16_IS_TRAIL(code_unit16_low)) {
+      return false;
+    }
+
+    uint32 code_point = CBU16_GET_SUPPLEMENTARY(code_unit16_high,
+                                                code_unit16_low);
+    offset = 0;
+    CBU8_APPEND_UNSAFE(code_unit8, offset, code_point);
+  } else {
+    // Not a surrogate.
+    DCHECK(CBU16_IS_SINGLE(code_unit16_high));
+    CBU8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high);
+  }
+
+  dest_string->append(code_unit8);
+  return true;
+}
+
+void JSONParser::DecodeUTF8(const int32& point, StringBuilder* dest) {
+  // Anything outside of the basic ASCII plane will need to be decoded from
+  // int32 to a multi-byte sequence.
+  if (point < kExtendedASCIIStart) {
+    dest->Append(point);
+  } else {
+    char utf8_units[4] = { 0 };
+    int offset = 0;
+    CBU8_APPEND_UNSAFE(utf8_units, offset, point);
+    dest->Convert();
+    // CBU8_APPEND_UNSAFE can overwrite up to 4 bytes, so utf8_units may not be
+    // zero terminated at this point.  |offset| contains the correct length.
+    dest->AppendString(std::string(utf8_units, offset));
+  }
+}
+
+Value* JSONParser::ConsumeNumber() {
+  const char* num_start = pos_;
+  const int start_index = index_;
+  int end_index = start_index;
+
+  if (*pos_ == '-')
+    NextChar();
+
+  if (!ReadInt(false)) {
+    ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+    return NULL;
+  }
+  end_index = index_;
+
+  // The optional fraction part.
+  if (*pos_ == '.') {
+    if (!CanConsume(1)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+    NextChar();
+    if (!ReadInt(true)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+    end_index = index_;
+  }
+
+  // Optional exponent part.
+  if (*pos_ == 'e' || *pos_ == 'E') {
+    NextChar();
+    if (*pos_ == '-' || *pos_ == '+')
+      NextChar();
+    if (!ReadInt(true)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+    end_index = index_;
+  }
+
+  // ReadInt is greedy because numbers have no easily detectable sentinel,
+  // so save off where the parser should be on exit (see Consume invariant at
+  // the top of the header), then make sure the next token is one which is
+  // valid.
+  const char* exit_pos = pos_ - 1;
+  int exit_index = index_ - 1;
+
+  switch (GetNextToken()) {
+    case T_OBJECT_END:
+    case T_ARRAY_END:
+    case T_LIST_SEPARATOR:
+    case T_END_OF_INPUT:
+      break;
+    default:
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+  }
+
+  pos_ = exit_pos;
+  index_ = exit_index;
+
+  StringPiece num_string(num_start, end_index - start_index);
+
+  int num_int;
+  if (StringToInt(num_string, &num_int))
+    return Value::CreateIntegerValue(num_int);
+
+  double num_double;
+  if (base::StringToDouble(num_string.as_string(), &num_double) &&
+      IsFinite(num_double)) {
+    return Value::CreateDoubleValue(num_double);
+  }
+
+  return NULL;
+}
+
+bool JSONParser::ReadInt(bool allow_leading_zeros) {
+  char first = *pos_;
+  int len = 0;
+
+  char c = first;
+  while (CanConsume(1) && IsAsciiDigit(c)) {
+    c = *NextChar();
+    ++len;
+  }
+
+  if (len == 0)
+    return false;
+
+  if (!allow_leading_zeros && len > 1 && first == '0')
+    return false;
+
+  return true;
+}
+
+Value* JSONParser::ConsumeLiteral() {
+  switch (*pos_) {
+    case 't': {
+      const char* kTrueLiteral = "true";
+      const int kTrueLen = static_cast<int>(strlen(kTrueLiteral));
+      if (!CanConsume(kTrueLen - 1) ||
+          !StringsAreEqual(pos_, kTrueLiteral, kTrueLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kTrueLen - 1);
+      return Value::CreateBooleanValue(true);
+    }
+    case 'f': {
+      const char* kFalseLiteral = "false";
+      const int kFalseLen = static_cast<int>(strlen(kFalseLiteral));
+      if (!CanConsume(kFalseLen - 1) ||
+          !StringsAreEqual(pos_, kFalseLiteral, kFalseLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kFalseLen - 1);
+      return Value::CreateBooleanValue(false);
+    }
+    case 'n': {
+      const char* kNullLiteral = "null";
+      const int kNullLen = static_cast<int>(strlen(kNullLiteral));
+      if (!CanConsume(kNullLen - 1) ||
+          !StringsAreEqual(pos_, kNullLiteral, kNullLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kNullLen - 1);
+      return Value::CreateNullValue();
+    }
+    default:
+      ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+      return NULL;
+  }
+}
+
+// static
+bool JSONParser::StringsAreEqual(const char* one, const char* two, size_t len) {
+  return strncmp(one, two, len) == 0;
+}
+
+void JSONParser::ReportError(JSONReader::JsonParseError code,
+                             int column_adjust) {
+  error_code_ = code;
+  error_line_ = line_number_;
+  error_column_ = index_ - index_last_line_ + column_adjust;
+}
+
+// static
+std::string JSONParser::FormatErrorMessage(int line, int column,
+                                           const std::string& description) {
+  if (line || column) {
+    return StringPrintf("Line: %i, column: %i, %s",
+        line, column, description.c_str());
+  }
+  return description;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/json/json_parser.h b/base/json/json_parser.h
new file mode 100644
index 0000000..020ac25
--- /dev/null
+++ b/base/json/json_parser.h
@@ -0,0 +1,271 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_JSON_JSON_PARSER_H_
+#define BASE_JSON_JSON_PARSER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/json/json_reader.h"
+#include "base/string_piece.h"
+
+#if !defined(OS_CHROMEOS)
+#include "base/gtest_prod_util.h"
+#endif
+
+namespace base {
+class Value;
+}
+
+#if defined(OS_CHROMEOS)
+// Chromium and Chromium OS check out gtest to different places, so this is
+// unable to compile on both if gtest_prod.h is included here. Instead, include
+// its only contents -- this will need to be updated if the macro ever changes.
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \
+  FRIEND_TEST(test_case_name, test_name); \
+  FRIEND_TEST(test_case_name, DISABLED_##test_name); \
+  FRIEND_TEST(test_case_name, FLAKY_##test_name)
+#endif  // OS_CHROMEOS
+
+namespace base {
+namespace internal {
+
+class JSONParserTest;
+
+// The implementation behind the JSONReader interface. This class is not meant
+// to be used directly; it encapsulates logic that need not be exposed publicly.
+//
+// This parser guarantees O(n) time through the input string. It also optimizes
+// base::StringValue by using StringPiece where possible when returning Value
+// objects by using "hidden roots," discussed in the implementation.
+//
+// Iteration happens on the byte level, with the functions CanConsume and
+// NextChar. The conversion from byte to JSON token happens without advancing
+// the parser in GetNextToken/ParseToken, that is tokenization operates on
+// the current parser position without advancing.
+//
+// Built on top of these are a family of Consume functions that iterate
+// internally. Invariant: on entry of a Consume function, the parser is wound
+// to the first byte of a valid JSON token. On exit, it is on the last byte
+// of a token, such that the next iteration of the parser will be at the byte
+// immediately following the token, which would likely be the first byte of the
+// next token.
+class BASE_EXPORT_PRIVATE JSONParser {
+ public:
+  explicit JSONParser(int options);
+  ~JSONParser();
+
+  // Parses the input string according to the set options and returns the
+  // result as a Value owned by the caller.
+  Value* Parse(const StringPiece& input);
+
+  // Returns the error code.
+  JSONReader::JsonParseError error_code() const;
+
+  // Returns the human-friendly error message.
+  std::string GetErrorMessage() const;
+
+ private:
+  enum Token {
+    T_OBJECT_BEGIN,           // {
+    T_OBJECT_END,             // }
+    T_ARRAY_BEGIN,            // [
+    T_ARRAY_END,              // ]
+    T_STRING,
+    T_NUMBER,
+    T_BOOL_TRUE,              // true
+    T_BOOL_FALSE,             // false
+    T_NULL,                   // null
+    T_LIST_SEPARATOR,         // ,
+    T_OBJECT_PAIR_SEPARATOR,  // :
+    T_END_OF_INPUT,
+    T_INVALID_TOKEN,
+  };
+
+  // A helper class used for parsing strings. One optimization performed is to
+  // create base::Value with a StringPiece to avoid unnecessary std::string
+  // copies. This is not possible if the input string needs to be decoded from
+  // UTF-16 to UTF-8, or if an escape sequence causes characters to be skipped.
+  // This class centralizes that logic.
+  class StringBuilder {
+   public:
+    // Empty constructor. Used for creating a builder with which to Swap().
+    StringBuilder();
+
+    // |pos| is the beginning of an input string, excluding the |"|.
+    explicit StringBuilder(const char* pos);
+
+    ~StringBuilder();
+
+    // Swaps the contents of |other| with this.
+    void Swap(StringBuilder* other);
+
+    // Either increases the |length_| of the string or copies the character if
+    // the StringBuilder has been converted. |c| must be in the basic ASCII
+    // plane; all other characters need to be in UTF-8 units, appended with
+    // AppendString below.
+    void Append(const char& c);
+
+    // Appends a string to the std::string. Must be Convert()ed to use.
+    void AppendString(const std::string& str);
+
+    // Converts the builder from its default StringPiece to a full std::string,
+    // performing a copy. Once a builder is converted, it cannot be made a
+    // StringPiece again.
+    void Convert();
+
+    // Returns whether the builder can be converted to a StringPiece.
+    bool CanBeStringPiece() const;
+
+    // Returns the StringPiece representation. Returns an empty piece if it
+    // cannot be converted.
+    StringPiece AsStringPiece();
+
+    // Returns the builder as a std::string.
+    const std::string& AsString();
+
+   private:
+    // The beginning of the input string.
+    const char* pos_;
+
+    // Number of bytes in |pos_| that make up the string being built.
+    size_t length_;
+
+    // The copied string representation. NULL until Convert() is called.
+    // Strong. scoped_ptr<T> has too much of an overhead here.
+    std::string* string_;
+  };
+
+  // Quick check that the stream has capacity to consume |length| more bytes.
+  bool CanConsume(int length);
+
+  // The basic way to consume a single character in the stream. Consumes one
+  // byte of the input stream and returns a pointer to the rest of it.
+  const char* NextChar();
+
+  // Performs the equivalent of NextChar N times.
+  void NextNChars(int n);
+
+  // Skips over whitespace and comments to find the next token in the stream.
+  // This does not advance the parser for non-whitespace or comment chars.
+  Token GetNextToken();
+
+  // Consumes whitespace characters and comments until the next non-that is
+  // encountered.
+  void EatWhitespaceAndComments();
+  // Helper function that consumes a comment, assuming that the parser is
+  // currently wound to a '/'.
+  bool EatComment();
+
+  // Calls GetNextToken() and then ParseToken(). Caller owns the result.
+  Value* ParseNextToken();
+
+  // Takes a token that represents the start of a Value ("a structural token"
+  // in RFC terms) and consumes it, returning the result as an object the
+  // caller owns.
+  Value* ParseToken(Token token);
+
+  // Assuming that the parser is currently wound to '{', this parses a JSON
+  // object into a DictionaryValue.
+  Value* ConsumeDictionary();
+
+  // Assuming that the parser is wound to '[', this parses a JSON list into a
+  // ListValue.
+  Value* ConsumeList();
+
+  // Calls through ConsumeStringRaw and wraps it in a value.
+  Value* ConsumeString();
+
+  // Assuming that the parser is wound to a double quote, this parses a string,
+  // decoding any escape sequences and converts UTF-16 to UTF-8. Returns true on
+  // success and Swap()s the result into |out|. Returns false on failure with
+  // error information set.
+  bool ConsumeStringRaw(StringBuilder* out);
+  // Helper function for ConsumeStringRaw() that consumes the next four or 10
+  // bytes (parser is wound to the first character of a HEX sequence, with the
+  // potential for consuming another \uXXXX for a surrogate). Returns true on
+  // success and places the UTF8 code units in |dest_string|, and false on
+  // failure.
+  bool DecodeUTF16(std::string* dest_string);
+  // Helper function for ConsumeStringRaw() that takes a single code point,
+  // decodes it into UTF-8 units, and appends it to the given builder. The
+  // point must be valid.
+  void DecodeUTF8(const int32& point, StringBuilder* dest);
+
+  // Assuming that the parser is wound to the start of a valid JSON number,
+  // this parses and converts it to either an int or double value.
+  Value* ConsumeNumber();
+  // Helper that reads characters that are ints. Returns true if a number was
+  // read and false on error.
+  bool ReadInt(bool allow_leading_zeros);
+
+  // Consumes the literal values of |true|, |false|, and |null|, assuming the
+  // parser is wound to the first character of any of those.
+  Value* ConsumeLiteral();
+
+  // Compares two string buffers of a given length.
+  static bool StringsAreEqual(const char* left, const char* right, size_t len);
+
+  // Sets the error information to |code| at the current column, based on
+  // |index_| and |index_last_line_|, with an optional positive/negative
+  // adjustment by |column_adjust|.
+  void ReportError(JSONReader::JsonParseError code, int column_adjust);
+
+  // Given the line and column number of an error, formats one of the error
+  // message contants from json_reader.h for human display.
+  static std::string FormatErrorMessage(int line, int column,
+                                        const std::string& description);
+
+  // base::JSONParserOptions that control parsing.
+  int options_;
+
+  // Pointer to the start of the input data.
+  const char* start_pos_;
+
+  // Pointer to the current position in the input data. Equivalent to
+  // |start_pos_ + index_|.
+  const char* pos_;
+
+  // Pointer to the last character of the input data.
+  const char* end_pos_;
+
+  // The index in the input stream to which the parser is wound.
+  int index_;
+
+  // The number of times the parser has recursed (current stack depth).
+  int stack_depth_;
+
+  // The line number that the parser is at currently.
+  int line_number_;
+
+  // The last value of |index_| on the previous line.
+  int index_last_line_;
+
+  // Error information.
+  JSONReader::JsonParseError error_code_;
+  int error_line_;
+  int error_column_;
+
+  friend class JSONParserTest;
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, NextChar);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeDictionary);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeList);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeString);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeLiterals);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeNumbers);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ErrorMessages);
+
+  DISALLOW_COPY_AND_ASSIGN(JSONParser);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_PARSER_H_
diff --git a/base/json/json_parser_unittest.cc b/base/json/json_parser_unittest.cc
new file mode 100644
index 0000000..8ee886b
--- /dev/null
+++ b/base/json/json_parser_unittest.cc
@@ -0,0 +1,306 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_parser.h"
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace internal {
+
+class JSONParserTest : public testing::Test {
+ public:
+  JSONParser* NewTestParser(const std::string& input) {
+    JSONParser* parser = new JSONParser(JSON_PARSE_RFC);
+    parser->start_pos_ = input.data();
+    parser->pos_ = parser->start_pos_;
+    parser->end_pos_ = parser->start_pos_ + input.length();
+    return parser;
+  }
+
+  void TestLastThree(JSONParser* parser) {
+    EXPECT_EQ(',', *parser->NextChar());
+    EXPECT_EQ('|', *parser->NextChar());
+    EXPECT_EQ('\0', *parser->NextChar());
+    EXPECT_EQ(parser->end_pos_, parser->pos_);
+  }
+};
+
+TEST_F(JSONParserTest, NextChar) {
+  std::string input("Hello world");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+
+  EXPECT_EQ('H', *parser->pos_);
+  for (size_t i = 1; i < input.length(); ++i) {
+    EXPECT_EQ(input[i], *parser->NextChar());
+  }
+  EXPECT_EQ(parser->end_pos_, parser->NextChar());
+}
+
+TEST_F(JSONParserTest, ConsumeString) {
+  std::string input("\"test\",|");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+  scoped_ptr<Value> value(parser->ConsumeString());
+  EXPECT_EQ('"', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  std::string str;
+  EXPECT_TRUE(value->GetAsString(&str));
+  EXPECT_EQ("test", str);
+}
+
+TEST_F(JSONParserTest, ConsumeList) {
+  std::string input("[true, false],|");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+  scoped_ptr<Value> value(parser->ConsumeList());
+  EXPECT_EQ(']', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  base::ListValue* list;
+  EXPECT_TRUE(value->GetAsList(&list));
+  EXPECT_EQ(2u, list->GetSize());
+}
+
+TEST_F(JSONParserTest, ConsumeDictionary) {
+  std::string input("{\"abc\":\"def\"},|");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+  scoped_ptr<Value> value(parser->ConsumeDictionary());
+  EXPECT_EQ('}', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  base::DictionaryValue* dict;
+  EXPECT_TRUE(value->GetAsDictionary(&dict));
+  std::string str;
+  EXPECT_TRUE(dict->GetString("abc", &str));
+  EXPECT_EQ("def", str);
+}
+
+TEST_F(JSONParserTest, ConsumeLiterals) {
+  // Literal |true|.
+  std::string input("true,|");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+  scoped_ptr<Value> value(parser->ConsumeLiteral());
+  EXPECT_EQ('e', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  bool bool_value = false;
+  EXPECT_TRUE(value->GetAsBoolean(&bool_value));
+  EXPECT_TRUE(bool_value);
+
+  // Literal |false|.
+  input = "false,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeLiteral());
+  EXPECT_EQ('e', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->GetAsBoolean(&bool_value));
+  EXPECT_FALSE(bool_value);
+
+  // Literal |null|.
+  input = "null,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeLiteral());
+  EXPECT_EQ('l', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->IsType(Value::TYPE_NULL));
+}
+
+TEST_F(JSONParserTest, ConsumeNumbers) {
+  // Integer.
+  std::string input("1234,|");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+  scoped_ptr<Value> value(parser->ConsumeNumber());
+  EXPECT_EQ('4', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  int number_i;
+  EXPECT_TRUE(value->GetAsInteger(&number_i));
+  EXPECT_EQ(1234, number_i);
+
+  // Negative integer.
+  input = "-1234,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeNumber());
+  EXPECT_EQ('4', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->GetAsInteger(&number_i));
+  EXPECT_EQ(-1234, number_i);
+
+  // Double.
+  input = "12.34,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeNumber());
+  EXPECT_EQ('4', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  double number_d;
+  EXPECT_TRUE(value->GetAsDouble(&number_d));
+  EXPECT_EQ(12.34, number_d);
+
+  // Scientific.
+  input = "42e3,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeNumber());
+  EXPECT_EQ('3', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->GetAsDouble(&number_d));
+  EXPECT_EQ(42000, number_d);
+
+  // Negative scientific.
+  input = "314159e-5,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeNumber());
+  EXPECT_EQ('5', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->GetAsDouble(&number_d));
+  EXPECT_EQ(3.14159, number_d);
+
+  // Positive scientific.
+  input = "0.42e+3,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeNumber());
+  EXPECT_EQ('3', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->GetAsDouble(&number_d));
+  EXPECT_EQ(420, number_d);
+}
+
+TEST_F(JSONParserTest, ErrorMessages) {
+  // Error strings should not be modified in case of success.
+  std::string error_message;
+  int error_code = 0;
+  scoped_ptr<Value> root;
+  root.reset(JSONReader::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.reset(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);
+
+  // Test each of the error conditions
+  root.reset(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.reset(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.reset(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.reset(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.reset(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.reset(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.reset(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.reset(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.reset(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;
+  scoped_ptr<Value> root(
+      JSONReader::ReadAndReturnError(kUtf8Data, JSON_PARSE_RFC, &error_code,
+                                     &error_message));
+  EXPECT_TRUE(root.get()) << error_message;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
new file mode 100644
index 0000000..593273e
--- /dev/null
+++ b/base/json/json_reader.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/json/json_reader.h"
+
+#include "base/json/json_parser.h"
+#include "base/logging.h"
+
+namespace base {
+
+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()
+    : parser_(new internal::JSONParser(JSON_PARSE_RFC)) {
+}
+
+JSONReader::JSONReader(int options)
+    : parser_(new internal::JSONParser(options)) {
+}
+
+JSONReader::~JSONReader() {
+}
+
+// static
+Value* JSONReader::Read(const StringPiece& json) {
+  internal::JSONParser parser(JSON_PARSE_RFC);
+  return parser.Parse(json);
+}
+
+// static
+Value* JSONReader::Read(const StringPiece& json,
+                        int options) {
+  internal::JSONParser parser(options);
+  return parser.Parse(json);
+}
+
+// static
+Value* JSONReader::ReadAndReturnError(const StringPiece& json,
+                                      int options,
+                                      int* error_code_out,
+                                      std::string* error_msg_out) {
+  internal::JSONParser parser(options);
+  Value* root = parser.Parse(json);
+  if (root)
+    return root;
+
+  if (error_code_out)
+    *error_code_out = parser.error_code();
+  if (error_msg_out)
+    *error_msg_out = parser.GetErrorMessage();
+
+  return NULL;
+}
+
+// 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();
+  }
+}
+
+Value* JSONReader::ReadToValue(const std::string& 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/base/json/json_reader.h b/base/json/json_reader.h
new file mode 100644
index 0000000..86b2612
--- /dev/null
+++ b/base/json/json_reader.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A JSON parser.  Converts strings of JSON into a Value object (see
+// base/values.h).
+// http://www.ietf.org/rfc/rfc4627.txt?number=4627
+//
+// Known limitations/deviations from the RFC:
+// - Only knows how to parse ints within the range of a signed 32 bit int and
+//   decimal numbers within a double.
+// - Assumes input is encoded as UTF8.  The spec says we should allow UTF-16
+//   (BE or LE) and UTF-32 (BE or LE) as well.
+// - We limit nesting to 100 levels to prevent stack overflow (this is allowed
+//   by the RFC).
+// - A Unicode FAQ ("http://unicode.org/faq/utf_bom.html") writes a data
+//   stream may start with a Unicode Byte-Order-Mark (U+FEFF), i.e. the input
+//   UTF-8 string for the JSONReader::JsonToValue() function may start with a
+//   UTF-8 BOM (0xEF, 0xBB, 0xBF).
+//   To avoid the function from mis-treating a UTF-8 BOM as an invalid
+//   character, the function skips a Unicode BOM at the beginning of the
+//   Unicode string (converted from the input UTF-8 string) before parsing it.
+//
+// TODO(tc): Add a parsing option to to relax object keys being wrapped in
+//   double quotes
+// TODO(tc): Add an option to disable comment stripping
+
+#ifndef BASE_JSON_JSON_READER_H_
+#define BASE_JSON_JSON_READER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/string_piece.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class Value;
+
+namespace internal {
+class JSONParser;
+}
+}
+
+namespace base {
+
+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,
+  };
+
+  // String versions of parse error codes.
+  static const char* kInvalidEscape;
+  static const char* kSyntaxError;
+  static const char* kUnexpectedToken;
+  static const char* kTrailingComma;
+  static const char* kTooMuchNesting;
+  static const char* kUnexpectedDataAfterRoot;
+  static const char* kUnsupportedEncoding;
+  static const char* kUnquotedDictionaryKey;
+
+  // Constructs a reader with the default options, JSON_PARSE_RFC.
+  JSONReader();
+
+  // Constructs a reader with custom options.
+  explicit JSONReader(int options);
+
+  ~JSONReader();
+
+  // Reads and parses |json|, returning a Value. The caller owns the returned
+  // instance. If |json| is not a properly formed JSON string, returns NULL.
+  static Value* Read(const StringPiece& json);
+
+  // Reads and parses |json|, returning a Value owned by the caller. The
+  // parser respects the given |options|. If the input is not properly formed,
+  // returns NULL.
+  static Value* Read(const StringPiece& json, int options);
+
+  // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
+  // are optional. If specified and NULL is returned, they will be populated
+  // an error code and a formatted error message (including error location if
+  // appropriate). Otherwise, they will be unmodified.
+  static Value* ReadAndReturnError(const StringPiece& json,
+                                   int options,  // JSONParserOptions
+                                   int* error_code_out,
+                                   std::string* error_msg_out);
+
+  // Converts a JSON parse error code into a human readable message.
+  // Returns an empty string if error_code is JSON_NO_ERROR.
+  static std::string ErrorCodeToString(JsonParseError error_code);
+
+  // Parses an input string into a Value that is owned by the caller.
+  Value* ReadToValue(const std::string& json);
+
+  // Returns the error code if the last call to ReadToValue() failed.
+  // Returns JSON_NO_ERROR otherwise.
+  JsonParseError error_code() const;
+
+  // Converts error_code_ to a human-readable string, including line and column
+  // numbers if appropriate.
+  std::string GetErrorMessage() const;
+
+ private:
+  scoped_ptr<internal::JSONParser> parser_;
+};
+
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_READER_H_
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
new file mode 100644
index 0000000..38bf590
--- /dev/null
+++ b/base/json/json_reader_unittest.cc
@@ -0,0 +1,648 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_reader.h"
+
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(JSONReaderTest, Reading) {
+  // some whitespace checking
+  scoped_ptr<Value> root;
+  root.reset(JSONReader().ReadToValue("   null   "));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+
+  // Invalid JSON string
+  root.reset(JSONReader().ReadToValue("nu"));
+  EXPECT_FALSE(root.get());
+
+  // Simple bool
+  root.reset(JSONReader().ReadToValue("true  "));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN));
+
+  // Embedded comment
+  root.reset(JSONReader().ReadToValue("/* comment */null"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+  root.reset(JSONReader().ReadToValue("40 /* comment */"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+  root.reset(JSONReader().ReadToValue("true // comment"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN));
+  root.reset(JSONReader().ReadToValue("/* comment */\"sample string\""));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  std::string value;
+  EXPECT_TRUE(root->GetAsString(&value));
+  EXPECT_EQ("sample string", value);
+  root.reset(JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]"));
+  ASSERT_TRUE(root.get());
+  ListValue* list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(2u, list->GetSize());
+  int int_val = 0;
+  EXPECT_TRUE(list->GetInteger(0, &int_val));
+  EXPECT_EQ(1, int_val);
+  EXPECT_TRUE(list->GetInteger(1, &int_val));
+  EXPECT_EQ(3, int_val);
+  root.reset(JSONReader().ReadToValue("[1, /*a*/2, 3]"));
+  ASSERT_TRUE(root.get());
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(3u, list->GetSize());
+
+  // Test number formats
+  root.reset(JSONReader().ReadToValue("43"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+  EXPECT_TRUE(root->GetAsInteger(&int_val));
+  EXPECT_EQ(43, int_val);
+
+  // According to RFC4627, oct, hex, and leading zeros are invalid JSON.
+  root.reset(JSONReader().ReadToValue("043"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("0x43"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("00"));
+  EXPECT_FALSE(root.get());
+
+  // Test 0 (which needs to be special cased because of the leading zero
+  // clause).
+  root.reset(JSONReader().ReadToValue("0"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+  int_val = 1;
+  EXPECT_TRUE(root->GetAsInteger(&int_val));
+  EXPECT_EQ(0, int_val);
+
+  // Numbers that overflow ints should succeed, being internally promoted to
+  // storage as doubles
+  root.reset(JSONReader().ReadToValue("2147483648"));
+  ASSERT_TRUE(root.get());
+  double double_val;
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(2147483648.0, double_val);
+  root.reset(JSONReader().ReadToValue("-2147483649"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(-2147483649.0, double_val);
+
+  // Parse a double
+  root.reset(JSONReader().ReadToValue("43.1"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(43.1, double_val);
+
+  root.reset(JSONReader().ReadToValue("4.3e-1"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(.43, double_val);
+
+  root.reset(JSONReader().ReadToValue("2.1e0"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(2.1, double_val);
+
+  root.reset(JSONReader().ReadToValue("2.1e+0001"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(21.0, double_val);
+
+  root.reset(JSONReader().ReadToValue("0.01"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(0.01, double_val);
+
+  root.reset(JSONReader().ReadToValue("1.00"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(1.0, double_val);
+
+  // Fractional parts must have a digit before and after the decimal point.
+  root.reset(JSONReader().ReadToValue("1."));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue(".1"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("1.e10"));
+  EXPECT_FALSE(root.get());
+
+  // Exponent must have a digit following the 'e'.
+  root.reset(JSONReader().ReadToValue("1e"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("1E"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("1e1."));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("1e1.0"));
+  EXPECT_FALSE(root.get());
+
+  // INF/-INF/NaN are not valid
+  root.reset(JSONReader().ReadToValue("1e1000"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("-1e1000"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("NaN"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("nan"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("inf"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid number formats
+  root.reset(JSONReader().ReadToValue("4.3.1"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("4e3.1"));
+  EXPECT_FALSE(root.get());
+
+  // Test string parser
+  root.reset(JSONReader().ReadToValue("\"hello world\""));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  std::string str_val;
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ("hello world", str_val);
+
+  // Empty string
+  root.reset(JSONReader().ReadToValue("\"\""));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ("", str_val);
+
+  // Test basic string escapes
+  root.reset(JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\""));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ(" \"\\/\b\f\n\r\t\v", str_val);
+
+  // Test hex and unicode escapes including the null character.
+  root.reset(JSONReader().ReadToValue("\"\\x41\\x00\\u1234\""));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ(std::wstring(L"A\0\x1234", 3), UTF8ToWide(str_val));
+
+  // Test invalid strings
+  root.reset(JSONReader().ReadToValue("\"no closing quote"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("\"\\z invalid escape char\""));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("\"\\xAQ invalid hex code\""));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("not enough hex chars\\x1\""));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("\"not enough escape chars\\u123\""));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("\"extra backslash at end of input\\\""));
+  EXPECT_FALSE(root.get());
+
+  // Basic array
+  root.reset(JSONReader::Read("[true, false, null]"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(3U, list->GetSize());
+
+  // Test with trailing comma.  Should be parsed the same as above.
+  scoped_ptr<Value> root2;
+  root2.reset(JSONReader::Read("[true, false, null, ]",
+                               JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  // Empty array
+  root.reset(JSONReader::Read("[]"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(0U, list->GetSize());
+
+  // Nested arrays
+  root.reset(JSONReader::Read("[[true], [], [false, [], [null]], null]"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(4U, list->GetSize());
+
+  // Lots of trailing commas.
+  root2.reset(JSONReader::Read("[[true], [], [false, [], [null, ]  , ], null,]",
+                               JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  // Invalid, missing close brace.
+  root.reset(JSONReader::Read("[[true], [], [false, [], [null]], null"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, too many commas
+  root.reset(JSONReader::Read("[true,, null]"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::Read("[true,, null]", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, no commas
+  root.reset(JSONReader::Read("[true null]"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, trailing comma
+  root.reset(JSONReader::Read("[true,]"));
+  EXPECT_FALSE(root.get());
+
+  // Valid if we set |allow_trailing_comma| to true.
+  root.reset(JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(1U, list->GetSize());
+  Value* tmp_value = NULL;
+  ASSERT_TRUE(list->Get(0, &tmp_value));
+  EXPECT_TRUE(tmp_value->IsType(Value::TYPE_BOOLEAN));
+  bool bool_value = false;
+  EXPECT_TRUE(tmp_value->GetAsBoolean(&bool_value));
+  EXPECT_TRUE(bool_value);
+
+  // Don't allow empty elements, even if |allow_trailing_comma| is
+  // true.
+  root.reset(JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::Read("[true,,]", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::Read("[,true,]", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+
+  // Test objects
+  root.reset(JSONReader::Read("{}"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+
+  root.reset(JSONReader::Read(
+      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+  DictionaryValue* dict_val = static_cast<DictionaryValue*>(root.get());
+  double_val = 0.0;
+  EXPECT_TRUE(dict_val->GetDouble("number", &double_val));
+  EXPECT_DOUBLE_EQ(9.87654321, double_val);
+  Value* null_val = NULL;
+  ASSERT_TRUE(dict_val->Get("null", &null_val));
+  EXPECT_TRUE(null_val->IsType(Value::TYPE_NULL));
+  str_val.clear();
+  EXPECT_TRUE(dict_val->GetString("S", &str_val));
+  EXPECT_EQ("str", str_val);
+
+  root2.reset(JSONReader::Read(
+      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }",
+      JSON_ALLOW_TRAILING_COMMAS));
+  ASSERT_TRUE(root2.get());
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  // Test newline equivalence.
+  root2.reset(JSONReader::Read(
+      "{\n"
+      "  \"number\":9.87654321,\n"
+      "  \"null\":null,\n"
+      "  \"\\x53\":\"str\",\n"
+      "}\n", JSON_ALLOW_TRAILING_COMMAS));
+  ASSERT_TRUE(root2.get());
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  root2.reset(JSONReader::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.get());
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  // Test nesting
+  root.reset(JSONReader::Read(
+      "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+  dict_val = static_cast<DictionaryValue*>(root.get());
+  DictionaryValue* inner_dict = NULL;
+  ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict));
+  ListValue* inner_array = NULL;
+  ASSERT_TRUE(inner_dict->GetList("array", &inner_array));
+  EXPECT_EQ(1U, inner_array->GetSize());
+  bool_value = true;
+  EXPECT_TRUE(dict_val->GetBoolean("false", &bool_value));
+  EXPECT_FALSE(bool_value);
+  inner_dict = NULL;
+  EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict));
+
+  root2.reset(JSONReader::Read(
+      "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}",
+      JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  // Test keys with periods
+  root.reset(JSONReader::Read(
+      "{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+  dict_val = static_cast<DictionaryValue*>(root.get());
+  int integer_value = 0;
+  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value));
+  EXPECT_EQ(3, integer_value);
+  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("c", &integer_value));
+  EXPECT_EQ(2, integer_value);
+  inner_dict = NULL;
+  ASSERT_TRUE(dict_val->GetDictionaryWithoutPathExpansion("d.e.f",
+                                                          &inner_dict));
+  EXPECT_EQ(1U, inner_dict->size());
+  EXPECT_TRUE(inner_dict->GetIntegerWithoutPathExpansion("g.h.i.j",
+                                                         &integer_value));
+  EXPECT_EQ(1, integer_value);
+
+  root.reset(JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+  dict_val = static_cast<DictionaryValue*>(root.get());
+  EXPECT_TRUE(dict_val->GetInteger("a.b", &integer_value));
+  EXPECT_EQ(2, integer_value);
+  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value));
+  EXPECT_EQ(1, integer_value);
+
+  // Invalid, no closing brace
+  root.reset(JSONReader::Read("{\"a\": true"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, keys must be quoted
+  root.reset(JSONReader::Read("{foo:true}"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, trailing comma
+  root.reset(JSONReader::Read("{\"a\":true,}"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, too many commas
+  root.reset(JSONReader::Read("{\"a\":true,,\"b\":false}"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::Read("{\"a\":true,,\"b\":false}",
+                              JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, no separator
+  root.reset(JSONReader::Read("{\"a\" \"b\"}"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, lone comma.
+  root.reset(JSONReader::Read("{,}"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::Read("{,}", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::Read("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::Read("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::Read("{\"a\":true,,\"b\":false}",
+                              JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+
+  // Test stack overflow
+  std::string evil(1000000, '[');
+  evil.append(std::string(1000000, ']'));
+  root.reset(JSONReader::Read(evil));
+  EXPECT_FALSE(root.get());
+
+  // A few thousand adjacent lists is fine.
+  std::string not_evil("[");
+  not_evil.reserve(15010);
+  for (int i = 0; i < 5000; ++i) {
+    not_evil.append("[],");
+  }
+  not_evil.append("[]]");
+  root.reset(JSONReader::Read(not_evil));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(5001U, list->GetSize());
+
+  // Test utf8 encoded input
+  root.reset(JSONReader().ReadToValue("\"\xe7\xbd\x91\xe9\xa1\xb5\""));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ(L"\x7f51\x9875", UTF8ToWide(str_val));
+
+  root.reset(JSONReader().ReadToValue(
+      "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+  EXPECT_TRUE(root->GetAsDictionary(&dict_val));
+  EXPECT_TRUE(dict_val->GetString("path", &str_val));
+  EXPECT_EQ("/tmp/\xC3\xA0\xC3\xA8\xC3\xB2.png", str_val);
+
+  // Test invalid utf8 encoded input
+  root.reset(JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\""));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("\"123\xc0\x81\""));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader().ReadToValue("\"abc\xc0\xae\""));
+  EXPECT_FALSE(root.get());
+
+  // Test utf16 encoded strings.
+  root.reset(JSONReader().ReadToValue("\"\\u20ac3,14\""));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ("\xe2\x82\xac""3,14", str_val);
+
+  root.reset(JSONReader().ReadToValue("\"\\ud83d\\udca9\\ud83d\\udc6c\""));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ("\xf0\x9f\x92\xa9\xf0\x9f\x91\xac", str_val);
+
+  // Test invalid utf16 strings.
+  const char* cases[] = {
+    "\"\\u123\"",  // Invalid scalar.
+    "\"\\ud83d\"",  // Invalid scalar.
+    "\"\\u$%@!\"",  // Invalid scalar.
+    "\"\\uzz89\"",  // Invalid scalar.
+    "\"\\ud83d\\udca\"",  // Invalid lower surrogate.
+    "\"\\ud83d\\ud83d\"",  // Invalid lower surrogate.
+    "\"\\ud83foo\"",  // No lower surrogate.
+    "\"\\ud83\\foo\""  // No lower surrogate.
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    root.reset(JSONReader().ReadToValue(cases[i]));
+    EXPECT_FALSE(root.get()) << cases[i];
+  }
+
+  // Test literal root objects.
+  root.reset(JSONReader::Read("null"));
+  EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+
+  root.reset(JSONReader::Read("true"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->GetAsBoolean(&bool_value));
+  EXPECT_TRUE(bool_value);
+
+  root.reset(JSONReader::Read("10"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->GetAsInteger(&integer_value));
+  EXPECT_EQ(10, integer_value);
+
+  root.reset(JSONReader::Read("\"root\""));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ("root", str_val);
+}
+
+TEST(JSONReaderTest, ReadFromFile) {
+  FilePath path;
+  ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &path));
+  path = path.Append(FILE_PATH_LITERAL("base"))
+             .Append(FILE_PATH_LITERAL("data"))
+             .Append(FILE_PATH_LITERAL("json"));
+
+  std::string input;
+  ASSERT_TRUE(file_util::ReadFileToString(
+      path.Append(FILE_PATH_LITERAL("bom_feff.json")), &input));
+
+  JSONReader reader;
+  scoped_ptr<Value> root(reader.ReadToValue(input));
+  ASSERT_TRUE(root.get()) << reader.GetErrorMessage();
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+}
+
+// Tests that the root of a JSON object can be deleted safely while its
+// children outlive it.
+TEST(JSONReaderTest, StringOptimizations) {
+  Value* dict_literals[2] = {0};
+  Value* dict_strings[2] = {0};
+  Value* list_values[2] = {0};
+
+  {
+    scoped_ptr<Value> root(JSONReader::Read(
+        "{"
+        "  \"test\": {"
+        "    \"foo\": true,"
+        "    \"bar\": 3.14,"
+        "    \"baz\": \"bat\","
+        "    \"moo\": \"cow\""
+        "  },"
+        "  \"list\": ["
+        "    \"a\","
+        "    \"b\""
+        "  ]"
+        "}", JSON_DETACHABLE_CHILDREN));
+    ASSERT_TRUE(root.get());
+
+    DictionaryValue* root_dict = NULL;
+    ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+
+    DictionaryValue* dict = NULL;
+    ListValue* list = NULL;
+
+    ASSERT_TRUE(root_dict->GetDictionary("test", &dict));
+    ASSERT_TRUE(root_dict->GetList("list", &list));
+
+    EXPECT_TRUE(dict->Remove("foo", &dict_literals[0]));
+    EXPECT_TRUE(dict->Remove("bar", &dict_literals[1]));
+    EXPECT_TRUE(dict->Remove("baz", &dict_strings[0]));
+    EXPECT_TRUE(dict->Remove("moo", &dict_strings[1]));
+
+    ASSERT_EQ(2u, list->GetSize());
+    EXPECT_TRUE(list->Remove(0, &list_values[0]));
+    EXPECT_TRUE(list->Remove(0, &list_values[1]));
+  }
+
+  bool b = false;
+  double d = 0;
+  std::string s;
+
+  EXPECT_TRUE(dict_literals[0]->GetAsBoolean(&b));
+  EXPECT_TRUE(b);
+
+  EXPECT_TRUE(dict_literals[1]->GetAsDouble(&d));
+  EXPECT_EQ(3.14, d);
+
+  EXPECT_TRUE(dict_strings[0]->GetAsString(&s));
+  EXPECT_EQ("bat", s);
+
+  EXPECT_TRUE(dict_strings[1]->GetAsString(&s));
+  EXPECT_EQ("cow", s);
+
+  EXPECT_TRUE(list_values[0]->GetAsString(&s));
+  EXPECT_EQ("a", s);
+  EXPECT_TRUE(list_values[1]->GetAsString(&s));
+  EXPECT_EQ("b", s);
+
+  delete dict_literals[0];
+  delete dict_literals[1];
+  delete dict_strings[0];
+  delete dict_strings[1];
+  delete list_values[0];
+  delete list_values[1];
+}
+
+// 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* invalid_json[] = {
+      "/* test *",
+      "{\"foo\"",
+      "{\"foo\":",
+      "  [",
+      "\"\\u123g\"",
+      "{\n\"eh:\n}",
+  };
+
+  for (size_t i = 0; i < arraysize(invalid_json); ++i) {
+    JSONReader reader;
+    LOG(INFO) << "Sanity test " << i << ": <" << invalid_json[i] << ">";
+    EXPECT_FALSE(reader.ReadToValue(invalid_json[i]));
+    EXPECT_NE(JSONReader::JSON_NO_ERROR, reader.error_code());
+    EXPECT_NE("", reader.GetErrorMessage());
+  }
+}
+
+TEST(JSONReaderTest, IllegalTrailingNull) {
+  const char json[] = { '"', 'n', 'u', 'l', 'l', '"', '\0' };
+  std::string json_string(json, sizeof(json));
+  JSONReader reader;
+  EXPECT_FALSE(reader.ReadToValue(json_string));
+  EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, reader.error_code());
+}
+
+}  // namespace base
diff --git a/base/json/json_string_value_serializer.cc b/base/json/json_string_value_serializer.cc
new file mode 100644
index 0000000..59c0765
--- /dev/null
+++ b/base/json/json_string_value_serializer.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/json/json_string_value_serializer.h"
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+
+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_ || initialized_with_const_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;
+
+  base::JSONWriter::WriteWithOptions(&root, options, json_string_);
+  return true;
+}
+
+Value* JSONStringValueSerializer::Deserialize(int* error_code,
+                                              std::string* error_str) {
+  if (!json_string_)
+    return NULL;
+
+  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/base/json/json_string_value_serializer.h b/base/json/json_string_value_serializer.h
new file mode 100644
index 0000000..8c94dfb
--- /dev/null
+++ b/base/json/json_string_value_serializer.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+#ifndef BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_

+#define BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_

+

+#include <string>

+

+#include "base/base_export.h"

+#include "base/basictypes.h"

+#include "base/file_path.h"

+#include "base/values.h"

+

+class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {

+ public:

+  // json_string is the string that will be source of the deserialization

+  // or the destination of the serialization.  The caller of the constructor

+  // retains ownership of the string.

+  explicit JSONStringValueSerializer(std::string* json_string)

+      : json_string_(json_string),

+        initialized_with_const_string_(false),

+        pretty_print_(false),

+        allow_trailing_comma_(false) {

+  }

+

+  // This version allows initialization with a const string reference for

+  // deserialization only.

+  explicit JSONStringValueSerializer(const std::string& json_string)

+      : json_string_(&const_cast<std::string&>(json_string)),

+        initialized_with_const_string_(true),

+        pretty_print_(false),

+        allow_trailing_comma_(false) {

+  }

+

+  virtual ~JSONStringValueSerializer();

+

+  // 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.

+  virtual bool Serialize(const Value& root) OVERRIDE;

+

+  // Equivalent to Serialize(root) except binary values are omitted from the

+  // output.

+  bool SerializeAndOmitBinaryValues(const Value& root);

+

+  // 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 (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.

+  virtual Value* Deserialize(int* error_code,

+                             std::string* error_message) OVERRIDE;

+

+  void set_pretty_print(bool new_value) { pretty_print_ = new_value; }

+  bool pretty_print() { return pretty_print_; }

+

+  void set_allow_trailing_comma(bool new_value) {

+    allow_trailing_comma_ = new_value;

+  }

+

+ private:

+  bool SerializeInternal(const Value& root, bool omit_binary_values);

+

+  std::string* json_string_;

+  bool initialized_with_const_string_;

+  bool pretty_print_;  // If true, serialization will span multiple lines.

+  // If true, deserialization will allow trailing commas.

+  bool allow_trailing_comma_;

+

+  DISALLOW_COPY_AND_ASSIGN(JSONStringValueSerializer);

+};

+

+#endif  // BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_

+

diff --git a/base/json/json_value_converter.h b/base/json/json_value_converter.h
new file mode 100644
index 0000000..69da0d8
--- /dev/null
+++ b/base/json/json_value_converter.h
@@ -0,0 +1,527 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_JSON_JSON_VALUE_CONVERTER_H_
+#define BASE_JSON_JSON_VALUE_CONVERTER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/stl_util.h"
+#include "base/string16.h"
+#include "base/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) {
+  }
+
+  virtual bool ConvertField(
+      const base::Value& value, StructType* dst) const OVERRIDE {
+    return value_converter_->Convert(value, &(dst->*field_pointer_));
+  }
+
+ private:
+  FieldType StructType::* field_pointer_;
+  scoped_ptr<ValueConverter<FieldType> > value_converter_;
+  DISALLOW_COPY_AND_ASSIGN(FieldConverter);
+};
+
+template <typename FieldType>
+class BasicValueConverter;
+
+template <>
+class BasicValueConverter<int> : public ValueConverter<int> {
+ public:
+  BasicValueConverter() {}
+
+  virtual bool Convert(const base::Value& value, int* field) const OVERRIDE {
+    return value.GetAsInteger(field);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BasicValueConverter<std::string> : public ValueConverter<std::string> {
+ public:
+  BasicValueConverter() {}
+
+  virtual bool Convert(
+      const base::Value& value, std::string* field) const OVERRIDE {
+    return value.GetAsString(field);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BasicValueConverter<string16> : public ValueConverter<string16> {
+ public:
+  BasicValueConverter() {}
+
+  virtual bool Convert(
+      const base::Value& value, string16* field) const OVERRIDE {
+    return value.GetAsString(field);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BasicValueConverter<double> : public ValueConverter<double> {
+ public:
+  BasicValueConverter() {}
+
+  virtual bool Convert(const base::Value& value, double* field) const OVERRIDE {
+    return value.GetAsDouble(field);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BasicValueConverter<bool> : public ValueConverter<bool> {
+ public:
+  BasicValueConverter() {}
+
+  virtual bool Convert(const base::Value& value, bool* field) const OVERRIDE {
+    return value.GetAsBoolean(field);
+  }
+
+ 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) {}
+
+  virtual 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) {}
+
+  virtual 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() {}
+
+  virtual 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() {}
+
+  virtual bool Convert(
+      const base::Value& value, ScopedVector<Element>* field) const OVERRIDE {
+    const base::ListValue* list = NULL;
+    if (!value.GetAsList(&list)) {
+      // The field is not a list.
+      return false;
+    }
+
+    field->reserve(list->GetSize());
+    for (size_t i = 0; i < list->GetSize(); ++i) {
+      const base::Value* element = NULL;
+      if (!list->Get(i, &element))
+        continue;
+
+      scoped_ptr<Element> e(new Element);
+      if (basic_converter_.Convert(*element, e.get())) {
+        field->push_back(e.release());
+      } else {
+        DVLOG(1) << "failure at " << i << "-th element";
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  BasicValueConverter<Element> basic_converter_;
+  DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter);
+};
+
+template <typename NestedType>
+class RepeatedMessageConverter
+    : public ValueConverter<ScopedVector<NestedType> > {
+ public:
+  RepeatedMessageConverter() {}
+
+  virtual bool Convert(const base::Value& value,
+                       ScopedVector<NestedType>* field) const OVERRIDE {
+    const base::ListValue* list = NULL;
+    if (!value.GetAsList(&list))
+      return false;
+
+    field->reserve(list->GetSize());
+    for (size_t i = 0; i < list->GetSize(); ++i) {
+      const base::Value* element = NULL;
+      if (!list->Get(i, &element))
+        continue;
+
+      scoped_ptr<NestedType> nested(new NestedType);
+      if (converter_.Convert(*element, nested.get())) {
+        field->push_back(nested.release());
+      } else {
+        DVLOG(1) << "failure at " << i << "-th element";
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  JSONValueConverter<NestedType> converter_;
+  DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter);
+};
+
+template <typename NestedType>
+class RepeatedCustomValueConverter
+    : public ValueConverter<ScopedVector<NestedType> > {
+ public:
+  typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field);
+
+  RepeatedCustomValueConverter(ConvertFunc convert_func)
+      : convert_func_(convert_func) {}
+
+  virtual bool Convert(const base::Value& value,
+                       ScopedVector<NestedType>* field) const OVERRIDE {
+    const base::ListValue* list = NULL;
+    if (!value.GetAsList(&list))
+      return false;
+
+    field->reserve(list->GetSize());
+    for (size_t i = 0; i < list->GetSize(); ++i) {
+      const base::Value* element = NULL;
+      if (!list->Get(i, &element))
+        continue;
+
+      scoped_ptr<NestedType> nested(new NestedType);
+      if ((*convert_func_)(element, nested.get())) {
+        field->push_back(nested.release());
+      } else {
+        DVLOG(1) << "failure at " << i << "-th element";
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  ConvertFunc convert_func_;
+  DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter);
+};
+
+
+}  // namespace internal
+
+template <class StructType>
+class JSONValueConverter {
+ public:
+  JSONValueConverter() {
+    StructType::RegisterJSONConverter(this);
+  }
+
+  void RegisterIntField(const std::string& field_name,
+                        int StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, int>(
+        field_name, field, new internal::BasicValueConverter<int>));
+  }
+
+  void RegisterStringField(const std::string& field_name,
+                           std::string StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, std::string>(
+        field_name, field, new internal::BasicValueConverter<std::string>));
+  }
+
+  void RegisterStringField(const std::string& field_name,
+                           string16 StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, string16>(
+        field_name, field, new internal::BasicValueConverter<string16>));
+  }
+
+  void RegisterBoolField(const std::string& field_name,
+                         bool StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, bool>(
+        field_name, field, new internal::BasicValueConverter<bool>));
+  }
+
+  void RegisterDoubleField(const std::string& field_name,
+                           double StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, double>(
+        field_name, field, new internal::BasicValueConverter<double>));
+  }
+
+  template <class NestedType>
+  void RegisterNestedField(
+      const std::string& field_name, NestedType StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, NestedType>(
+            field_name,
+            field,
+            new internal::NestedValueConverter<NestedType>));
+  }
+
+  template <typename FieldType>
+  void RegisterCustomField(
+      const std::string& field_name,
+      FieldType StructType::* field,
+      bool (*convert_func)(const StringPiece&, FieldType*)) {
+    fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
+        field_name,
+        field,
+        new internal::CustomFieldConverter<FieldType>(convert_func)));
+  }
+
+  template <typename FieldType>
+  void RegisterCustomValueField(
+      const std::string& field_name,
+      FieldType StructType::* field,
+      bool (*convert_func)(const base::Value*, FieldType*)) {
+    fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
+        field_name,
+        field,
+        new internal::ValueFieldConverter<FieldType>(convert_func)));
+  }
+
+  void RegisterRepeatedInt(const std::string& field_name,
+                           ScopedVector<int> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<int> >(
+            field_name, field, new internal::RepeatedValueConverter<int>));
+  }
+
+  void RegisterRepeatedString(const std::string& field_name,
+                              ScopedVector<std::string> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<std::string> >(
+            field_name,
+            field,
+            new internal::RepeatedValueConverter<std::string>));
+  }
+
+  void RegisterRepeatedString(const std::string& field_name,
+                              ScopedVector<string16> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<string16> >(
+            field_name,
+            field,
+            new internal::RepeatedValueConverter<string16>));
+  }
+
+  void RegisterRepeatedDouble(const std::string& field_name,
+                              ScopedVector<double> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<double> >(
+            field_name, field, new internal::RepeatedValueConverter<double>));
+  }
+
+  void RegisterRepeatedBool(const std::string& field_name,
+                            ScopedVector<bool> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<bool> >(
+            field_name, field, new internal::RepeatedValueConverter<bool>));
+  }
+
+  template <class NestedType>
+  void RegisterRepeatedCustomValue(
+      const std::string& field_name,
+      ScopedVector<NestedType> StructType::* field,
+      bool (*convert_func)(const base::Value*, NestedType*)) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
+            field_name,
+            field,
+            new internal::RepeatedCustomValueConverter<NestedType>(
+                convert_func)));
+  }
+
+  template <class NestedType>
+  void RegisterRepeatedMessage(const std::string& field_name,
+                               ScopedVector<NestedType> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
+            field_name,
+            field,
+            new internal::RepeatedMessageConverter<NestedType>));
+  }
+
+  bool Convert(const base::Value& value, StructType* output) const {
+    const DictionaryValue* dictionary_value = NULL;
+    if (!value.GetAsDictionary(&dictionary_value))
+      return false;
+
+    for(size_t i = 0; i < fields_.size(); ++i) {
+      const internal::FieldConverterBase<StructType>* field_converter =
+          fields_[i];
+      const base::Value* field = NULL;
+      if (dictionary_value->Get(field_converter->field_path(), &field)) {
+        if (!field_converter->ConvertField(*field, output)) {
+          DVLOG(1) << "failure at field " << field_converter->field_path();
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+ private:
+  ScopedVector<internal::FieldConverterBase<StructType> > fields_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONValueConverter);
+};
+
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_VALUE_CONVERTER_H_
diff --git a/base/json/json_value_converter_unittest.cc b/base/json/json_value_converter_unittest.cc
new file mode 100644
index 0000000..e5ad289
--- /dev/null
+++ b/base/json/json_value_converter_unittest.cc
@@ -0,0 +1,256 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_value_converter.h"
+
+#include <string>
+#include <vector>
+
+#include "base/values.h"
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+// Very simple messages.
+struct SimpleMessage {
+  enum SimpleEnum {
+    FOO, BAR,
+  };
+  int foo;
+  std::string bar;
+  bool baz;
+  bool bstruct;
+  SimpleEnum simple_enum;
+  ScopedVector<int> ints;
+  ScopedVector<std::string> string_values;
+  SimpleMessage() : foo(0), baz(false), bstruct(false), simple_enum(FOO) {}
+
+  static bool ParseSimpleEnum(const StringPiece& value, SimpleEnum* field) {
+    if (value == "foo") {
+      *field = FOO;
+      return true;
+    } else if (value == "bar") {
+      *field = BAR;
+      return true;
+    }
+    return false;
+  }
+
+  static bool HasFieldPresent(const base::Value* value, bool* result) {
+    *result = value != NULL;
+    return true;
+  }
+
+  static bool GetValueString(const base::Value* value, std::string* result) {
+    const base::DictionaryValue* dict = NULL;
+    if (!value->GetAsDictionary(&dict))
+      return false;
+
+    if (!dict->GetString("val", result))
+      return false;
+
+    return true;
+  }
+
+  static void RegisterJSONConverter(
+      base::JSONValueConverter<SimpleMessage>* converter) {
+    converter->RegisterIntField("foo", &SimpleMessage::foo);
+    converter->RegisterStringField("bar", &SimpleMessage::bar);
+    converter->RegisterBoolField("baz", &SimpleMessage::baz);
+    converter->RegisterCustomField<SimpleEnum>(
+        "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum);
+    converter->RegisterRepeatedInt("ints", &SimpleMessage::ints);
+    converter->RegisterCustomValueField<bool>("bstruct",
+                                              &SimpleMessage::bstruct,
+                                              &HasFieldPresent);
+    converter->RegisterRepeatedCustomValue<std::string>(
+        "string_values",
+        &SimpleMessage::string_values,
+        &GetValueString);
+  }
+};
+
+// For nested messages.
+struct NestedMessage {
+  double foo;
+  SimpleMessage child;
+  ScopedVector<SimpleMessage> children;
+
+  NestedMessage() : foo(0) {}
+
+  static void RegisterJSONConverter(
+      base::JSONValueConverter<NestedMessage>* converter) {
+    converter->RegisterDoubleField("foo", &NestedMessage::foo);
+    converter->RegisterNestedField("child", &NestedMessage::child);
+    converter->RegisterRepeatedMessage("children", &NestedMessage::children);
+  }
+};
+
+}  // namespace
+
+TEST(JSONValueConverterTest, ParseSimpleMessage) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": \"bar\",\n"
+      "  \"baz\": true,\n"
+      "  \"bstruct\": {},\n"
+      "  \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}],"
+      "  \"simple_enum\": \"foo\","
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+
+  EXPECT_EQ(1, message.foo);
+  EXPECT_EQ("bar", message.bar);
+  EXPECT_TRUE(message.baz);
+  EXPECT_EQ(SimpleMessage::FOO, message.simple_enum);
+  EXPECT_EQ(2, static_cast<int>(message.ints.size()));
+  ASSERT_EQ(2U, message.string_values.size());
+  EXPECT_EQ("value_1", *message.string_values[0]);
+  EXPECT_EQ("value_2", *message.string_values[1]);
+  EXPECT_EQ(1, *(message.ints[0]));
+  EXPECT_EQ(2, *(message.ints[1]));
+}
+
+TEST(JSONValueConverterTest, ParseNestedMessage) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1.0,\n"
+      "  \"child\": {\n"
+      "    \"foo\": 1,\n"
+      "    \"bar\": \"bar\",\n"
+      "    \"bstruct\": {},\n"
+      "    \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}],"
+      "    \"baz\": true\n"
+      "  },\n"
+      "  \"children\": [{\n"
+      "    \"foo\": 2,\n"
+      "    \"bar\": \"foobar\",\n"
+      "    \"bstruct\": \"\",\n"
+      "    \"string_values\": [{\"val\": \"value_1\"}],"
+      "    \"baz\": true\n"
+      "  },\n"
+      "  {\n"
+      "    \"foo\": 3,\n"
+      "    \"bar\": \"barbaz\",\n"
+      "    \"baz\": false\n"
+      "  }]\n"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  NestedMessage message;
+  base::JSONValueConverter<NestedMessage> converter;
+  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+
+  EXPECT_EQ(1.0, message.foo);
+  EXPECT_EQ(1, message.child.foo);
+  EXPECT_EQ("bar", message.child.bar);
+  EXPECT_TRUE(message.child.baz);
+  EXPECT_TRUE(message.child.bstruct);
+  ASSERT_EQ(2U, message.child.string_values.size());
+  EXPECT_EQ("value_1", *message.child.string_values[0]);
+  EXPECT_EQ("value_2", *message.child.string_values[1]);
+
+  EXPECT_EQ(2, static_cast<int>(message.children.size()));
+  const SimpleMessage* first_child = message.children[0];
+  ASSERT_TRUE(first_child);
+  EXPECT_EQ(2, first_child->foo);
+  EXPECT_EQ("foobar", first_child->bar);
+  EXPECT_TRUE(first_child->baz);
+  EXPECT_TRUE(first_child->bstruct);
+  ASSERT_EQ(1U, first_child->string_values.size());
+  EXPECT_EQ("value_1", *first_child->string_values[0]);
+
+  const SimpleMessage* second_child = message.children[1];
+  ASSERT_TRUE(second_child);
+  EXPECT_EQ(3, second_child->foo);
+  EXPECT_EQ("barbaz", second_child->bar);
+  EXPECT_FALSE(second_child->baz);
+  EXPECT_FALSE(second_child->bstruct);
+  EXPECT_EQ(0U, second_child->string_values.size());
+}
+
+TEST(JSONValueConverterTest, ParseFailures) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": 2,\n" // "bar" is an integer here.
+      "  \"baz\": true,\n"
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  // Do not check the values below.  |message| may be modified during
+  // Convert() even it fails.
+}
+
+TEST(JSONValueConverterTest, ParseWithMissingFields) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"baz\": true,\n"
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  // Convert() still succeeds even if the input doesn't have "bar" field.
+  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+
+  EXPECT_EQ(1, message.foo);
+  EXPECT_TRUE(message.baz);
+  EXPECT_EQ(2, static_cast<int>(message.ints.size()));
+  EXPECT_EQ(1, *(message.ints[0]));
+  EXPECT_EQ(2, *(message.ints[1]));
+}
+
+TEST(JSONValueConverterTest, EnumParserFails) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": \"bar\",\n"
+      "  \"baz\": true,\n"
+      "  \"simple_enum\": \"baz\","
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  // No check the values as mentioned above.
+}
+
+TEST(JSONValueConverterTest, RepeatedValueErrorInTheMiddle) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": \"bar\",\n"
+      "  \"baz\": true,\n"
+      "  \"simple_enum\": \"baz\","
+      "  \"ints\": [1, false]"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  // No check the values as mentioned above.
+}
+
+}  // namespace base
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc
new file mode 100644
index 0000000..89e3e4d
--- /dev/null
+++ b/base/json/json_value_serializer_unittest.cc
@@ -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.
+
+#include <string>
+
+#include "base/file_util.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/memory/scoped_ptr.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Some proper JSON to test with:
+const char kProperJSON[] =
+    "{\n"
+    "   \"compound\": {\n"
+    "      \"a\": 1,\n"
+    "      \"b\": 2\n"
+    "   },\n"
+    "   \"some_String\": \"1337\",\n"
+    "   \"some_int\": 42,\n"
+    "   \"the_list\": [ \"val1\", \"val2\" ]\n"
+    "}\n";
+
+// Some proper JSON with trailing commas:
+const char kProperJSONWithCommas[] =
+    "{\n"
+    "\t\"some_int\": 42,\n"
+    "\t\"some_String\": \"1337\",\n"
+    "\t\"the_list\": [\"val1\", \"val2\", ],\n"
+    "\t\"compound\": { \"a\": 1, \"b\": 2, },\n"
+    "}\n";
+
+const char kWinLineEnds[] = "\r\n";
+const char kLinuxLineEnds[] = "\n";
+
+// Verifies the generated JSON against the expected output.
+void CheckJSONIsStillTheSame(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);
+}
+
+// Test proper JSON [de]serialization from string is working.
+TEST(JSONValueSerializerTest, ReadProperJSONFromString) {
+  // Try to deserialize it through the serializer.
+  std::string proper_json(kProperJSON);
+  JSONStringValueSerializer str_deserializer(proper_json);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(0, error_code);
+  ASSERT_TRUE(error_message.empty());
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test that trialing commas are only properly deserialized from string when
+// the proper flag for that is set.
+TEST(JSONValueSerializerTest, ReadJSONWithTrailingCommasFromString) {
+  // Try to deserialize it through the serializer.
+  std::string proper_json(kProperJSONWithCommas);
+  JSONStringValueSerializer str_deserializer(proper_json);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_FALSE(value.get());
+  ASSERT_NE(0, error_code);
+  ASSERT_FALSE(error_message.empty());
+  // Now the flag is set and it must pass.
+  str_deserializer.set_allow_trailing_comma(true);
+  value.reset(str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test proper JSON [de]serialization from file is working.
+TEST(JSONValueSerializerTest, 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)),
+            file_util::WriteFile(temp_file, kProperJSON, strlen(kProperJSON)));
+
+  // Try to deserialize it through the serializer.
+  JSONFileValueSerializer file_deserializer(temp_file);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      file_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(0, error_code);
+  ASSERT_TRUE(error_message.empty());
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test that trialing commas are only properly deserialized from file when
+// the proper flag for that is set.
+TEST(JSONValueSerializerTest, 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)),
+            file_util::WriteFile(temp_file,
+                                 kProperJSONWithCommas,
+                                 strlen(kProperJSONWithCommas)));
+
+  // Try to deserialize it through the serializer.
+  JSONFileValueSerializer file_deserializer(temp_file);
+  // This must fail without the proper flag.
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      file_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_FALSE(value.get());
+  ASSERT_NE(0, error_code);
+  ASSERT_FALSE(error_message.empty());
+  // Now the flag is set and it must pass.
+  file_deserializer.set_allow_trailing_comma(true);
+  value.reset(file_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+}  // namespace
+
+}  // namespace base
+
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
new file mode 100644
index 0000000..e8cf9ac
--- /dev/null
+++ b/base/json/json_writer.cc
@@ -0,0 +1,236 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_writer.h"
+
+#include <cmath>
+
+#include "base/json/string_escape.h"
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "base/string_number_conversions.h"
+#include "base/values.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+#if defined(OS_WIN)
+static const char kPrettyPrintLineEnding[] = "\r\n";
+#else
+static const char kPrettyPrintLineEnding[] = "\n";
+#endif
+
+/* static */
+const char* JSONWriter::kEmptyArray = "[]";
+
+/* static */
+void JSONWriter::Write(const Value* const node, std::string* json) {
+  WriteWithOptions(node, 0, json);
+}
+
+/* static */
+void JSONWriter::WriteWithOptions(const Value* const node, int options,
+                                  std::string* json) {
+  json->clear();
+  // Is there a better way to estimate the size of the output?
+  json->reserve(1024);
+
+  bool escape = !(options & OPTIONS_DO_NOT_ESCAPE);
+  bool omit_binary_values = !!(options & OPTIONS_OMIT_BINARY_VALUES);
+  bool omit_double_type_preservation =
+      !!(options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION);
+  bool pretty_print = !!(options & OPTIONS_PRETTY_PRINT);
+
+  JSONWriter writer(escape, omit_binary_values, omit_double_type_preservation,
+                    pretty_print, json);
+  writer.BuildJSONString(node, 0);
+
+  if (pretty_print)
+    json->append(kPrettyPrintLineEnding);
+}
+
+JSONWriter::JSONWriter(bool escape, bool omit_binary_values,
+                       bool omit_double_type_preservation, bool pretty_print,
+                       std::string* json)
+    : escape_(escape),
+      omit_binary_values_(omit_binary_values),
+      omit_double_type_preservation_(omit_double_type_preservation),
+      pretty_print_(pretty_print),
+      json_string_(json) {
+  DCHECK(json);
+}
+
+void JSONWriter::BuildJSONString(const Value* const node, int depth) {
+  switch (node->GetType()) {
+    case Value::TYPE_NULL:
+      json_string_->append("null");
+      break;
+
+    case Value::TYPE_BOOLEAN:
+      {
+        bool value;
+        bool result = node->GetAsBoolean(&value);
+        DCHECK(result);
+        json_string_->append(value ? "true" : "false");
+        break;
+      }
+
+    case Value::TYPE_INTEGER:
+      {
+        int value;
+        bool result = node->GetAsInteger(&value);
+        DCHECK(result);
+        base::StringAppendF(json_string_, "%d", value);
+        break;
+      }
+
+    case Value::TYPE_DOUBLE:
+      {
+        double value;
+        bool result = node->GetAsDouble(&value);
+        DCHECK(result);
+        if (omit_double_type_preservation_ &&
+            value <= kint64max &&
+            value >= kint64min &&
+            std::floor(value) == value) {
+          json_string_->append(Int64ToString(static_cast<int64>(value)));
+          break;
+        }
+        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(0, "0");
+        } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
+          // "-.1" bad "-0.1" good
+          real.insert(1, "0");
+        }
+        json_string_->append(real);
+        break;
+      }
+
+    case Value::TYPE_STRING:
+      {
+        std::string value;
+        bool result = node->GetAsString(&value);
+        DCHECK(result);
+        if (escape_) {
+          JsonDoubleQuote(UTF8ToUTF16(value), true, json_string_);
+        } else {
+          JsonDoubleQuote(value, true, json_string_);
+        }
+        break;
+      }
+
+    case Value::TYPE_LIST:
+      {
+        json_string_->append("[");
+        if (pretty_print_)
+          json_string_->append(" ");
+
+        const ListValue* list = static_cast<const ListValue*>(node);
+        for (size_t i = 0; i < list->GetSize(); ++i) {
+          const Value* value = NULL;
+          bool result = list->Get(i, &value);
+          DCHECK(result);
+
+          if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) {
+            continue;
+          }
+
+          if (i != 0) {
+            json_string_->append(",");
+            if (pretty_print_)
+              json_string_->append(" ");
+          }
+
+          BuildJSONString(value, depth);
+        }
+
+        if (pretty_print_)
+          json_string_->append(" ");
+        json_string_->append("]");
+        break;
+      }
+
+    case Value::TYPE_DICTIONARY:
+      {
+        json_string_->append("{");
+        if (pretty_print_)
+          json_string_->append(kPrettyPrintLineEnding);
+
+        const DictionaryValue* dict =
+          static_cast<const DictionaryValue*>(node);
+        for (DictionaryValue::key_iterator key_itr = dict->begin_keys();
+             key_itr != dict->end_keys();
+             ++key_itr) {
+          const Value* value = NULL;
+          bool result = dict->GetWithoutPathExpansion(*key_itr, &value);
+          DCHECK(result);
+
+          if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) {
+            continue;
+          }
+
+          if (key_itr != dict->begin_keys()) {
+            json_string_->append(",");
+            if (pretty_print_)
+              json_string_->append(kPrettyPrintLineEnding);
+          }
+
+          if (pretty_print_)
+            IndentLine(depth + 1);
+          AppendQuotedString(*key_itr);
+          if (pretty_print_) {
+            json_string_->append(": ");
+          } else {
+            json_string_->append(":");
+          }
+          BuildJSONString(value, depth + 1);
+        }
+
+        if (pretty_print_) {
+          json_string_->append(kPrettyPrintLineEnding);
+          IndentLine(depth);
+          json_string_->append("}");
+        } else {
+          json_string_->append("}");
+        }
+        break;
+      }
+
+    case Value::TYPE_BINARY:
+      {
+        if (!omit_binary_values_) {
+          NOTREACHED() << "Cannot serialize binary value.";
+        }
+        break;
+      }
+
+    default:
+      NOTREACHED() << "unknown json type";
+  }
+}
+
+void JSONWriter::AppendQuotedString(const std::string& str) {
+  // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we
+  // have to convert it to UTF-16. This round-trip is suboptimal.
+  JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_);
+}
+
+void JSONWriter::IndentLine(int depth) {
+  // It may be faster to keep an indent string so we don't have to keep
+  // reallocating.
+  json_string_->append(std::string(depth * 3, ' '));
+}
+
+}  // namespace base
diff --git a/base/json/json_writer.h b/base/json/json_writer.h
new file mode 100644
index 0000000..94052c8
--- /dev/null
+++ b/base/json/json_writer.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_JSON_JSON_WRITER_H_
+#define BASE_JSON_JSON_WRITER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class Value;
+
+class BASE_EXPORT JSONWriter {
+ public:
+  enum Options {
+    // Do not escape the string, preserving its UTF8 characters. It is useful
+    // if you can pass the resulting string to the JSON parser in binary form
+    // (as UTF8).
+    OPTIONS_DO_NOT_ESCAPE = 1 << 0,
+
+    // For values of binary type, the value (and key if within a dictionary)
+    // will be omitted from the output.
+    OPTIONS_OMIT_BINARY_VALUES = 1 << 1,
+
+    // 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 << 2,
+
+    // Return a slightly nicer formatted json string (pads with whitespace to
+    // help with readability).
+    OPTIONS_PRETTY_PRINT = 1 << 3
+  };
+
+  // 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)?
+  static void Write(const Value* const node, std::string* json);
+
+  // Same as above but with |options| which is a bunch of JSONWriter::Options
+  // bitwise ORed together.
+  static void WriteWithOptions(const Value* const node, int options,
+                               std::string* json);
+
+  // A static, constant JSON string representing an empty array.  Useful
+  // for empty JSON argument passing.
+  static const char* kEmptyArray;
+
+ private:
+  JSONWriter(bool escape, bool omit_binary_values,
+             bool omit_double_type_preservation, bool pretty_print,
+             std::string* json);
+
+  // Called recursively to build the JSON string.  Whe completed, value is
+  // json_string_ will contain the JSON.
+  void BuildJSONString(const Value* const node, int depth);
+
+  // Appends a quoted, escaped, version of (UTF-8) str to json_string_.
+  void AppendQuotedString(const std::string& str);
+
+  // Adds space to json_string_ for the indent level.
+  void IndentLine(int depth);
+
+  bool escape_;
+  bool omit_binary_values_;
+  bool omit_double_type_preservation_;
+  bool pretty_print_;
+
+  // Where we write JSON data as we generate it.
+  std::string* json_string_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONWriter);
+};
+
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_WRITER_H_
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc
new file mode 100644
index 0000000..c52a1df
--- /dev/null
+++ b/base/json/json_writer_unittest.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_writer.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(JSONWriterTest, Writing) {
+  // Test null
+  Value* root = Value::CreateNullValue();
+  std::string output_js;
+  JSONWriter::Write(root, &output_js);
+  ASSERT_EQ("null", output_js);
+  delete root;
+
+  // Test empty dict
+  root = new DictionaryValue;
+  JSONWriter::Write(root, &output_js);
+  ASSERT_EQ("{}", output_js);
+  delete root;
+
+  // Test empty list
+  root = new ListValue;
+  JSONWriter::Write(root, &output_js);
+  ASSERT_EQ("[]", output_js);
+  delete root;
+
+  // Test Real values should always have a decimal or an 'e'.
+  root = Value::CreateDoubleValue(1.0);
+  JSONWriter::Write(root, &output_js);
+  ASSERT_EQ("1.0", output_js);
+  delete root;
+
+  // Test Real values in the the range (-1, 1) must have leading zeros
+  root = Value::CreateDoubleValue(0.2);
+  JSONWriter::Write(root, &output_js);
+  ASSERT_EQ("0.2", output_js);
+  delete root;
+
+  // Test Real values in the the range (-1, 1) must have leading zeros
+  root = Value::CreateDoubleValue(-0.8);
+  JSONWriter::Write(root, &output_js);
+  ASSERT_EQ("-0.8", output_js);
+  delete root;
+
+  // Writer unittests like empty list/dict nesting,
+  // list list nesting, etc.
+  DictionaryValue root_dict;
+  ListValue* list = new ListValue;
+  root_dict.Set("list", list);
+  DictionaryValue* inner_dict = new DictionaryValue;
+  list->Append(inner_dict);
+  inner_dict->SetInteger("inner int", 10);
+  ListValue* inner_list = new ListValue;
+  list->Append(inner_list);
+  list->Append(Value::CreateBooleanValue(true));
+
+  // Test the pretty-printer.
+  JSONWriter::Write(&root_dict, &output_js);
+  ASSERT_EQ("{\"list\":[{\"inner int\":10},[],true]}", output_js);
+  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
+  ASSERT_EQ("{" JSON_NEWLINE
+            "   \"list\": [ {" JSON_NEWLINE
+            "      \"inner int\": 10" JSON_NEWLINE
+            "   }, [  ], true ]" JSON_NEWLINE
+            "}" JSON_NEWLINE,
+            output_js);
+#undef JSON_NEWLINE
+
+  // Test keys with periods
+  DictionaryValue period_dict;
+  period_dict.SetWithoutPathExpansion("a.b", Value::CreateIntegerValue(3));
+  period_dict.SetWithoutPathExpansion("c", Value::CreateIntegerValue(2));
+  DictionaryValue* period_dict2 = new DictionaryValue;
+  period_dict2->SetWithoutPathExpansion("g.h.i.j",
+                                        Value::CreateIntegerValue(1));
+  period_dict.SetWithoutPathExpansion("d.e.f", period_dict2);
+  JSONWriter::Write(&period_dict, &output_js);
+  ASSERT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
+
+  DictionaryValue period_dict3;
+  period_dict3.Set("a.b", Value::CreateIntegerValue(2));
+  period_dict3.SetWithoutPathExpansion("a.b", Value::CreateIntegerValue(1));
+  JSONWriter::Write(&period_dict3, &output_js);
+  ASSERT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
+
+  // Test omitting binary values.
+  root = BinaryValue::CreateWithCopiedBuffer("asdf", 4);
+  JSONWriter::WriteWithOptions(root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES,
+                               &output_js);
+  ASSERT_TRUE(output_js.empty());
+  delete root;
+
+  ListValue binary_list;
+  binary_list.Append(Value::CreateIntegerValue(5));
+  binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_list.Append(Value::CreateIntegerValue(2));
+  JSONWriter::WriteWithOptions(&binary_list,
+                               JSONWriter::OPTIONS_OMIT_BINARY_VALUES,
+                               &output_js);
+  ASSERT_EQ("[5,2]", output_js);
+
+  DictionaryValue binary_dict;
+  binary_dict.Set("a", Value::CreateIntegerValue(5));
+  binary_dict.Set("b", BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_dict.Set("c", Value::CreateIntegerValue(2));
+  JSONWriter::WriteWithOptions(&binary_dict,
+                               JSONWriter::OPTIONS_OMIT_BINARY_VALUES,
+                               &output_js);
+  ASSERT_EQ("{\"a\":5,\"c\":2}", output_js);
+
+  // Test allowing a double with no fractional part to be written as an integer.
+  FundamentalValue double_value(1e10);
+  JSONWriter::WriteWithOptions(
+      &double_value,
+      JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
+      &output_js);
+  ASSERT_EQ("10000000000", output_js);
+}
+
+}  // namespace base
diff --git a/base/json/string_escape.cc b/base/json/string_escape.cc
new file mode 100644
index 0000000..b4415b8
--- /dev/null
+++ b/base/json/string_escape.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/string_escape.h"
+
+#include <string>
+
+#include "base/stringprintf.h"
+#include "base/string_util.h"
+
+namespace base {
+
+namespace {
+
+// Try to escape |c| as a "SingleEscapeCharacter" (\n, etc).  If successful,
+// returns true and appends the escape sequence to |dst|.  This isn't required
+// by the spec, but it's more readable by humans than the \uXXXX alternatives.
+template<typename CHAR>
+static bool JsonSingleEscapeChar(const CHAR c, std::string* dst) {
+  // 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 (c) {
+    case '\b':
+      dst->append("\\b");
+      break;
+    case '\f':
+      dst->append("\\f");
+      break;
+    case '\n':
+      dst->append("\\n");
+      break;
+    case '\r':
+      dst->append("\\r");
+      break;
+    case '\t':
+      dst->append("\\t");
+      break;
+    case '\\':
+      dst->append("\\\\");
+      break;
+    case '"':
+      dst->append("\\\"");
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
+template <class STR>
+void JsonDoubleQuoteT(const STR& str,
+                      bool put_in_quotes,
+                      std::string* dst) {
+  if (put_in_quotes)
+    dst->push_back('"');
+
+  for (typename STR::const_iterator it = str.begin(); it != str.end(); ++it) {
+    typename ToUnsigned<typename STR::value_type>::Unsigned c = *it;
+    if (!JsonSingleEscapeChar(c, dst)) {
+      if (c < 32 || c > 126 || c == '<' || c == '>') {
+        // 1. Escaping <, > to prevent script execution.
+        // 2. Technically, we could also pass through c > 126 as UTF8, but this
+        //    is also optional.  It would also be a pain to implement here.
+        unsigned int as_uint = static_cast<unsigned int>(c);
+        base::StringAppendF(dst, "\\u%04X", as_uint);
+      } else {
+        unsigned char ascii = static_cast<unsigned char>(*it);
+        dst->push_back(ascii);
+      }
+    }
+  }
+
+  if (put_in_quotes)
+    dst->push_back('"');
+}
+
+}  // namespace
+
+void JsonDoubleQuote(const std::string& str,
+                     bool put_in_quotes,
+                     std::string* dst) {
+  JsonDoubleQuoteT(str, put_in_quotes, dst);
+}
+
+std::string GetDoubleQuotedJson(const std::string& str) {
+  std::string dst;
+  JsonDoubleQuote(str, true, &dst);
+  return dst;
+}
+
+void JsonDoubleQuote(const string16& str,
+                     bool put_in_quotes,
+                     std::string* dst) {
+  JsonDoubleQuoteT(str, put_in_quotes, dst);
+}
+
+std::string GetDoubleQuotedJson(const string16& str) {
+  std::string dst;
+  JsonDoubleQuote(str, true, &dst);
+  return dst;
+}
+
+}  // namespace base
diff --git a/base/json/string_escape.h b/base/json/string_escape.h
new file mode 100644
index 0000000..088db62
--- /dev/null
+++ b/base/json/string_escape.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.
+//
+// This file defines utility functions for escaping strings.
+
+#ifndef BASE_JSON_STRING_ESCAPE_H_
+#define BASE_JSON_STRING_ESCAPE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/string16.h"
+
+namespace base {
+
+// Escape |str| appropriately for a JSON string literal, _appending_ the
+// result to |dst|. This will create unicode escape sequences (\uXXXX).
+// If |put_in_quotes| is true, the result will be surrounded in double quotes.
+// The outputted literal, when interpreted by the browser, should result in a
+// javascript string that is identical and the same length as the input |str|.
+BASE_EXPORT void JsonDoubleQuote(const std::string& str,
+                                 bool put_in_quotes,
+                                 std::string* dst);
+
+// Same as above, but always returns the result double quoted.
+BASE_EXPORT std::string GetDoubleQuotedJson(const std::string& str);
+
+BASE_EXPORT void JsonDoubleQuote(const string16& str,
+                                 bool put_in_quotes,
+                                 std::string* dst);
+
+// Same as above, but always returns the result double quoted.
+BASE_EXPORT std::string GetDoubleQuotedJson(const string16& str);
+
+}  // namespace base
+
+#endif  // BASE_JSON_STRING_ESCAPE_H_
diff --git a/base/json/string_escape_unittest.cc b/base/json/string_escape_unittest.cc
new file mode 100644
index 0000000..c550ca3
--- /dev/null
+++ b/base/json/string_escape_unittest.cc
@@ -0,0 +1,100 @@
+// 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 "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const struct json_narrow_test_data {
+  const char* to_escape;
+  const char* escaped;
+} json_narrow_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!", "b\\u000F\\u007F\\u00F0\\u00FF!"},
+  {"c<>d", "c\\u003C\\u003Ed"},
+};
+
+}  // namespace
+
+TEST(StringEscapeTest, JsonDoubleQuoteNarrow) {
+  for (size_t i = 0; i < arraysize(json_narrow_cases); ++i) {
+    std::string in = json_narrow_cases[i].to_escape;
+    std::string out;
+    JsonDoubleQuote(in, false, &out);
+    EXPECT_EQ(std::string(json_narrow_cases[i].escaped), out);
+  }
+
+  std::string in = json_narrow_cases[0].to_escape;
+  std::string out;
+  JsonDoubleQuote(in, false, &out);
+
+  // test quoting
+  std::string out_quoted;
+  JsonDoubleQuote(in, true, &out_quoted);
+  EXPECT_EQ(out.length() + 2, out_quoted.length());
+  EXPECT_EQ(out_quoted.find(out), 1U);
+
+  // 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 += json_narrow_cases[0].escaped;
+  out.clear();
+  JsonDoubleQuote(in, false, &out);
+  EXPECT_EQ(expected, out);
+}
+
+namespace {
+
+const struct json_wide_test_data {
+  const wchar_t* to_escape;
+  const char* escaped;
+} json_wide_cases[] = {
+  {L"b\uffb1\u00ff", "b\\uFFB1\\u00FF"},
+  {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\\u007F\\u00F0\\u00FF!"},
+  {L"c<>d", "c\\u003C\\u003Ed"},
+};
+
+}  // namespace
+
+TEST(StringEscapeTest, JsonDoubleQuoteWide) {
+  for (size_t i = 0; i < arraysize(json_wide_cases); ++i) {
+    std::string out;
+    string16 in = WideToUTF16(json_wide_cases[i].to_escape);
+    JsonDoubleQuote(in, false, &out);
+    EXPECT_EQ(std::string(json_wide_cases[i].escaped), out);
+  }
+
+  string16 in = WideToUTF16(json_wide_cases[0].to_escape);
+  std::string out;
+  JsonDoubleQuote(in, false, &out);
+
+  // test quoting
+  std::string out_quoted;
+  JsonDoubleQuote(in, true, &out_quoted);
+  EXPECT_EQ(out.length() + 2, out_quoted.length());
+  EXPECT_EQ(out_quoted.find(out), 1U);
+
+  // 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 += json_wide_cases[0].escaped;
+  out.clear();
+  JsonDoubleQuote(in, false, &out);
+  EXPECT_EQ(expected, out);
+}
+
+}  // namespace base
diff --git a/base/lazy_instance.cc b/base/lazy_instance.cc
new file mode 100644
index 0000000..a81cb8c
--- /dev/null
+++ b/base/lazy_instance.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/lazy_instance.h"
+
+#include "base/at_exit.h"
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+#include "base/threading/platform_thread.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.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*)) {
+  // See the comment to the corresponding HAPPENS_AFTER in Pointer().
+  ANNOTATE_HAPPENS_BEFORE(state);
+
+  // Instance is created, go from CREATING to CREATED.
+  // Releases visibility over private_buf_ to readers. Pairing Acquire_Load's
+  // are in NeedsInstance() and Pointer().
+  subtle::Release_Store(state, new_instance);
+
+  // Make sure that the lazily instantiated object will get destroyed at exit.
+  if (dtor)
+    AtExitManager::RegisterCallback(dtor, lazy_instance);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
new file mode 100644
index 0000000..7021829
--- /dev/null
+++ b/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/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/aligned_memory.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread_restrictions.h"
+
+// LazyInstance uses its own struct initializer-list style static
+// initialization, as base's LINKER_INITIALIZED requires a constructor and on
+// some compilers (notably gcc 4.4) this still ends up needing runtime
+// initialization.
+#define LAZY_INSTANCE_INITIALIZER {0}
+
+namespace base {
+
+template <typename Type>
+struct DefaultLazyInstanceTraits {
+  static const bool kRegisterOnExit = true;
+  static const bool kAllowedToAccessOnNonjoinableThread = false;
+
+  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;
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+
+  static Type* New(void* instance) {
+    return DefaultLazyInstanceTraits<Type>::New(instance);
+  }
+  static void Delete(Type* instance) {
+  }
+};
+
+// Our AtomicWord doubles as a spinlock, where a value of
+// kBeingCreatedMarker means the spinlock is being held for creation.
+static const subtle::AtomicWord kLazyInstanceStateCreating = 1;
+
+// Check if instance needs to be created. If so return true otherwise
+// if another thread has beat us, wait for instance to be created and
+// return false.
+BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state);
+
+// After creating an instance, call this to register the dtor to be called
+// at program exit and to update the atomic state to hold the |new_instance|
+BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state,
+                                      subtle::AtomicWord new_instance,
+                                      void* lazy_instance,
+                                      void (*dtor)(void*));
+
+}  // namespace internal
+
+template <typename Type, typename Traits = DefaultLazyInstanceTraits<Type> >
+class LazyInstance {
+ public:
+  // Do not define a destructor, as doing so makes LazyInstance a
+  // non-POD-struct. We don't want that because then a static initializer will
+  // be created to register the (empty) destructor with atexit() under MSVC, for
+  // example. We handle destruction of the contained Type class explicitly via
+  // the OnExit member function, where needed.
+  // ~LazyInstance() {}
+
+  // Convenience typedef to avoid having to repeat Type for leaky lazy
+  // instances.
+  typedef LazyInstance<Type, internal::LeakyLazyInstanceTraits<Type> > Leaky;
+
+  Type& Get() {
+    return *Pointer();
+  }
+
+  Type* Pointer() {
+#ifndef NDEBUG
+    // Avoid making TLS lookup on release builds.
+    if (!Traits::kAllowedToAccessOnNonjoinableThread)
+      ThreadRestrictions::AssertSingletonAllowed();
+#endif
+    // If any bit in the created mask is true, the instance has already been
+    // fully constructed.
+    static const subtle::AtomicWord kLazyInstanceCreatedMask =
+        ~internal::kLazyInstanceStateCreating;
+
+    // We will hopefully have fast access when the instance is already created.
+    // Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating
+    // at most once, the load is taken out of NeedsInstance() as a fast-path.
+    // The load has acquire memory ordering as a thread which sees
+    // private_instance_ > creating needs to acquire visibility over
+    // the associated data (private_buf_). Pairing Release_Store is in
+    // CompleteLazyInstance().
+    subtle::AtomicWord value = subtle::Acquire_Load(&private_instance_);
+    if (!(value & kLazyInstanceCreatedMask) &&
+        internal::NeedsLazyInstance(&private_instance_)) {
+      // Create the instance in the space provided by |private_buf_|.
+      value = reinterpret_cast<subtle::AtomicWord>(
+          Traits::New(private_buf_.void_data()));
+      internal::CompleteLazyInstance(&private_instance_, value, this,
+                                     Traits::kRegisterOnExit ? OnExit : NULL);
+    }
+
+    // This annotation helps race detectors recognize correct lock-less
+    // synchronization between different threads calling Pointer().
+    // We suggest dynamic race detection tool that "Traits::New" above
+    // and CompleteLazyInstance(...) happens before "return instance()" below.
+    // See the corresponding HAPPENS_BEFORE in CompleteLazyInstance(...).
+    ANNOTATE_HAPPENS_AFTER(&private_instance_);
+    return instance();
+  }
+
+  bool operator==(Type* p) {
+    switch (subtle::NoBarrier_Load(&private_instance_)) {
+      case 0:
+        return p == NULL;
+      case internal::kLazyInstanceStateCreating:
+        return static_cast<void*>(p) == private_buf_.void_data();
+      default:
+        return p == instance();
+    }
+  }
+
+  // Effectively private: member data is only public to allow the linker to
+  // statically initialize it and to maintain a POD class. DO NOT USE FROM
+  // OUTSIDE THIS CLASS.
+
+  subtle::AtomicWord private_instance_;
+  // Preallocated space for the Type instance.
+  base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> private_buf_;
+
+ private:
+  Type* instance() {
+    return reinterpret_cast<Type*>(subtle::NoBarrier_Load(&private_instance_));
+  }
+
+  // Adapter function for use with AtExit.  This should be called single
+  // threaded, so don't synchronize across threads.
+  // Calling OnExit while the instance is in use by other threads is a mistake.
+  static void OnExit(void* lazy_instance) {
+    LazyInstance<Type, Traits>* me =
+        reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance);
+    Traits::Delete(me->instance());
+    subtle::NoBarrier_Store(&me->private_instance_, 0);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_LAZY_INSTANCE_H_
diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc
new file mode 100644
index 0000000..e25366e
--- /dev/null
+++ b/base/lazy_instance_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/atomic_sequence_num.h"
+#include "base/lazy_instance.h"
+#include "base/memory/aligned_memory.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+base::StaticAtomicSequenceNumber constructed_seq_;
+base::StaticAtomicSequenceNumber destructed_seq_;
+
+class ConstructAndDestructLogger {
+ public:
+  ConstructAndDestructLogger() {
+    constructed_seq_.GetNext();
+  }
+  ~ConstructAndDestructLogger() {
+    destructed_seq_.GetNext();
+  }
+};
+
+class SlowConstructor {
+ public:
+  SlowConstructor() : some_int_(0) {
+    // Sleep for 1 second to try to cause a race.
+    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+    ++constructed;
+    some_int_ = 12;
+  }
+  int some_int() const { return some_int_; }
+
+  static int constructed;
+ private:
+  int some_int_;
+};
+
+int SlowConstructor::constructed = 0;
+
+class SlowDelegate : public base::DelegateSimpleThread::Delegate {
+ public:
+  explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
+      : lazy_(lazy) {}
+
+  virtual void Run() OVERRIDE {
+    EXPECT_EQ(12, lazy_->Get().some_int());
+    EXPECT_EQ(12, lazy_->Pointer()->some_int());
+  }
+
+ private:
+  base::LazyInstance<SlowConstructor>* lazy_;
+};
+
+}  // namespace
+
+static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
+    LAZY_INSTANCE_INITIALIZER;
+
+TEST(LazyInstanceTest, Basic) {
+  {
+    base::ShadowingAtExitManager shadow;
+
+    EXPECT_EQ(0, constructed_seq_.GetNext());
+    EXPECT_EQ(0, destructed_seq_.GetNext());
+
+    lazy_logger.Get();
+    EXPECT_EQ(2, constructed_seq_.GetNext());
+    EXPECT_EQ(1, destructed_seq_.GetNext());
+
+    lazy_logger.Pointer();
+    EXPECT_EQ(3, constructed_seq_.GetNext());
+    EXPECT_EQ(2, destructed_seq_.GetNext());
+  }
+  EXPECT_EQ(4, constructed_seq_.GetNext());
+  EXPECT_EQ(4, destructed_seq_.GetNext());
+}
+
+static base::LazyInstance<SlowConstructor> lazy_slow =
+    LAZY_INSTANCE_INITIALIZER;
+
+TEST(LazyInstanceTest, ConstructorThreadSafety) {
+  {
+    base::ShadowingAtExitManager shadow;
+
+    SlowDelegate delegate(&lazy_slow);
+    EXPECT_EQ(0, SlowConstructor::constructed);
+
+    base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
+    pool.AddWork(&delegate, 20);
+    EXPECT_EQ(0, SlowConstructor::constructed);
+
+    pool.Start();
+    pool.JoinAll();
+    EXPECT_EQ(1, SlowConstructor::constructed);
+  }
+}
+
+namespace {
+
+// DeleteLogger is an object which sets a flag when it's destroyed.
+// It accepts a bool* and sets the bool to true when the dtor runs.
+class DeleteLogger {
+ public:
+  DeleteLogger() : deleted_(NULL) {}
+  ~DeleteLogger() { *deleted_ = true; }
+
+  void SetDeletedPtr(bool* deleted) {
+    deleted_ = deleted;
+  }
+
+ private:
+  bool* deleted_;
+};
+
+}  // anonymous namespace
+
+TEST(LazyInstanceTest, LeakyLazyInstance) {
+  // Check that using a plain LazyInstance causes the dtor to run
+  // when the AtExitManager finishes.
+  bool deleted1 = false;
+  {
+    base::ShadowingAtExitManager shadow;
+    static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER;
+    test.Get().SetDeletedPtr(&deleted1);
+  }
+  EXPECT_TRUE(deleted1);
+
+  // Check that using a *leaky* LazyInstance makes the dtor not run
+  // when the AtExitManager finishes.
+  bool deleted2 = false;
+  {
+    base::ShadowingAtExitManager shadow;
+    static base::LazyInstance<DeleteLogger>::Leaky
+        test = LAZY_INSTANCE_INITIALIZER;
+    test.Get().SetDeletedPtr(&deleted2);
+  }
+  EXPECT_FALSE(deleted2);
+}
+
+namespace {
+
+template <size_t alignment>
+class AlignedData {
+ public:
+  AlignedData() {}
+  ~AlignedData() {}
+  base::AlignedMemory<alignment, alignment> data_;
+};
+
+}  // anonymous namespace
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST(LazyInstanceTest, Alignment) {
+  using base::LazyInstance;
+
+  // Create some static instances with increasing sizes and alignment
+  // requirements. By ordering this way, the linker will need to do some work to
+  // ensure proper alignment of the static data.
+  static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER;
+  static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER;
+  static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER;
+
+  EXPECT_ALIGNED(align4.Pointer(), 4);
+  EXPECT_ALIGNED(align32.Pointer(), 32);
+  EXPECT_ALIGNED(align4096.Pointer(), 4096);
+}
diff --git a/base/linux_util.cc b/base/linux_util.cc
new file mode 100644
index 0000000..49df773
--- /dev/null
+++ b/base/linux_util.cc
@@ -0,0 +1,304 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/linux_util.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/string_util.h"
+#include "base/synchronization/lock.h"
+
+namespace {
+
+// Not needed for OS_CHROMEOS.
+#if defined(OS_LINUX)
+enum LinuxDistroState {
+  STATE_DID_NOT_CHECK  = 0,
+  STATE_CHECK_STARTED  = 1,
+  STATE_CHECK_FINISHED = 2,
+};
+
+// Helper class for GetLinuxDistro().
+class LinuxDistroHelper {
+ public:
+  // Retrieves the Singleton.
+  static LinuxDistroHelper* GetInstance() {
+    return Singleton<LinuxDistroHelper>::get();
+  }
+
+  // The simple state machine goes from:
+  // STATE_DID_NOT_CHECK -> STATE_CHECK_STARTED -> STATE_CHECK_FINISHED.
+  LinuxDistroHelper() : state_(STATE_DID_NOT_CHECK) {}
+  ~LinuxDistroHelper() {}
+
+  // Retrieve the current state, if we're in STATE_DID_NOT_CHECK,
+  // we automatically move to STATE_CHECK_STARTED so nobody else will
+  // do the check.
+  LinuxDistroState State() {
+    base::AutoLock scoped_lock(lock_);
+    if (STATE_DID_NOT_CHECK == state_) {
+      state_ = STATE_CHECK_STARTED;
+      return STATE_DID_NOT_CHECK;
+    }
+    return state_;
+  }
+
+  // Indicate the check finished, move to STATE_CHECK_FINISHED.
+  void CheckFinished() {
+    base::AutoLock scoped_lock(lock_);
+    DCHECK_EQ(STATE_CHECK_STARTED, state_);
+    state_ = STATE_CHECK_FINISHED;
+  }
+
+ private:
+  base::Lock lock_;
+  LinuxDistroState state_;
+};
+#endif  // if defined(OS_LINUX)
+
+// expected prefix of the target of the /proc/self/fd/%d link for a socket
+const char kSocketLinkPrefix[] = "socket:[";
+
+// Parse a symlink in /proc/pid/fd/$x and return the inode number of the
+// socket.
+//   inode_out: (output) set to the inode number on success
+//   path: e.g. /proc/1234/fd/5 (must be a UNIX domain socket descriptor)
+//   log: if true, log messages about failure details
+bool ProcPathGetInode(ino_t* inode_out, const char* path, bool log = false) {
+  DCHECK(inode_out);
+  DCHECK(path);
+
+  char buf[256];
+  const ssize_t n = readlink(path, buf, sizeof(buf) - 1);
+  if (n == -1) {
+    if (log) {
+      DLOG(WARNING) << "Failed to read the inode number for a socket from /proc"
+                      "(" << errno << ")";
+    }
+    return false;
+  }
+  buf[n] = 0;
+
+  if (memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) {
+    if (log) {
+      DLOG(WARNING) << "The descriptor passed from the crashing process wasn't "
+                      " a UNIX domain socket.";
+    }
+    return false;
+  }
+
+  char* endptr;
+  const unsigned long long int inode_ul =
+      strtoull(buf + sizeof(kSocketLinkPrefix) - 1, &endptr, 10);
+  if (*endptr != ']')
+    return false;
+
+  if (inode_ul == ULLONG_MAX) {
+    if (log) {
+      DLOG(WARNING) << "Failed to parse a socket's inode number: the number "
+                       "was too large. Please report this bug: " << buf;
+    }
+    return false;
+  }
+
+  *inode_out = inode_ul;
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+
+const char kFindInodeSwitch[] = "--find-inode";
+
+// Account for the terminating null character.
+static const int kDistroSize = 128 + 1;
+
+// We use this static string to hold the Linux distro info. If we
+// crash, the crash handler code will send this in the crash dump.
+char g_linux_distro[kDistroSize] =
+#if defined(OS_CHROMEOS)
+    "CrOS";
+#elif defined(OS_ANDROID)
+    "Android";
+#else  // if defined(OS_LINUX)
+    "Unknown";
+#endif
+
+std::string GetLinuxDistro() {
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+  return g_linux_distro;
+#elif defined(OS_LINUX)
+  LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::GetInstance();
+  LinuxDistroState state = distro_state_singleton->State();
+  if (STATE_CHECK_FINISHED == state)
+    return g_linux_distro;
+  if (STATE_CHECK_STARTED == state)
+    return "Unknown"; // Don't wait for other thread to finish.
+  DCHECK_EQ(state, STATE_DID_NOT_CHECK);
+  // We do this check only once per process. If it fails, there's
+  // little reason to believe it will work if we attempt to run
+  // lsb_release again.
+  std::vector<std::string> argv;
+  argv.push_back("lsb_release");
+  argv.push_back("-d");
+  std::string output;
+  base::GetAppOutput(CommandLine(argv), &output);
+  if (output.length() > 0) {
+    // lsb_release -d should return: Description:<tab>Distro Info
+    const char field[] = "Description:\t";
+    if (output.compare(0, strlen(field), field) == 0) {
+      SetLinuxDistro(output.substr(strlen(field)));
+    }
+  }
+  distro_state_singleton->CheckFinished();
+  return g_linux_distro;
+#else
+  NOTIMPLEMENTED();
+  return "Unknown";
+#endif
+}
+
+void SetLinuxDistro(const std::string& distro) {
+  std::string trimmed_distro;
+  TrimWhitespaceASCII(distro, TRIM_ALL, &trimmed_distro);
+  base::strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
+}
+
+bool FileDescriptorGetInode(ino_t* inode_out, int fd) {
+  DCHECK(inode_out);
+
+  struct stat buf;
+  if (fstat(fd, &buf) < 0)
+    return false;
+
+  if (!S_ISSOCK(buf.st_mode))
+    return false;
+
+  *inode_out = buf.st_ino;
+  return true;
+}
+
+bool FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode) {
+  DCHECK(pid_out);
+  bool already_found = false;
+
+  DIR* proc = opendir("/proc");
+  if (!proc) {
+    DLOG(WARNING) << "Cannot open /proc";
+    return false;
+  }
+
+  std::vector<pid_t> pids;
+
+  struct dirent* dent;
+  while ((dent = readdir(proc))) {
+    char* endptr;
+    const unsigned long int pid_ul = strtoul(dent->d_name, &endptr, 10);
+    if (pid_ul == ULONG_MAX || *endptr)
+      continue;
+    pids.push_back(pid_ul);
+  }
+  closedir(proc);
+
+  for (std::vector<pid_t>::const_iterator
+       i = pids.begin(); i != pids.end(); ++i) {
+    const pid_t current_pid = *i;
+    char buf[256];
+    snprintf(buf, sizeof(buf), "/proc/%d/fd", current_pid);
+    DIR* fd = opendir(buf);
+    if (!fd)
+      continue;
+
+    while ((dent = readdir(fd))) {
+      if (snprintf(buf, sizeof(buf), "/proc/%d/fd/%s", current_pid,
+                   dent->d_name) >= static_cast<int>(sizeof(buf))) {
+        continue;
+      }
+
+      ino_t fd_inode;
+      if (ProcPathGetInode(&fd_inode, buf)) {
+        if (fd_inode == socket_inode) {
+          if (already_found) {
+            closedir(fd);
+            return false;
+          }
+
+          already_found = true;
+          *pid_out = current_pid;
+          break;
+        }
+      }
+    }
+
+    closedir(fd);
+  }
+
+  return already_found;
+}
+
+pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data,
+                              bool* syscall_supported) {
+  char buf[256];
+  snprintf(buf, sizeof(buf), "/proc/%d/task", pid);
+
+  if (syscall_supported != NULL)
+    *syscall_supported = false;
+
+  DIR* task = opendir(buf);
+  if (!task) {
+    DLOG(WARNING) << "Cannot open " << buf;
+    return -1;
+  }
+
+  std::vector<pid_t> tids;
+  struct dirent* dent;
+  while ((dent = readdir(task))) {
+    char* endptr;
+    const unsigned long int tid_ul = strtoul(dent->d_name, &endptr, 10);
+    if (tid_ul == ULONG_MAX || *endptr)
+      continue;
+    tids.push_back(tid_ul);
+  }
+  closedir(task);
+
+  scoped_array<char> syscall_data(new char[expected_data.length()]);
+  for (std::vector<pid_t>::const_iterator
+       i = tids.begin(); i != tids.end(); ++i) {
+    const pid_t current_tid = *i;
+    snprintf(buf, sizeof(buf), "/proc/%d/task/%d/syscall", pid, current_tid);
+    int fd = open(buf, O_RDONLY);
+    if (fd < 0)
+      continue;
+    if (syscall_supported != NULL)
+      *syscall_supported = true;
+    bool read_ret =
+        file_util::ReadFromFD(fd, syscall_data.get(), expected_data.length());
+    close(fd);
+    if (!read_ret)
+      continue;
+
+    if (0 == strncmp(expected_data.c_str(), syscall_data.get(),
+                     expected_data.length())) {
+      return current_tid;
+    }
+  }
+  return -1;
+}
+
+}  // namespace base
diff --git a/base/linux_util.h b/base/linux_util.h
new file mode 100644
index 0000000..b9ba56d
--- /dev/null
+++ b/base/linux_util.h
@@ -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.
+
+#ifndef BASE_LINUX_UTIL_H_
+#define BASE_LINUX_UTIL_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+BASE_EXPORT extern const char kFindInodeSwitch[];
+
+// This is declared here so the crash reporter can access the memory directly
+// in compromised context without going through the standard library.
+BASE_EXPORT extern char g_linux_distro[];
+
+// Get the Linux Distro if we can, or return "Unknown".
+BASE_EXPORT std::string GetLinuxDistro();
+
+// Set the Linux Distro string.
+BASE_EXPORT void SetLinuxDistro(const std::string& distro);
+
+// Return the inode number for the UNIX domain socket |fd|.
+BASE_EXPORT bool FileDescriptorGetInode(ino_t* inode_out, int fd);
+
+// Find the process which holds the given socket, named by inode number. If
+// multiple processes hold the socket, this function returns false.
+BASE_EXPORT bool FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode);
+
+// For a given process |pid|, look through all its threads and find the first
+// thread with /proc/[pid]/task/[thread_id]/syscall whose first N bytes matches
+// |expected_data|, where N is the length of |expected_data|.
+// Returns the thread id or -1 on error.  If |syscall_supported| is
+// set to false the kernel does not support syscall in procfs.
+BASE_EXPORT pid_t FindThreadIDWithSyscall(pid_t pid,
+                                          const std::string& expected_data,
+                                          bool* syscall_supported);
+
+}  // namespace base
+
+#endif  // BASE_LINUX_UTIL_H_
diff --git a/base/location.cc b/base/location.cc
new file mode 100644
index 0000000..3422138
--- /dev/null
+++ b/base/location.cc
@@ -0,0 +1,102 @@
+// Copyright (c) 2012 The Chromium Authors. 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)
+// MSDN says to #include <intrin.h>, but that breaks the VS2005 build.
+extern "C" {
+  void* _ReturnAddress();
+}
+#endif
+
+#include "base/location.h"
+#include "base/string_number_conversions.h"
+#include "base/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) {
+}
+
+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)
+  return __builtin_extract_return_addr(__builtin_return_address(0));
+#endif  // COMPILER_GCC
+
+  return NULL;
+}
+
+}  // namespace tracked_objects
diff --git a/base/location.h b/base/location.h
new file mode 100644
index 0000000..05a4f66
--- /dev/null
+++ b/base/location.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 BASE_LOCATION_H_
+#define BASE_LOCATION_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.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();
+
+  // Comparison operator for insertion into a std::map<> hash tables.
+  // All we need is *some* (any) hashing distinction.  Strings should already
+  // be unique, so we don't bother with strcmp or such.
+  // Use line number as the primary key (because it is fast, and usually gets us
+  // a difference), and then pointers as secondary keys (just to get some
+  // distinctions).
+  bool operator < (const Location& other) const {
+    if (line_number_ != other.line_number_)
+      return line_number_ < other.line_number_;
+    if (file_name_ != other.file_name_)
+      return file_name_ < other.file_name_;
+    return function_name_ < other.function_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;
+
+  // Translate the some of the state in this instance into a human readable
+  // string with HTML characters in the function names escaped, and append that
+  // string to |output|.  Inclusion of the file_name_ and function_name_ are
+  // optional, and controlled by the boolean arguments.
+  void Write(bool display_filename, bool display_function_name,
+             std::string* output) const;
+
+  // Write function_name_ in HTML with '<' and '>' properly encoded.
+  void WriteFunctionName(std::string* output) const;
+
+ private:
+  const char* function_name_;
+  const char* file_name_;
+  int line_number_;
+  const void* program_counter_;
+};
+
+// A "snapshotted" representation of the Location class that can safely be
+// passed across process boundaries.
+struct BASE_EXPORT LocationSnapshot {
+  // The default constructor is exposed to support the IPC serialization macros.
+  LocationSnapshot();
+  explicit LocationSnapshot(const tracked_objects::Location& location);
+  ~LocationSnapshot();
+
+  std::string file_name;
+  std::string function_name;
+  int line_number;
+};
+
+BASE_EXPORT const void* GetProgramCounter();
+
+// Define a macro to record the current source location.
+#define FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION(__FUNCTION__)
+
+#define FROM_HERE_WITH_EXPLICIT_FUNCTION(function_name)                        \
+    ::tracked_objects::Location(function_name,                                 \
+                                __FILE__,                                      \
+                                __LINE__,                                      \
+                                ::tracked_objects::GetProgramCounter())
+
+}  // namespace tracked_objects
+
+#endif  // BASE_LOCATION_H_
diff --git a/base/logging.cc b/base/logging.cc
new file mode 100644
index 0000000..7f9caff
--- /dev/null
+++ b/base/logging.cc
@@ -0,0 +1,861 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+
+#if defined(OS_WIN)
+#include <io.h>
+#include <windows.h>
+typedef HANDLE FileHandle;
+typedef HANDLE MutexHandle;
+// Windows warns on using write().  It prefers _write().
+#define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count))
+// Windows doesn't define STDERR_FILENO.  Define it here.
+#define STDERR_FILENO 2
+#elif defined(OS_MACOSX)
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach-o/dyld.h>
+#elif defined(OS_POSIX)
+#if defined(OS_NACL)
+#include <sys/time.h> // timespec doesn't seem to be in <time.h>
+#else
+#include <sys/syscall.h>
+#endif
+#include <time.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#define MAX_PATH PATH_MAX
+typedef FILE* FileHandle;
+typedef pthread_mutex_t* MutexHandle;
+#endif
+
+#include <algorithm>
+#include <cstring>
+#include <ctime>
+#include <iomanip>
+#include <ostream>
+
+#include "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/eintr_wrapper.h"
+#include "base/string_piece.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/threading/platform_thread.h"
+#include "base/utf_string_conversions.h"
+#include "base/vlog.h"
+#if defined(OS_POSIX)
+#include "base/safe_strerror_posix.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include <android/log.h>
+#endif
+
+namespace logging {
+
+DcheckState g_dcheck_state = DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
+
+namespace {
+
+VlogInfo* g_vlog_info = NULL;
+VlogInfo* g_vlog_info_prev = NULL;
+
+const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
+  "INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" };
+
+int min_log_level = 0;
+
+// The default set here for logging_destination will only be used if
+// InitLogging is not called.  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)
+LoggingDestination logging_destination = LOG_ONLY_TO_FILE;
+#elif defined(OS_POSIX)
+LoggingDestination logging_destination = LOG_ONLY_TO_SYSTEM_DEBUG_LOG;
+#endif
+
+// 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* log_file_name = NULL;
+
+// this file is lazily opened and the handle may be NULL
+FileHandle log_file = NULL;
+
+// what should be prepended to each message?
+bool log_process_id = false;
+bool log_thread_id = false;
+bool log_timestamp = true;
+bool 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 = NULL;
+// An report handler override specified by the client to be called instead of
+// the debug message dialog.
+LogReportHandlerFunction log_report_handler = NULL;
+// A log message handler that gets notified of every log message we process.
+LogMessageHandlerFunction log_message_handler = NULL;
+
+// Helper functions to wrap platform differences.
+
+int32 CurrentProcessId() {
+#if defined(OS_WIN)
+  return GetCurrentProcessId();
+#elif defined(OS_POSIX)
+  return getpid();
+#endif
+}
+
+uint64 TickCount() {
+#if defined(OS_WIN)
+  return GetTickCount();
+#elif defined(OS_MACOSX)
+  return mach_absolute_time();
+#elif defined(OS_NACL)
+  // NaCl sadly does not have _POSIX_TIMERS enabled in sys/features.h
+  // So we have to use clock() for now.
+  return clock();
+#elif defined(OS_POSIX)
+  struct timespec ts;
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+
+  uint64 absolute_micro =
+    static_cast<int64>(ts.tv_sec) * 1000000 +
+    static_cast<int64>(ts.tv_nsec) / 1000;
+
+  return absolute_micro;
+#endif
+}
+
+void CloseFile(FileHandle log) {
+#if defined(OS_WIN)
+  CloseHandle(log);
+#else
+  fclose(log);
+#endif
+}
+
+void DeleteFilePath(const PathString& log_name) {
+#if defined(OS_WIN)
+  DeleteFile(log_name.c_str());
+#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(NULL, module_name, MAX_PATH);
+
+  PathString log_file = module_name;
+  PathString::size_type last_backslash =
+      log_file.rfind('\\', log_file.size());
+  if (last_backslash != PathString::npos)
+    log_file.erase(last_backslash + 1);
+  log_file += L"debug.log";
+  return log_file;
+#elif defined(OS_POSIX)
+  // On other platforms we just use the current directory.
+  return PathString("debug.log");
+#endif
+}
+
+// This class acts as a wrapper for locking the logging files.
+// LoggingLock::Init() should be called from the main thread before any logging
+// is done. Then whenever logging, be sure to have a local LoggingLock
+// instance on the stack. This will ensure that the lock is unlocked upon
+// exiting the frame.
+// LoggingLocks can not be nested.
+class LoggingLock {
+ public:
+  LoggingLock() {
+    LockLogging();
+  }
+
+  ~LoggingLock() {
+    UnlockLogging();
+  }
+
+  static void Init(LogLockingState lock_log, const PathChar* new_log_file) {
+    if (initialized)
+      return;
+    lock_log_file = lock_log;
+    if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+      if (!log_mutex) {
+        std::wstring safe_name;
+        if (new_log_file)
+          safe_name = new_log_file;
+        else
+          safe_name = GetDefaultLogFile();
+        // \ is not a legal character in mutex names so we replace \ with /
+        std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
+        std::wstring t(L"Global\\");
+        t.append(safe_name);
+        log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
+
+        if (log_mutex == NULL) {
+#if DEBUG
+          // Keep the error code for debugging
+          int error = GetLastError();  // NOLINT
+          base::debug::BreakDebugger();
+#endif
+          // Return nicely without putting initialized to true.
+          return;
+        }
+      }
+#endif
+    } else {
+      log_lock = new base::internal::LockImpl();
+    }
+    initialized = true;
+  }
+
+ private:
+  static void LockLogging() {
+    if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+      ::WaitForSingleObject(log_mutex, INFINITE);
+      // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
+      // abort the process here. UI tests might be crashy sometimes,
+      // and aborting the test binary only makes the problem worse.
+      // We also don't use LOG macros because that might lead to an infinite
+      // loop. For more info see http://crbug.com/18028.
+#elif defined(OS_POSIX)
+      pthread_mutex_lock(&log_mutex);
+#endif
+    } else {
+      // use the lock
+      log_lock->Lock();
+    }
+  }
+
+  static void UnlockLogging() {
+    if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+      ReleaseMutex(log_mutex);
+#elif defined(OS_POSIX)
+      pthread_mutex_unlock(&log_mutex);
+#endif
+    } else {
+      log_lock->Unlock();
+    }
+  }
+
+  // The lock is used if log file locking is false. It helps us avoid problems
+  // with multiple threads writing to the log file at the same time.  Use
+  // LockImpl directly instead of using Lock, because Lock makes logging calls.
+  static base::internal::LockImpl* log_lock;
+
+  // When we don't use a lock, we are using a global mutex. We need to do this
+  // because LockFileEx is not thread safe.
+#if defined(OS_WIN)
+  static MutexHandle log_mutex;
+#elif defined(OS_POSIX)
+  static pthread_mutex_t log_mutex;
+#endif
+
+  static bool initialized;
+  static LogLockingState lock_log_file;
+};
+
+// static
+bool LoggingLock::initialized = false;
+// static
+base::internal::LockImpl* LoggingLock::log_lock = NULL;
+// static
+LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
+
+#if defined(OS_WIN)
+// static
+MutexHandle LoggingLock::log_mutex = NULL;
+#elif defined(OS_POSIX)
+pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+// Called by logging functions to ensure that debug_file is initialized
+// and can be used for writing. Returns false if the file could not be
+// initialized. debug_file will be NULL in this case.
+bool InitializeLogFileHandle() {
+  if (log_file)
+    return true;
+
+  if (!log_file_name) {
+    // Nobody has called InitLogging to specify a debug log file, so here we
+    // initialize the log file name to a default.
+    log_file_name = new PathString(GetDefaultLogFile());
+  }
+
+  if (logging_destination == LOG_ONLY_TO_FILE ||
+      logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
+#if defined(OS_WIN)
+    log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
+                          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                          OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
+      // try the current directory
+      log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
+                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                            OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+      if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
+        log_file = NULL;
+        return false;
+      }
+    }
+    SetFilePointer(log_file, 0, 0, FILE_END);
+#elif defined(OS_POSIX)
+    log_file = fopen(log_file_name->c_str(), "a");
+    if (log_file == NULL)
+      return false;
+#endif
+  }
+
+  return true;
+}
+
+}  // namespace
+
+
+bool BaseInitLoggingImpl(const PathChar* new_log_file,
+                         LoggingDestination logging_dest,
+                         LogLockingState lock_log,
+                         OldFileDeletionState delete_old,
+                         DcheckState dcheck_state) {
+  g_dcheck_state = dcheck_state;
+// TODO(bbudge) Hook this up to NaCl logging.
+#if !defined(OS_NACL)
+  CommandLine* command_line = 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),
+                     &min_log_level);
+  }
+
+  LoggingLock::Init(lock_log, new_log_file);
+
+  LoggingLock logging_lock;
+
+  if (log_file) {
+    // calling InitLogging twice or after some log call has already opened the
+    // default log file will re-initialize to the new options
+    CloseFile(log_file);
+    log_file = NULL;
+  }
+
+  logging_destination = logging_dest;
+
+  // ignore file options if logging is disabled or only to system
+  if (logging_destination == LOG_NONE ||
+      logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
+    return true;
+
+  if (!log_file_name)
+    log_file_name = new PathString();
+  *log_file_name = new_log_file;
+  if (delete_old == DELETE_OLD_LOG_FILE)
+    DeleteFilePath(*log_file_name);
+
+  return InitializeLogFileHandle();
+#else
+  (void) g_vlog_info_prev;
+  return true;
+#endif  // !defined(OS_NACL)
+}
+
+void SetMinLogLevel(int level) {
+  min_log_level = std::min(LOG_ERROR_REPORT, level);
+}
+
+int GetMinLogLevel() {
+  return min_log_level;
+}
+
+int GetVlogVerbosity() {
+  return std::max(-1, LOG_INFO - GetMinLogLevel());
+}
+
+int GetVlogLevelHelper(const char* file, size_t N) {
+  DCHECK_GT(N, 0U);
+  // Note: g_vlog_info may change on a different thread during startup
+  // (but will always be valid or NULL).
+  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) {
+  log_process_id = enable_process_id;
+  log_thread_id = enable_thread_id;
+  log_timestamp = enable_timestamp;
+  log_tickcount = enable_tickcount;
+}
+
+void SetShowErrorDialogs(bool enable_dialogs) {
+  show_error_dialogs = enable_dialogs;
+}
+
+void SetLogAssertHandler(LogAssertHandlerFunction handler) {
+  log_assert_handler = handler;
+}
+
+void SetLogReportHandler(LogReportHandlerFunction handler) {
+  log_report_handler = handler;
+}
+
+void SetLogMessageHandler(LogMessageHandlerFunction handler) {
+  log_message_handler = handler;
+}
+
+LogMessageHandlerFunction GetLogMessageHandler() {
+  return log_message_handler;
+}
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+// 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);
+#endif
+
+// Displays a message box to the user with the error message in it.
+// Used for fatal messages, where we close the app simultaneously.
+// This is for developers only; we don't use this in circumstances
+// (like release builds) where users could see it, since users don't
+// understand these messages anyway.
+void DisplayDebugMessageInDialog(const std::string& str) {
+  if (str.empty())
+    return;
+
+  if (!show_error_dialogs)
+    return;
+
+#if defined(OS_WIN)
+  // For Windows programs, it's possible that the message loop is
+  // messed up on a fatal error, and creating a MessageBox will cause
+  // that message loop to be run. Instead, we try to spawn another
+  // process that displays its command line. We look for "Debug
+  // Message.exe" in the same directory as the application. If it
+  // exists, we use it, otherwise, we use a regular message box.
+  wchar_t prog_name[MAX_PATH];
+  GetModuleFileNameW(NULL, prog_name, MAX_PATH);
+  wchar_t* backslash = wcsrchr(prog_name, '\\');
+  if (backslash)
+    backslash[1] = 0;
+  wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
+
+  std::wstring cmdline = UTF8ToWide(str);
+  if (cmdline.empty())
+    return;
+
+  STARTUPINFO startup_info;
+  memset(&startup_info, 0, sizeof(startup_info));
+  startup_info.cb = sizeof(startup_info);
+
+  PROCESS_INFORMATION process_info;
+  if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL,
+                     NULL, &startup_info, &process_info)) {
+    WaitForSingleObject(process_info.hProcess, INFINITE);
+    CloseHandle(process_info.hThread);
+    CloseHandle(process_info.hProcess);
+  } else {
+    // debug process broken, let's just do a message box
+    MessageBoxW(NULL, &cmdline[0], L"Fatal error",
+                MB_OK | MB_ICONHAND | MB_TOPMOST);
+  }
+#else
+  // We intentionally don't implement a dialog on other platforms.
+  // You can just look at stderr.
+#endif
+}
+
+#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,
+                       int ctr)
+    : severity_(severity), file_(file), line_(line) {
+  Init(file, line);
+}
+
+LogMessage::LogMessage(const char* file, int line)
+    : severity_(LOG_INFO), file_(file), line_(line) {
+  Init(file, line);
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
+    : severity_(severity), file_(file), line_(line) {
+  Init(file, line);
+}
+
+LogMessage::LogMessage(const char* file, int line, std::string* result)
+    : severity_(LOG_FATAL), file_(file), line_(line) {
+  Init(file, line);
+  stream_ << "Check failed: " << *result;
+  delete result;
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+                       std::string* result)
+    : severity_(severity), file_(file), line_(line) {
+  Init(file, line);
+  stream_ << "Check failed: " << *result;
+  delete result;
+}
+
+LogMessage::~LogMessage() {
+  // TODO(port): enable stacktrace generation on LOG_FATAL once backtrace are
+  // working in Android.
+#if  !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_NACL)
+  if (severity_ == LOG_FATAL) {
+    // Include a stack trace on a fatal.
+    base::debug::StackTrace trace;
+    stream_ << std::endl;  // Newline to separate from log message.
+    trace.OutputToStream(&stream_);
+  }
+#endif
+  stream_ << std::endl;
+  std::string str_newline(stream_.str());
+
+  // Give any log message handler first dibs on the message.
+  if (log_message_handler && log_message_handler(severity_, file_, line_,
+          message_start_, str_newline)) {
+    // The handler took care of it, no further processing.
+    return;
+  }
+
+  if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
+      logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
+#if defined(OS_WIN)
+    OutputDebugStringA(str_newline.c_str());
+#elif defined(OS_ANDROID)
+    android_LogPriority priority = ANDROID_LOG_UNKNOWN;
+    switch (severity_) {
+      case LOG_INFO:
+        priority = ANDROID_LOG_INFO;
+        break;
+      case LOG_WARNING:
+        priority = ANDROID_LOG_WARN;
+        break;
+      case LOG_ERROR:
+      case LOG_ERROR_REPORT:
+        priority = ANDROID_LOG_ERROR;
+        break;
+      case LOG_FATAL:
+        priority = ANDROID_LOG_FATAL;
+        break;
+    }
+    __android_log_write(priority, "chromium", str_newline.c_str());
+#endif
+    fprintf(stderr, "%s", str_newline.c_str());
+    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.
+    fprintf(stderr, "%s", str_newline.c_str());
+    fflush(stderr);
+  }
+
+  // We can have multiple threads and/or processes, so try to prevent them
+  // from clobbering each other's writes.
+  // If the client app did not call InitLogging, and the lock has not
+  // been created do it now. We do this on demand, but if two threads try
+  // to do this at the same time, there will be a race condition to create
+  // the lock. This is why InitLogging should be called from the main
+  // thread at the beginning of execution.
+  LoggingLock::Init(LOCK_LOG_FILE, NULL);
+  // write to log file
+  if (logging_destination != LOG_NONE &&
+      logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG) {
+    LoggingLock logging_lock;
+    if (InitializeLogFileHandle()) {
+#if defined(OS_WIN)
+      SetFilePointer(log_file, 0, 0, SEEK_END);
+      DWORD num_written;
+      WriteFile(log_file,
+                static_cast<const void*>(str_newline.c_str()),
+                static_cast<DWORD>(str_newline.length()),
+                &num_written,
+                NULL);
+#else
+      fprintf(log_file, "%s", str_newline.c_str());
+      fflush(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);
+
+    // display a message or break into the debugger on a fatal error
+    if (base::debug::BeingDebugged()) {
+      base::debug::BreakDebugger();
+    } else {
+      if (log_assert_handler) {
+        // make a copy of the string for the handler out of paranoia
+        log_assert_handler(std::string(stream_.str()));
+      } else {
+        // Don't use the string with the newline, get a fresh version to send to
+        // the debug message process. We also don't display assertions to the
+        // user in release mode. The enduser can't do anything with this
+        // information, and displaying message boxes when the application is
+        // hosed can cause additional problems.
+#ifndef NDEBUG
+        DisplayDebugMessageInDialog(stream_.str());
+#endif
+        // Crash the process to generate a dump.
+        base::debug::BreakDebugger();
+      }
+    }
+  } else if (severity_ == LOG_ERROR_REPORT) {
+    // We are here only if the user runs with --enable-dcheck in release mode.
+    if (log_report_handler) {
+      log_report_handler(std::string(stream_.str()));
+    } else {
+      DisplayDebugMessageInDialog(stream_.str());
+    }
+  }
+}
+
+// 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 (log_process_id)
+    stream_ << CurrentProcessId() << ':';
+  if (log_thread_id)
+    stream_ << base::PlatformThread::CurrentId() << ':';
+  if (log_timestamp) {
+    time_t t = time(NULL);
+    struct tm local_time = {0};
+#if _MSC_VER >= 1400
+    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 (log_tickcount)
+    stream_ << TickCount() << ':';
+  if (severity_ >= 0)
+    stream_ << log_severity_names[severity_];
+  else
+    stream_ << "VERBOSE" << -severity_;
+
+  stream_ << ":" << filename << "(" << line << ")] ";
+
+  message_start_ = stream_.tellp();
+}
+
+#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)
+Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
+                                           int line,
+                                           LogSeverity severity,
+                                           SystemErrorCode err,
+                                           const char* module)
+    : err_(err),
+      module_(module),
+      log_message_(file, line, severity) {
+}
+
+Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
+                                           int line,
+                                           LogSeverity severity,
+                                           SystemErrorCode err)
+    : err_(err),
+      module_(NULL),
+      log_message_(file, line, severity) {
+}
+
+Win32ErrorLogMessage::~Win32ErrorLogMessage() {
+  const int error_message_buffer_size = 256;
+  char msgbuf[error_message_buffer_size];
+  DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
+  HMODULE hmod;
+  if (module_) {
+    hmod = GetModuleHandleA(module_);
+    if (hmod) {
+      flags |= FORMAT_MESSAGE_FROM_HMODULE;
+    } else {
+      // This makes a nested Win32ErrorLogMessage. It will have module_ of NULL
+      // so it will not call GetModuleHandle, so recursive errors are
+      // impossible.
+      DPLOG(WARNING) << "Couldn't open module " << module_
+          << " for error message query";
+    }
+  } else {
+    hmod = NULL;
+  }
+  DWORD len = FormatMessageA(flags,
+                             hmod,
+                             err_,
+                             0,
+                             msgbuf,
+                             sizeof(msgbuf) / sizeof(msgbuf[0]),
+                             NULL);
+  if (len) {
+    while ((len > 0) &&
+           isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
+      msgbuf[--len] = 0;
+    }
+    stream() << ": " << msgbuf;
+  } else {
+    stream() << ": Error " << GetLastError() << " while retrieving error "
+        << 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() << ": " << safe_strerror(err_);
+}
+#endif  // OS_WIN
+
+void CloseLogFile() {
+  LoggingLock logging_lock;
+
+  if (!log_file)
+    return;
+
+  CloseFile(log_file);
+  log_file = NULL;
+}
+
+void RawLog(int level, const char* message) {
+  if (level >= min_log_level) {
+    size_t bytes_written = 0;
+    const size_t message_len = strlen(message);
+    int rv;
+    while (bytes_written < message_len) {
+      rv = HANDLE_EINTR(
+          write(STDERR_FILENO, message + bytes_written,
+                message_len - bytes_written));
+      if (rv < 0) {
+        // Give up, nothing we can do now.
+        break;
+      }
+      bytes_written += rv;
+    }
+
+    if (message_len > 0 && message[message_len - 1] != '\n') {
+      do {
+        rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
+        if (rv < 0) {
+          // Give up, nothing we can do now.
+          break;
+        }
+      } while (rv != 1);
+    }
+  }
+
+  if (level == LOG_FATAL)
+    base::debug::BreakDebugger();
+}
+
+// This was defined at the beginning of this file.
+#undef write
+
+}  // namespace logging
+
+std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
+  return out << WideToUTF8(std::wstring(wstr));
+}
diff --git a/base/logging.h b/base/logging.h
new file mode 100644
index 0000000..6ea430d
--- /dev/null
+++ b/base/logging.h
@@ -0,0 +1,986 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LOGGING_H_
+#define BASE_LOGGING_H_
+
+#include <cassert>
+#include <string>
+#include <cstring>
+#include <sstream>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/debug/debugger.h"
+#include "build/build_config.h"
+
+//
+// Optional message capabilities
+// -----------------------------
+// Assertion failed messages and fatal errors are displayed in a dialog box
+// before the application exits. However, running this UI creates a message
+// loop, which causes application messages to be processed and potentially
+// dispatched to existing application windows. Since the application is in a
+// bad state when this assertion dialog is displayed, these messages may not
+// get processed and hang the dialog, or the application might go crazy.
+//
+// Therefore, it can be beneficial to display the error dialog in a separate
+// process from the main application. When the logging system needs to display
+// a fatal error dialog box, it will look for a program called
+// "DebugMessage.exe" in the same directory as the application executable. It
+// will run this application with the message as the command line, and will
+// not include the name of the application as is traditional for easier
+// parsing.
+//
+// The code for DebugMessage.exe is only one line. In WinMain, do:
+//   MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);
+//
+// If DebugMessage.exe is not found, the logging code will use a normal
+// MessageBox, potentially causing the problems discussed above.
+
+
+// Instructions
+// ------------
+//
+// Make a bunch of macros for logging.  The way to log things is to stream
+// things to LOG(<a particular severity level>).  E.g.,
+//
+//   LOG(INFO) << "Found " << num_cookies << " cookies";
+//
+// You can also do conditional logging:
+//
+//   LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// The above will cause log messages to be output on the 1st, 11th, 21st, ...
+// times it is executed.  Note that the special COUNTER value is used to
+// identify which repetition is happening.
+//
+// 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, ERROR_REPORT,
+// and FATAL.
+//
+// Very important: logging a message at the FATAL severity level causes
+// the program to terminate (after the message is logged).
+//
+// Note the special severity of ERROR_REPORT only available/relevant in normal
+// mode, which displays error dialog without terminating the program. There is
+// no error dialog for severity ERROR or below in normal mode.
+//
+// There is also the special severity of DFATAL, which logs FATAL in
+// debug mode, ERROR in normal mode.
+
+namespace logging {
+
+// Where to record logging output? A flat file and/or system debug log via
+// OutputDebugString. Defaults on Windows to LOG_ONLY_TO_FILE, and on
+// POSIX to LOG_ONLY_TO_SYSTEM_DEBUG_LOG (aka stderr).
+enum LoggingDestination { LOG_NONE,
+                          LOG_ONLY_TO_FILE,
+                          LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
+                          LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG };
+
+// Indicates that the log file should be locked when being written to.
+// Often, there is no locking, which is fine for a single threaded program.
+// If logging is being done from multiple threads or there can be more than
+// one process doing the logging, the file should be locked during writes to
+// make each log outut atomic. Other writers will block.
+//
+// All processes writing to the log file must have their locking set for it to
+// work properly. Defaults to DONT_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 };
+
+enum DcheckState {
+  DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS,
+  ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS
+};
+
+// 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
+
+// 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 PathChar* log_file,
+                                     LoggingDestination logging_dest,
+                                     LogLockingState lock_log,
+                                     OldFileDeletionState delete_old,
+                                     DcheckState dcheck_state);
+
+// 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 PathChar* log_file,
+                        LoggingDestination logging_dest,
+                        LogLockingState lock_log,
+                        OldFileDeletionState delete_old,
+                        DcheckState dcheck_state) {
+  return BaseInitLoggingImpl(log_file, logging_dest, lock_log,
+                             delete_old, dcheck_state);
+}
+
+// Sets the log level. Anything at or above this level will be written to the
+// log file/displayed to the user (if applicable). Anything below this level
+// will be silently ignored. The log level defaults to 0 (everything is logged
+// up to level INFO) if this function is not called.
+// Note that log messages for VLOG(x) are logged at level -x, so setting
+// the min log level to negative values enables verbose logging.
+BASE_EXPORT void SetMinLogLevel(int level);
+
+// Gets the current log level.
+BASE_EXPORT int GetMinLogLevel();
+
+// Gets the VLOG default verbosity level.
+BASE_EXPORT int GetVlogVerbosity();
+
+// Gets the current vlog level for the given file (usually taken from
+// __FILE__).
+
+// Note that |N| is the size *with* the null terminator.
+BASE_EXPORT int GetVlogLevelHelper(const char* file_start, size_t N);
+
+template <size_t N>
+int GetVlogLevel(const char (&file)[N]) {
+  return GetVlogLevelHelper(file, N);
+}
+
+// Sets the common items you want to be prepended to each log message.
+// process and thread IDs default to off, the timestamp defaults to on.
+// If this function is not called, logging defaults to writing the timestamp
+// only.
+BASE_EXPORT void SetLogItems(bool enable_process_id, bool enable_thread_id,
+                             bool enable_timestamp, bool enable_tickcount);
+
+// Sets whether or not you'd like to see fatal debug messages popped up in
+// a dialog box or not.
+// Dialogs are not shown by default.
+BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs);
+
+// Sets the Log Assert Handler that will be used to notify of check failures.
+// The default handler shows a dialog box and then terminate the process,
+// however clients can use this function to override with their own handling
+// (e.g. a silent one for Unit Tests)
+typedef void (*LogAssertHandlerFunction)(const std::string& str);
+BASE_EXPORT void SetLogAssertHandler(LogAssertHandlerFunction handler);
+
+// Sets the Log Report Handler that will be used to notify of check failures
+// in non-debug mode. The default handler shows a dialog box and continues
+// the execution, however clients can use this function to override with their
+// own handling.
+typedef void (*LogReportHandlerFunction)(const std::string& str);
+BASE_EXPORT void SetLogReportHandler(LogReportHandlerFunction 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_ERROR_REPORT = 3;
+const LogSeverity LOG_FATAL = 4;
+const LogSeverity LOG_NUM_SEVERITIES = 5;
+
+// 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_ERROR_REPORT(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, \
+                     logging::LOG_ERROR_REPORT , ##__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_ERROR_REPORT \
+  COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(LogMessage)
+#define COMPACT_GOOGLE_LOG_FATAL \
+  COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
+#define COMPACT_GOOGLE_LOG_DFATAL \
+  COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
+
+// 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;
+
+// As special cases, we can assume that LOG_IS_ON(ERROR_REPORT) and
+// LOG_IS_ON(FATAL) always hold.  Also, LOG_IS_ON(DFATAL) always holds
+// in debug mode.  In particular, CHECK()s will always fire if they
+// fail.
+#define LOG_IS_ON(severity) \
+  ((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel())
+
+// We can't do any caching tricks with VLOG_IS_ON() like the
+// google-glog version since it requires GCC extensions.  This means
+// that using the v-logging functions in conjunction with --vmodule
+// may be slow.
+#define VLOG_IS_ON(verboselevel) \
+  ((verboselevel) <= ::logging::GetVlogLevel(__FILE__))
+
+// Helper macro which avoids evaluating the arguments to a stream if
+// the condition doesn't hold.
+#define LAZY_STREAM(stream, condition)                                  \
+  !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO.  There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
+
+#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity))
+#define LOG_IF(severity, condition) \
+  LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+#define SYSLOG(severity) LOG(severity)
+#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
+
+// The VLOG macros log with negative verbosities.
+#define VLOG_STREAM(verbose_level) \
+  logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
+
+#define VLOG(verbose_level) \
+  LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VLOG_IF(verbose_level, condition) \
+  LAZY_STREAM(VLOG_STREAM(verbose_level), \
+      VLOG_IS_ON(verbose_level) && (condition))
+
+#if defined (OS_WIN)
+#define VPLOG_STREAM(verbose_level) \
+  logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
+    ::logging::GetLastSystemErrorCode()).stream()
+#elif defined(OS_POSIX)
+#define VPLOG_STREAM(verbose_level) \
+  logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
+    ::logging::GetLastSystemErrorCode()).stream()
+#endif
+
+#define VPLOG(verbose_level) \
+  LAZY_STREAM(VPLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VPLOG_IF(verbose_level, condition) \
+  LAZY_STREAM(VPLOG_STREAM(verbose_level), \
+    VLOG_IS_ON(verbose_level) && (condition))
+
+// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
+
+#define LOG_ASSERT(condition)  \
+  LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+#define SYSLOG_ASSERT(condition) \
+  SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+
+#if defined(OS_WIN)
+#define LOG_GETLASTERROR_STREAM(severity) \
+  COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
+      ::logging::GetLastSystemErrorCode()).stream()
+#define LOG_GETLASTERROR(severity) \
+  LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity), LOG_IS_ON(severity))
+#define LOG_GETLASTERROR_MODULE_STREAM(severity, module) \
+  COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
+      ::logging::GetLastSystemErrorCode(), module).stream()
+#define LOG_GETLASTERROR_MODULE(severity, module)                       \
+  LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity, module),                \
+              LOG_IS_ON(severity))
+// PLOG_STREAM is used by PLOG, which is the usual error logging macro
+// for each platform.
+#define PLOG_STREAM(severity) LOG_GETLASTERROR_STREAM(severity)
+#elif defined(OS_POSIX)
+#define LOG_ERRNO_STREAM(severity) \
+  COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \
+      ::logging::GetLastSystemErrorCode()).stream()
+#define LOG_ERRNO(severity) \
+  LAZY_STREAM(LOG_ERRNO_STREAM(severity), LOG_IS_ON(severity))
+// PLOG_STREAM is used by PLOG, which is the usual error logging macro
+// for each platform.
+#define PLOG_STREAM(severity) LOG_ERRNO_STREAM(severity)
+#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))
+
+// http://crbug.com/16512 is open for a real fix for this.  For now, Windows
+// uses OFFICIAL_BUILD and other platforms use the branding flag when NDEBUG is
+// defined.
+#if ( defined(OS_WIN) && defined(OFFICIAL_BUILD)) || \
+    (!defined(OS_WIN) && defined(NDEBUG) && defined(GOOGLE_CHROME_BUILD))
+#define LOGGING_IS_OFFICIAL_BUILD 1
+#else
+#define LOGGING_IS_OFFICIAL_BUILD 0
+#endif
+
+// The actual stream used isn't important.
+#define EAT_STREAM_PARAMETERS                                           \
+  true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
+
+// CHECK dies with a fatal error if condition is not true.  It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode.
+//
+// We make sure CHECK et al. always evaluates their arguments, as
+// doing CHECK(FunctionWithSideEffect()) is a common idiom.
+
+#if LOGGING_IS_OFFICIAL_BUILD
+
+// Make all CHECK functions discard their log strings to reduce code
+// bloat for official builds.
+
+// TODO(akalin): This would be more valuable if there were some way to
+// remove BreakDebugger() from the backtrace, perhaps by turning it
+// into a macro (like __debugbreak() on Windows).
+#define CHECK(condition)                                                \
+  !(condition) ? ::base::debug::BreakDebugger() : EAT_STREAM_PARAMETERS
+
+#define PCHECK(condition) CHECK(condition)
+
+#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2))
+
+#else
+
+#define CHECK(condition)                       \
+  LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
+  << "Check failed: " #condition ". "
+
+#define PCHECK(condition) \
+  LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
+  << "Check failed: " #condition ". "
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+//
+// TODO(akalin): Rewrite this so that constructs like if (...)
+// CHECK_EQ(...) else { ... } work properly.
+#define CHECK_OP(name, op, val1, val2)                          \
+  if (std::string* _result =                                    \
+      logging::Check##name##Impl((val1), (val2),                \
+                                 #val1 " " #op " " #val2))      \
+    logging::LogMessage(__FILE__, __LINE__, _result).stream()
+
+#endif
+
+// Build the error message string.  This is separate from the "Impl"
+// function template because it is not performance critical and so can
+// be out of line, while the "Impl" code should be inline.  Caller
+// takes ownership of the returned string.
+template<class t1, class t2>
+std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
+  std::ostringstream ss;
+  ss << names << " (" << v1 << " vs. " << v2 << ")";
+  std::string* msg = new std::string(ss.str());
+  return msg;
+}
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+// 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);
+#endif
+
+// 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 LOGGING_IS_OFFICIAL_BUILD
+// In order to have optimized code for official builds, remove DLOGs and
+// DCHECKs.
+#define ENABLE_DLOG 0
+#define ENABLE_DCHECK 0
+
+#elif defined(NDEBUG)
+// Otherwise, if we're a release build, remove DLOGs but not DCHECKs
+// (since those can still be turned on via a command-line flag).
+#define ENABLE_DLOG 0
+#define ENABLE_DCHECK 1
+
+#else
+// Otherwise, we're a debug build so enable DLOGs and DCHECKs.
+#define ENABLE_DLOG 1
+#define ENABLE_DCHECK 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))
+
+#if defined(OS_WIN)
+#define DLOG_GETLASTERROR(severity) \
+  LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity), DLOG_IS_ON(severity))
+#define DLOG_GETLASTERROR_MODULE(severity, module)                      \
+  LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity, module),                \
+              DLOG_IS_ON(severity))
+#elif defined(OS_POSIX)
+#define DLOG_ERRNO(severity)                                    \
+  LAZY_STREAM(LOG_ERRNO_STREAM(severity), DLOG_IS_ON(severity))
+#endif
+
+#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 ENABLE_DCHECK
+
+#if defined(NDEBUG)
+
+BASE_EXPORT extern DcheckState g_dcheck_state;
+
+#if defined(DCHECK_ALWAYS_ON)
+
+#define DCHECK_IS_ON() true
+#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
+
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+  COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_ERROR_REPORT
+const LogSeverity LOG_DCHECK = LOG_ERROR_REPORT;
+#define DCHECK_IS_ON()                                                  \
+  ((::logging::g_dcheck_state ==                                        \
+    ::logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS) &&        \
+   LOG_IS_ON(DCHECK))
+
+#endif  // defined(DCHECK_ALWAYS_ON)
+
+#else  // defined(NDEBUG)
+
+// On a regular debug build, we want to have DCHECKs enabled.
+#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;
+#define DCHECK_IS_ON() true
+
+#endif  // defined(NDEBUG)
+
+#else  // ENABLE_DCHECK
+
+// These are just dummy values since DCHECK_IS_ON() is always false in
+// this case.
+#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;
+#define DCHECK_IS_ON() false
+
+#endif  // ENABLE_DCHECK
+#undef ENABLE_DCHECK
+
+// 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.
+
+#define DCHECK(condition)                                           \
+  LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition))   \
+  << "Check failed: " #condition ". "
+
+#define DPCHECK(condition)                                          \
+  LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition))  \
+  << "Check failed: " #condition ". "
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use DCHECK_EQ et al below.
+#define DCHECK_OP(name, op, val1, val2)                         \
+  if (DCHECK_IS_ON())                                           \
+    if (std::string* _result =                                  \
+        logging::Check##name##Impl((val1), (val2),              \
+                                   #val1 " " #op " " #val2))    \
+      logging::LogMessage(                                      \
+          __FILE__, __LINE__, ::logging::LOG_DCHECK,            \
+          _result).stream()
+
+// Equality/Inequality checks - compare two values, and log a
+// LOG_DCHECK message including the two values when the result is not
+// as expected.  The values must have operator<<(ostream, ...)
+// defined.
+//
+// You may append to the error message like so:
+//   DCHECK_NE(1, 2) << ": The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here.  In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+//   DCHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These may not compile correctly if one of the arguments is a pointer
+// and the other is NULL. To work around this, simply static_cast NULL to the
+// type of the desired pointer.
+
+#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
+#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
+#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
+#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
+#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
+#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
+
+#define NOTREACHED() DCHECK(false)
+
+// 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:
+  LogMessage(const char* file, int line, LogSeverity severity, int ctr);
+
+  // Two special constructors that generate reduced amounts of code at
+  // LOG call sites for common cases.
+  //
+  // Used for LOG(INFO): Implied are:
+  // severity = LOG_INFO, ctr = 0
+  //
+  // Using this constructor instead of the more complex constructor above
+  // saves a couple of bytes per call site.
+  LogMessage(const char* file, int line);
+
+  // Used for LOG(severity) where severity != INFO.  Implied
+  // are: ctr = 0
+  //
+  // Using this constructor instead of the more complex constructor above
+  // saves a couple of bytes per call site.
+  LogMessage(const char* file, int line, LogSeverity severity);
+
+  // A special constructor used for check failures.  Takes ownership
+  // of the given string.
+  // Implied severity = LOG_FATAL
+  LogMessage(const char* file, int line, std::string* result);
+
+  // A special constructor used for check failures, with the option to
+  // specify severity.  Takes ownership of the given string.
+  LogMessage(const char* file, int line, LogSeverity severity,
+             std::string* result);
+
+  ~LogMessage();
+
+  std::ostream& stream() { return stream_; }
+
+ private:
+  void Init(const char* file, int line);
+
+  LogSeverity severity_;
+  std::ostringstream stream_;
+  size_t message_start_;  // Offset of the start of the message (past prefix
+                          // info).
+  // The file and line information passed in to the constructor.
+  const char* file_;
+  const int line_;
+
+#if defined(OS_WIN)
+  // Stores the current value of GetLastError in the constructor and restores
+  // it in the destructor by calling SetLastError.
+  // This is useful since the LogMessage class uses a lot of Win32 calls
+  // that will lose the value of GLE and the code that called the log function
+  // will have lost the thread error value when the log call returns.
+  class SaveLastError {
+   public:
+    SaveLastError();
+    ~SaveLastError();
+
+    unsigned long get_error() const { return last_error_; }
+
+   protected:
+    unsigned long last_error_;
+  };
+
+  SaveLastError last_error_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(LogMessage);
+};
+
+// A non-macro interface to the log facility; (useful
+// when the logging level is not a compile-time constant).
+inline void LogAtLevel(int const log_level, std::string const &msg) {
+  LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
+}
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros.  This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+class LogMessageVoidify {
+ public:
+  LogMessageVoidify() { }
+  // This has to be an operator with a precedence lower than << but
+  // higher than ?:
+  void operator&(std::ostream&) { }
+};
+
+#if defined(OS_WIN)
+typedef unsigned long SystemErrorCode;
+#elif defined(OS_POSIX)
+typedef int SystemErrorCode;
+#endif
+
+// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
+// pull in windows.h just for GetLastError() and DWORD.
+BASE_EXPORT SystemErrorCode GetLastSystemErrorCode();
+
+#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,
+                       const char* module);
+
+  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_;
+  // Optional name of the module defining the error.
+  const char* module_;
+  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)
+
+}  // namespace logging
+
+// 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();
+}
+
+// The NOTIMPLEMENTED() macro annotates codepaths which have
+// not been implemented yet.
+//
+// The implementation of this macro is controlled by NOTIMPLEMENTED_POLICY:
+//   0 -- Do nothing (stripped by compiler)
+//   1 -- Warn at compile time
+//   2 -- Fail at compile time
+//   3 -- Fail at runtime (DCHECK)
+//   4 -- [default] LOG(ERROR) at runtime
+//   5 -- LOG(ERROR) at runtime, only once per call-site
+
+#ifndef NOTIMPLEMENTED_POLICY
+#if defined(OS_ANDROID) && defined(OFFICIAL_BUILD)
+#define NOTIMPLEMENTED_POLICY 0
+#else
+// Select default policy: LOG(ERROR)
+#define NOTIMPLEMENTED_POLICY 4
+#endif
+#endif
+
+#if defined(COMPILER_GCC)
+// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name
+// of the current function in the NOTIMPLEMENTED message.
+#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__
+#else
+#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED"
+#endif
+
+#if NOTIMPLEMENTED_POLICY == 0
+#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS
+#elif NOTIMPLEMENTED_POLICY == 1
+// TODO, figure out how to generate a warning
+#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#elif NOTIMPLEMENTED_POLICY == 2
+#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#elif NOTIMPLEMENTED_POLICY == 3
+#define NOTIMPLEMENTED() NOTREACHED()
+#elif NOTIMPLEMENTED_POLICY == 4
+#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG
+#elif NOTIMPLEMENTED_POLICY == 5
+#define NOTIMPLEMENTED() do {\
+  static int count = 0;\
+  LOG_IF(ERROR, 0 == count++) << NOTIMPLEMENTED_MSG;\
+} while(0)
+#endif
+
+#endif  // BASE_LOGGING_H_
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc
new file mode 100644
index 0000000..760cc24
--- /dev/null
+++ b/base/logging_unittest.cc
@@ -0,0 +1,261 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace logging {
+
+namespace {
+
+using ::testing::Return;
+
+// Needs to be global since log assert handlers can't maintain state.
+int log_sink_call_count = 0;
+
+void LogSink(const std::string& str) {
+  ++log_sink_call_count;
+}
+
+// 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);
+    SetLogReportHandler(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;
+  const int kExpectedDebugOrReleaseCalls = 6;
+  const int kExpectedDebugCalls = 6;
+  const int kExpectedCalls =
+      kExpectedDebugOrReleaseCalls + (DEBUG_MODE ? kExpectedDebugCalls : 0);
+  EXPECT_CALL(mock_log_source, Log()).Times(kExpectedCalls).
+      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_EQ(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();
+
+  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();
+}
+
+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(ERROR_REPORT));
+  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(ERROR_REPORT));
+  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(ERROR_REPORT));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_TRUE(LOG_IS_ON(DFATAL));
+
+  SetMinLogLevel(LOG_ERROR_REPORT);
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_FALSE(LOG_IS_ON(WARNING));
+  EXPECT_FALSE(LOG_IS_ON(ERROR));
+  EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_EQ(kDfatalIsFatal, LOG_IS_ON(DFATAL));
+
+  // LOG_IS_ON(ERROR_REPORT) should always be true.
+  SetMinLogLevel(LOG_FATAL);
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_FALSE(LOG_IS_ON(WARNING));
+  EXPECT_FALSE(LOG_IS_ON(ERROR));
+  EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_EQ(kDfatalIsFatal, LOG_IS_ON(DFATAL));
+
+  // So should LOG_IS_ON(FATAL).
+  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(ERROR_REPORT));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_EQ(kDfatalIsFatal, LOG_IS_ON(DFATAL));
+}
+
+TEST_F(LoggingTest, LoggingIsLazy) {
+  MockLogSource mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(0);
+
+  SetMinLogLevel(LOG_WARNING);
+
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_FALSE(DLOG_IS_ON(INFO));
+  EXPECT_FALSE(VLOG_IS_ON(1));
+
+  LOG(INFO) << mock_log_source.Log();
+  LOG_IF(INFO, false) << mock_log_source.Log();
+  PLOG(INFO) << mock_log_source.Log();
+  PLOG_IF(INFO, false) << mock_log_source.Log();
+  VLOG(1) << mock_log_source.Log();
+  VLOG_IF(1, true) << mock_log_source.Log();
+
+  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();
+}
+
+// Official builds have CHECKs directly call BreakDebugger.
+#if !defined(LOGGING_IS_OFFICIAL_BUILD)
+
+TEST_F(LoggingTest, CheckStreamsAreLazy) {
+  MockLogSource mock_log_source, uncalled_mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(8).
+      WillRepeatedly(Return("check message"));
+  EXPECT_CALL(uncalled_mock_log_source, Log()).Times(0);
+
+  SetLogAssertHandler(&LogSink);
+
+  CHECK(mock_log_source.Log()) << uncalled_mock_log_source.Log();
+  PCHECK(!mock_log_source.Log()) << mock_log_source.Log();
+  CHECK_EQ(mock_log_source.Log(), mock_log_source.Log())
+      << uncalled_mock_log_source.Log();
+  CHECK_NE(mock_log_source.Log(), mock_log_source.Log())
+      << mock_log_source.Log();
+}
+
+#endif
+
+TEST_F(LoggingTest, DebugLoggingReleaseBehavior) {
+#if !defined(NDEBUG)
+  int debug_only_variable = 1;
+#endif
+  // These should avoid emitting references to |debug_only_variable|
+  // in release mode.
+  DLOG_IF(INFO, debug_only_variable) << "test";
+  DLOG_ASSERT(debug_only_variable) << "test";
+  DPLOG_IF(INFO, debug_only_variable) << "test";
+  DVLOG_IF(1, debug_only_variable) << "test";
+}
+
+TEST_F(LoggingTest, DcheckStreamsAreLazy) {
+  MockLogSource mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(0);
+#if !defined(LOGGING_IS_OFFICIAL_BUILD) && defined(NDEBUG) && \
+    !defined(DCHECK_ALWAYS_ON)
+  // Unofficial release build without dcheck enabled.
+  g_dcheck_state = DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
+  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 LOGGING_IS_OFFICIAL_BUILD
+  // Official build.
+  EXPECT_FALSE(DCHECK_IS_ON());
+  EXPECT_FALSE(DLOG_IS_ON(DCHECK));
+#elif defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+  // Unofficial release build.
+  g_dcheck_state = ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
+  SetLogReportHandler(&LogSink);
+  EXPECT_TRUE(DCHECK_IS_ON());
+  EXPECT_FALSE(DLOG_IS_ON(DCHECK));
+#elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON)
+  // Unofficial release build with real DCHECKS.
+  g_dcheck_state = ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
+  SetLogAssertHandler(&LogSink);
+  EXPECT_TRUE(DCHECK_IS_ON());
+  EXPECT_FALSE(DLOG_IS_ON(DCHECK));
+#else
+  // Unofficial debug build.
+  SetLogAssertHandler(&LogSink);
+  EXPECT_TRUE(DCHECK_IS_ON());
+  EXPECT_TRUE(DLOG_IS_ON(DCHECK));
+#endif  // defined(LOGGING_IS_OFFICIAL_BUILD)
+
+  EXPECT_EQ(0, log_sink_call_count);
+  DCHECK(false);
+  EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count);
+  DPCHECK(false);
+  EXPECT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count);
+  DCHECK_EQ(0, 1);
+  EXPECT_EQ(DCHECK_IS_ON() ? 3 : 0, log_sink_call_count);
+}
+
+TEST_F(LoggingTest, DcheckReleaseBehavior) {
+  int some_variable = 1;
+  // These should still reference |some_variable| so we don't get
+  // unused variable warnings.
+  DCHECK(some_variable) << "test";
+  DPCHECK(some_variable) << "test";
+  DCHECK_EQ(some_variable, 1) << "test";
+}
+
+}  // namespace
+
+}  // namespace logging
diff --git a/base/logging_win.cc b/base/logging_win.cc
new file mode 100644
index 0000000..a714665
--- /dev/null
+++ b/base/logging_win.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging_win.h"
+#include "base/memory/singleton.h"
+#include <initguid.h>  // NOLINT
+
+namespace logging {
+
+using base::win::EtwEventLevel;
+using base::win::EtwMofEvent;
+
+DEFINE_GUID(kLogEventId,
+    0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7);
+
+LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) {
+}
+
+LogEventProvider* LogEventProvider::GetInstance() {
+  return Singleton<LogEventProvider,
+                   StaticMemorySingletonTraits<LogEventProvider> >::get();
+}
+
+bool LogEventProvider::LogMessage(logging::LogSeverity severity,
+    const char* file, int line, size_t message_start,
+    const std::string& message) {
+  EtwEventLevel level = TRACE_LEVEL_NONE;
+
+  // Convert the log severity to the most appropriate ETW trace level.
+  if (severity >= 0) {
+    switch (severity) {
+      case LOG_INFO:
+        level = TRACE_LEVEL_INFORMATION;
+        break;
+      case LOG_WARNING:
+        level = TRACE_LEVEL_WARNING;
+        break;
+      case LOG_ERROR:
+      case LOG_ERROR_REPORT:
+        level = TRACE_LEVEL_ERROR;
+        break;
+      case LOG_FATAL:
+        level = TRACE_LEVEL_FATAL;
+        break;
+    }
+  } else {  // severity < 0 is VLOG verbosity levels.
+    level = TRACE_LEVEL_INFORMATION - severity;
+  }
+
+  // Bail if we're not logging, not at that level,
+  // or if we're post-atexit handling.
+  LogEventProvider* provider = LogEventProvider::GetInstance();
+  if (provider == NULL || level > provider->enable_level())
+    return false;
+
+  // And now log the event.
+  if (provider->enable_flags() & ENABLE_LOG_MESSAGE_ONLY) {
+    EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level);
+    event.SetField(0, message.length() + 1 - message_start,
+        message.c_str() + message_start);
+
+    provider->Log(event.get());
+  } else {
+    const size_t kMaxBacktraceDepth = 32;
+    void* backtrace[kMaxBacktraceDepth];
+    DWORD depth = 0;
+
+    // Capture a stack trace if one is requested.
+    // requested per our enable flags.
+    if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE)
+      depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL);
+
+    EtwMofEvent<5> event(kLogEventId, LOG_MESSAGE_FULL, level);
+    if (file == NULL)
+      file = "";
+
+    // Add the stack trace.
+    event.SetField(0, sizeof(depth), &depth);
+    event.SetField(1, sizeof(backtrace[0]) * depth, &backtrace);
+    // The line.
+    event.SetField(2, sizeof(line), &line);
+    // The file.
+    event.SetField(3, strlen(file) + 1, file);
+    // And finally the message.
+    event.SetField(4, message.length() + 1 - message_start,
+        message.c_str() + message_start);
+
+    provider->Log(event.get());
+  }
+
+  // Don't increase verbosity in other log destinations.
+  if (severity < provider->old_log_level_)
+    return true;
+
+  return false;
+}
+
+void LogEventProvider::Initialize(const GUID& provider_name) {
+  LogEventProvider* provider = LogEventProvider::GetInstance();
+
+  provider->set_provider_name(provider_name);
+  provider->Register();
+
+  // Register our message handler with logging.
+  SetLogMessageHandler(LogMessage);
+}
+
+void LogEventProvider::Uninitialize() {
+  LogEventProvider::GetInstance()->Unregister();
+}
+
+void LogEventProvider::OnEventsEnabled() {
+  // Grab the old log level so we can restore it later.
+  old_log_level_ = GetMinLogLevel();
+
+  // Convert the new trace level to a logging severity
+  // and enable logging at that level.
+  EtwEventLevel level = enable_level();
+  if (level == TRACE_LEVEL_NONE || level == TRACE_LEVEL_FATAL) {
+    SetMinLogLevel(LOG_FATAL);
+  } else if (level == TRACE_LEVEL_ERROR) {
+    SetMinLogLevel(LOG_ERROR);
+  } else if (level == TRACE_LEVEL_WARNING) {
+    SetMinLogLevel(LOG_WARNING);
+  } else if (level == TRACE_LEVEL_INFORMATION) {
+    SetMinLogLevel(LOG_INFO);
+  } else if (level >= TRACE_LEVEL_VERBOSE) {
+    // Above INFO, we enable verbose levels with negative severities.
+    SetMinLogLevel(TRACE_LEVEL_INFORMATION - level);
+  }
+}
+
+void LogEventProvider::OnEventsDisabled() {
+  // Restore the old log level.
+  SetMinLogLevel(old_log_level_);
+}
+
+}  // namespace logging
diff --git a/base/logging_win.h b/base/logging_win.h
new file mode 100644
index 0000000..0720231
--- /dev/null
+++ b/base/logging_win.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LOGGING_WIN_H_
+#define BASE_LOGGING_WIN_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/win/event_trace_provider.h"
+#include "base/logging.h"
+
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace logging {
+
+// Event ID for the log messages we generate.
+BASE_EXPORT extern const GUID kLogEventId;
+
+// Feature enable mask for LogEventProvider.
+enum LogEnableMask {
+  // If this bit is set in our provider enable mask, we will include
+  // a stack trace with every log message.
+  ENABLE_STACK_TRACE_CAPTURE = 0x0001,
+  // If this bit is set in our provider enable mask, the provider will log
+  // a LOG message with only the textual content of the message, and no
+  // stack trace.
+  ENABLE_LOG_MESSAGE_ONLY = 0x0002,
+};
+
+// The message types our log event provider generates.
+// ETW likes user message types to start at 10.
+enum LogMessageTypes {
+  // A textual only log message, contains a zero-terminated string.
+  LOG_MESSAGE = 10,
+  // A message with a stack trace, followed by the zero-terminated
+  // message text.
+  LOG_MESSAGE_WITH_STACKTRACE = 11,
+  // A message with:
+  //  a stack trace,
+  //  the line number as a four byte integer,
+  //  the file as a zero terminated UTF8 string,
+  //  the zero-terminated UTF8 message text.
+  LOG_MESSAGE_FULL = 12,
+};
+
+// Trace provider class to drive log control and transport
+// with Event Tracing for Windows.
+class BASE_EXPORT LogEventProvider : public base::win::EtwTraceProvider {
+ public:
+  static LogEventProvider* GetInstance();
+
+  static bool LogMessage(logging::LogSeverity severity, const char* file,
+      int line, size_t message_start, const std::string& str);
+
+  static void Initialize(const GUID& provider_name);
+  static void Uninitialize();
+
+ protected:
+  // Overridden to manipulate the log level on ETW control callbacks.
+  virtual void OnEventsEnabled();
+  virtual void OnEventsDisabled();
+
+ private:
+  LogEventProvider();
+
+  // The log severity prior to OnEventsEnabled,
+  // restored in OnEventsDisabled.
+  logging::LogSeverity old_log_level_;
+
+  friend struct StaticMemorySingletonTraits<LogEventProvider>;
+  DISALLOW_COPY_AND_ASSIGN(LogEventProvider);
+};
+
+}  // namespace logging
+
+#endif  // BASE_LOGGING_WIN_H_
diff --git a/base/mac/OWNERS b/base/mac/OWNERS
new file mode 100644
index 0000000..a3fc32f
--- /dev/null
+++ b/base/mac/OWNERS
@@ -0,0 +1,2 @@
+mark@chromium.org
+thakis@chromium.org
diff --git a/base/mac/authorization_util.h b/base/mac/authorization_util.h
new file mode 100644
index 0000000..b34348d
--- /dev/null
+++ b/base/mac/authorization_util.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_MAC_AUTHORIZATION_UTIL_H_
+#define BASE_MAC_AUTHORIZATION_UTIL_H_
+
+// AuthorizationExecuteWithPrivileges fork()s and exec()s the tool, but it
+// does not wait() for it.  It also doesn't provide the caller with access to
+// the forked pid.  If used irresponsibly, zombie processes will accumulate.
+//
+// Apple's really gotten us between a rock and a hard place, here.
+//
+// Fortunately, AuthorizationExecuteWithPrivileges does give access to the
+// tool's stdout (and stdin) via a FILE* pipe.  The tool can output its pid
+// to this pipe, and the main program can read it, and then have something
+// that it can wait() for.
+//
+// The contract is that any tool executed by the wrappers declared in this
+// file must print its pid to stdout on a line by itself before doing anything
+// else.
+//
+// http://developer.apple.com/library/mac/#samplecode/BetterAuthorizationSample/Listings/BetterAuthorizationSampleLib_c.html
+// (Look for "What's This About Zombies?")
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Authorization.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// Obtains an AuthorizationRef that can be used to run commands as root.  If
+// necessary, prompts the user for authentication.  If the user is prompted,
+// |prompt| will be used as the prompt string and an icon appropriate for the
+// application will be displayed in a prompt dialog.  Note that the system
+// appends its own text to the prompt string.  Returns NULL on failure.
+BASE_EXPORT
+AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt);
+
+// Calls straight through to AuthorizationExecuteWithPrivileges.  If that
+// call succeeds, |pid| will be set to the pid of the executed tool.  If the
+// pid can't be determined, |pid| will be set to -1.  |pid| must not be NULL.
+// |pipe| may be NULL, but the tool will always be executed with a pipe in
+// order to read the pid from its stdout.
+BASE_EXPORT
+OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
+                                        const char* tool_path,
+                                        AuthorizationFlags options,
+                                        const char** arguments,
+                                        FILE** pipe,
+                                        pid_t* pid);
+
+// Calls ExecuteWithPrivilegesAndGetPID, and if that call succeeds, calls
+// waitpid() to wait for the process to exit.  If waitpid() succeeds, the
+// exit status is placed in |exit_status|, otherwise, -1 is stored.
+// |exit_status| may be NULL and this function will still wait for the process
+// to exit.
+BASE_EXPORT
+OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
+                                      const char* tool_path,
+                                      AuthorizationFlags options,
+                                      const char** arguments,
+                                      FILE** pipe,
+                                      int* exit_status);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_AUTHORIZATION_UTIL_H_
diff --git a/base/mac/authorization_util.mm b/base/mac/authorization_util.mm
new file mode 100644
index 0000000..a9fac3e
--- /dev/null
+++ b/base/mac/authorization_util.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/mac/authorization_util.h"
+
+#import <Foundation/Foundation.h>
+#include <sys/wait.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/mac_logging.h"
+#import "base/mac/mac_util.h"
+#include "base/mac/scoped_authorizationref.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+
+namespace base {
+namespace mac {
+
+AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) {
+  // Create an empty AuthorizationRef.
+  ScopedAuthorizationRef authorization;
+  OSStatus status = AuthorizationCreate(NULL,
+                                        kAuthorizationEmptyEnvironment,
+                                        kAuthorizationFlagDefaults,
+                                        &authorization);
+  if (status != errAuthorizationSuccess) {
+    OSSTATUS_LOG(ERROR, status) << "AuthorizationCreate";
+    return NULL;
+  }
+
+  // Specify the "system.privilege.admin" right, which allows
+  // AuthorizationExecuteWithPrivileges to run commands as root.
+  AuthorizationItem right_items[] = {
+    {kAuthorizationRightExecute, 0, NULL, 0}
+  };
+  AuthorizationRights rights = {arraysize(right_items), right_items};
+
+  // product_logo_32.png is used instead of app.icns because Authorization
+  // Services can't deal with .icns files.
+  NSString* icon_path =
+      [base::mac::FrameworkBundle() pathForResource:@"product_logo_32"
+                                             ofType:@"png"];
+  const char* icon_path_c = [icon_path fileSystemRepresentation];
+  size_t icon_path_length = icon_path_c ? strlen(icon_path_c) : 0;
+
+  // The OS will append " Type an administrator's name and password to allow
+  // <CFBundleDisplayName> to make changes."
+  NSString* prompt_ns = base::mac::CFToNSCast(prompt);
+  const char* prompt_c = [prompt_ns UTF8String];
+  size_t prompt_length = prompt_c ? strlen(prompt_c) : 0;
+
+  AuthorizationItem environment_items[] = {
+    {kAuthorizationEnvironmentIcon, icon_path_length, (void*)icon_path_c, 0},
+    {kAuthorizationEnvironmentPrompt, prompt_length, (void*)prompt_c, 0}
+  };
+
+  AuthorizationEnvironment environment = {arraysize(environment_items),
+                                          environment_items};
+
+  AuthorizationFlags flags = kAuthorizationFlagDefaults |
+                             kAuthorizationFlagInteractionAllowed |
+                             kAuthorizationFlagExtendRights |
+                             kAuthorizationFlagPreAuthorize;
+
+  status = AuthorizationCopyRights(authorization,
+                                   &rights,
+                                   &environment,
+                                   flags,
+                                   NULL);
+  if (status != errAuthorizationSuccess) {
+    if (status != errAuthorizationCanceled) {
+      OSSTATUS_LOG(ERROR, status) << "AuthorizationCopyRights";
+    }
+    return NULL;
+  }
+
+  return authorization.release();
+}
+
+OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
+                                        const char* tool_path,
+                                        AuthorizationFlags options,
+                                        const char** arguments,
+                                        FILE** pipe,
+                                        pid_t* pid) {
+  // pipe may be NULL, but this function needs one.  In that case, use a local
+  // pipe.
+  FILE* local_pipe;
+  FILE** pipe_pointer;
+  if (pipe) {
+    pipe_pointer = pipe;
+  } else {
+    pipe_pointer = &local_pipe;
+  }
+
+  // AuthorizationExecuteWithPrivileges wants |char* const*| for |arguments|,
+  // but it doesn't actually modify the arguments, and that type is kind of
+  // silly and callers probably aren't dealing with that.  Put the cast here
+  // to make things a little easier on callers.
+  OSStatus status = AuthorizationExecuteWithPrivileges(authorization,
+                                                       tool_path,
+                                                       options,
+                                                       (char* const*)arguments,
+                                                       pipe_pointer);
+  if (status != errAuthorizationSuccess) {
+    return status;
+  }
+
+  int line_pid = -1;
+  size_t line_length = 0;
+  char* line_c = fgetln(*pipe_pointer, &line_length);
+  if (line_c) {
+    if (line_length > 0 && line_c[line_length - 1] == '\n') {
+      // line_c + line_length is the start of the next line if there is one.
+      // Back up one character.
+      --line_length;
+    }
+    std::string line(line_c, line_length);
+    if (!base::StringToInt(line, &line_pid)) {
+      // StringToInt may have set line_pid to something, but if the conversion
+      // was imperfect, use -1.
+      LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: funny line: " << line;
+      line_pid = -1;
+    }
+  } else {
+    LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: no line";
+  }
+
+  if (!pipe) {
+    fclose(*pipe_pointer);
+  }
+
+  if (pid) {
+    *pid = line_pid;
+  }
+
+  return status;
+}
+
+OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
+                                      const char* tool_path,
+                                      AuthorizationFlags options,
+                                      const char** arguments,
+                                      FILE** pipe,
+                                      int* exit_status) {
+  pid_t pid;
+  OSStatus status = ExecuteWithPrivilegesAndGetPID(authorization,
+                                                   tool_path,
+                                                   options,
+                                                   arguments,
+                                                   pipe,
+                                                   &pid);
+  if (status != errAuthorizationSuccess) {
+    return status;
+  }
+
+  // exit_status may be NULL, but this function needs it.  In that case, use a
+  // local version.
+  int local_exit_status;
+  int* exit_status_pointer;
+  if (exit_status) {
+    exit_status_pointer = exit_status;
+  } else {
+    exit_status_pointer = &local_exit_status;
+  }
+
+  if (pid != -1) {
+    pid_t wait_result = HANDLE_EINTR(waitpid(pid, exit_status_pointer, 0));
+    if (wait_result != pid) {
+      PLOG(ERROR) << "waitpid";
+      *exit_status_pointer = -1;
+    }
+  } else {
+    *exit_status_pointer = -1;
+  }
+
+  return status;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/bind_objc_block.h b/base/mac/bind_objc_block.h
new file mode 100644
index 0000000..2d48c7d
--- /dev/null
+++ b/base/mac/bind_objc_block.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_BIND_OBJC_BLOCK_H_
+#define BASE_MAC_BIND_OBJC_BLOCK_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+
+namespace base {
+
+// Construct a closure from an objective-C block.
+BASE_EXPORT base::Closure BindBlock(void(^block)());
+
+}  // namespace base
+
+#endif  // BASE_MAC_BIND_OBJC_BLOCK_H_
diff --git a/base/mac/bind_objc_block.mm b/base/mac/bind_objc_block.mm
new file mode 100644
index 0000000..81472d0
--- /dev/null
+++ b/base/mac/bind_objc_block.mm
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/bind_objc_block.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_nsobject.h"
+
+namespace {
+
+// Run the block contained in the parameter.
+void RunBlock(scoped_nsobject<id> block) {
+  void(^extracted_block)() = block.get();
+  extracted_block();
+}
+
+}  // namespace
+
+namespace base {
+
+base::Closure BindBlock(void(^block)()) {
+  return base::Bind(&RunBlock, scoped_nsobject<id>([block copy]));
+}
+
+}  // namespace base
diff --git a/base/mac/bind_objc_block_unittest.mm b/base/mac/bind_objc_block_unittest.mm
new file mode 100644
index 0000000..17fbe6e
--- /dev/null
+++ b/base/mac/bind_objc_block_unittest.mm
@@ -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.
+
+#import "base/mac/bind_objc_block.h"
+
+#include "base/callback.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(BindObjcBlockTest, TestScopedClosureRunnerExitScope) {
+  int run_count = 0;
+  int* ptr = &run_count;
+  {
+    base::ScopedClosureRunner runner(base::BindBlock(^{
+        (*ptr)++;
+    }));
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(BindObjcBlockTest, TestScopedClosureRunnerRelease) {
+  int run_count = 0;
+  int* ptr = &run_count;
+  base::Closure c;
+  {
+    base::ScopedClosureRunner runner(base::BindBlock(^{
+        (*ptr)++;
+    }));
+    c = runner.Release();
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(0, run_count);
+  c.Run();
+  EXPECT_EQ(1, run_count);
+}
+
+}  // namespace
diff --git a/base/mac/bundle_locations.h b/base/mac/bundle_locations.h
new file mode 100644
index 0000000..dd84b59
--- /dev/null
+++ b/base/mac/bundle_locations.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_MAC_BUNDLE_LOCATIONS_H_
+#define BASE_MAC_BUNDLE_LOCATIONS_H_
+
+#include "base/base_export.h"
+#include "base/file_path.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
+#else  // __OBJC__
+class NSBundle;
+class NSString;
+#endif  // __OBJC__
+
+class FilePath;
+
+namespace base {
+namespace mac {
+
+// This file provides several functions to explicitly request the various
+// component bundles of Chrome.  Please use these methods rather than calling
+// +[NSBundle mainBundle] or CFBundleGetMainBundle().
+//
+// Terminology
+//  - "Outer Bundle" - This is the main bundle for Chrome; it's what
+//  +[NSBundle mainBundle] returns when Chrome is launched normally.
+//
+//  - "Main Bundle" - This is the bundle from which Chrome was launched.
+//  This will be the same as the outer bundle except when Chrome is launched
+//  via an app shortcut, in which case this will return the app shortcut's
+//  bundle rather than the main Chrome bundle.
+//
+//  - "Framework Bundle" - This is the bundle corresponding to the Chrome
+//  framework.
+//
+// Guidelines for use:
+//  - To access a resource, the Framework bundle should be used.
+//  - If the choice is between the Outer or Main bundles then please choose
+//  carefully.  Most often the Outer bundle will be the right choice, but for
+//  cases such as adding an app to the "launch on startup" list, the Main
+//  bundle is probably the one to use.
+
+// Methods for retrieving the various bundles.
+BASE_EXPORT NSBundle* MainBundle();
+BASE_EXPORT FilePath MainBundlePath();
+BASE_EXPORT NSBundle* OuterBundle();
+BASE_EXPORT FilePath OuterBundlePath();
+BASE_EXPORT NSBundle* FrameworkBundle();
+BASE_EXPORT FilePath FrameworkBundlePath();
+
+// Set the bundle that the preceding functions will return, overriding the
+// default values. Restore the default by passing in |nil|.
+BASE_EXPORT void SetOverrideOuterBundle(NSBundle* bundle);
+BASE_EXPORT void SetOverrideFrameworkBundle(NSBundle* bundle);
+
+// Same as above but accepting a FilePath argument.
+BASE_EXPORT void SetOverrideOuterBundlePath(const FilePath& file_path);
+BASE_EXPORT void SetOverrideFrameworkBundlePath(const FilePath& file_path);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_BUNDLE_LOCATIONS_H_
diff --git a/base/mac/bundle_locations.mm b/base/mac/bundle_locations.mm
new file mode 100644
index 0000000..363b7ea
--- /dev/null
+++ b/base/mac/bundle_locations.mm
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/bundle_locations.h"
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/sys_string_conversions.h"
+
+namespace base {
+namespace mac {
+
+// NSBundle isn't threadsafe, all functions in this file must be called on the
+// main thread.
+static NSBundle* g_override_framework_bundle = nil;
+static NSBundle* g_override_outer_bundle = nil;
+
+NSBundle* MainBundle() {
+  return [NSBundle mainBundle];
+}
+
+FilePath MainBundlePath() {
+  NSBundle* bundle = MainBundle();
+  return NSStringToFilePath([bundle bundlePath]);
+}
+
+NSBundle* OuterBundle() {
+  if (g_override_outer_bundle)
+    return g_override_outer_bundle;
+  return [NSBundle mainBundle];
+}
+
+FilePath OuterBundlePath() {
+  NSBundle* bundle = OuterBundle();
+  return NSStringToFilePath([bundle bundlePath]);
+}
+
+NSBundle* FrameworkBundle() {
+  if (g_override_framework_bundle)
+    return g_override_framework_bundle;
+  return [NSBundle mainBundle];
+}
+
+FilePath FrameworkBundlePath() {
+  NSBundle* bundle = FrameworkBundle();
+  return NSStringToFilePath([bundle bundlePath]);
+}
+
+static void AssignOverrideBundle(NSBundle* new_bundle,
+                                 NSBundle** override_bundle) {
+  if (new_bundle != *override_bundle) {
+    [*override_bundle release];
+    *override_bundle = [new_bundle retain];
+  }
+}
+
+static void AssignOverridePath(const FilePath& file_path,
+                               NSBundle** override_bundle) {
+  NSString* path = base::SysUTF8ToNSString(file_path.value());
+  NSBundle* new_bundle = [NSBundle bundleWithPath:path];
+  DCHECK(new_bundle) << "Failed to load the bundle at " << file_path.value();
+  AssignOverrideBundle(new_bundle, override_bundle);
+}
+
+void SetOverrideOuterBundle(NSBundle* bundle) {
+  AssignOverrideBundle(bundle, &g_override_outer_bundle);
+}
+
+void SetOverrideFrameworkBundle(NSBundle* bundle) {
+  AssignOverrideBundle(bundle, &g_override_framework_bundle);
+}
+
+void SetOverrideOuterBundlePath(const FilePath& file_path) {
+  AssignOverridePath(file_path, &g_override_outer_bundle);
+}
+
+void SetOverrideFrameworkBundlePath(const FilePath& file_path) {
+  AssignOverridePath(file_path, &g_override_framework_bundle);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/cocoa_protocols.h b/base/mac/cocoa_protocols.h
new file mode 100644
index 0000000..314e7fa
--- /dev/null
+++ b/base/mac/cocoa_protocols.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_COCOA_PROTOCOLS_MAC_H_
+#define BASE_COCOA_PROTOCOLS_MAC_H_
+
+#import <Cocoa/Cocoa.h>
+
+// GTM also maintinas a list of empty protocols, but only the ones the library
+// requires. Augment that below.
+#import "third_party/GTM/GTMDefines.h"
+
+// New Mac OS X SDKs introduce new protocols used for delegates.  These
+// protocol defintions aren't not present in earlier releases of the Mac OS X
+// SDK.  In order to support building against the new SDK, which requires
+// 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)
+
+#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
+
+DEFINE_EMPTY_PROTOCOL(NSUserNotificationCenterDelegate)
+
+#endif  // MAC_OS_X_VERSION_10_8
+
+#undef DEFINE_EMPTY_PROTOCOL
+
+#endif  // BASE_COCOA_PROTOCOLS_MAC_H_
diff --git a/base/mac/crash_logging.h b/base/mac/crash_logging.h
new file mode 100644
index 0000000..7e83eae
--- /dev/null
+++ b/base/mac/crash_logging.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_CRASH_LOGGING_H_
+#define BASE_MAC_CRASH_LOGGING_H_
+
+#include "base/base_export.h"
+
+#if __OBJC__
+#import "base/memory/scoped_nsobject.h"
+
+@class NSString;
+#else
+class NSString;
+#endif
+
+namespace base {
+namespace mac {
+
+typedef void (*SetCrashKeyValueFuncPtr)(NSString*, NSString*);
+typedef void (*ClearCrashKeyValueFuncPtr)(NSString*);
+
+// Set the low level functions used to supply crash keys to Breakpad.
+BASE_EXPORT void SetCrashKeyFunctions(SetCrashKeyValueFuncPtr set_key_func,
+                          ClearCrashKeyValueFuncPtr clear_key_func);
+
+// Set and clear meta information for Minidump.
+// IMPORTANT: On OS X, the key/value pairs are sent to the crash server
+// out of bounds and not recorded on disk in the minidump, this means
+// that if you look at the minidump file locally you won't see them!
+BASE_EXPORT void SetCrashKeyValue(NSString* key, NSString* val);
+BASE_EXPORT void ClearCrashKey(NSString* key);
+
+// Format |count| items from |addresses| using %p, and set the
+// resulting string as value for crash key |key|.  A maximum of 23
+// items will be encoded, since breakpad limits values to 255 bytes.
+BASE_EXPORT void SetCrashKeyFromAddresses(NSString* key,
+                                          const void* const* addresses,
+                                          size_t count);
+
+#if __OBJC__
+
+class BASE_EXPORT ScopedCrashKey {
+ public:
+  ScopedCrashKey(NSString* key, NSString* value);
+  ~ScopedCrashKey();
+ private:
+  scoped_nsobject<NSString> crash_key_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedCrashKey);
+};
+
+#endif  // __OBJC__
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_CRASH_LOGGING_H_
diff --git a/base/mac/crash_logging.mm b/base/mac/crash_logging.mm
new file mode 100644
index 0000000..e18a3fb
--- /dev/null
+++ b/base/mac/crash_logging.mm
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/crash_logging.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+static SetCrashKeyValueFuncPtr g_set_key_func;
+static ClearCrashKeyValueFuncPtr g_clear_key_func;
+
+void SetCrashKeyFunctions(SetCrashKeyValueFuncPtr set_key_func,
+                          ClearCrashKeyValueFuncPtr clear_key_func) {
+  g_set_key_func = set_key_func;
+  g_clear_key_func = clear_key_func;
+}
+
+void SetCrashKeyValue(NSString* key, NSString* val) {
+  if (g_set_key_func)
+    g_set_key_func(key, val);
+}
+
+void ClearCrashKey(NSString* key) {
+  if (g_clear_key_func)
+    g_clear_key_func(key);
+}
+
+void SetCrashKeyFromAddresses(NSString* key,
+                              const void* const* addresses,
+                              size_t count) {
+  NSString* value = @"<null>";
+  if (addresses && count) {
+    const size_t kBreakpadValueMax = 255;
+
+    NSMutableArray* hexBacktrace = [NSMutableArray arrayWithCapacity:count];
+    size_t length = 0;
+    for (size_t i = 0; i < count; ++i) {
+      NSString* s = [NSString stringWithFormat:@"%p", addresses[i]];
+      length += 1 + [s length];
+      if (length > kBreakpadValueMax)
+        break;
+      [hexBacktrace addObject:s];
+    }
+    value = [hexBacktrace componentsJoinedByString:@" "];
+
+    // Warn someone if this exceeds the breakpad limits.
+    DCHECK_LE(strlen([value UTF8String]), kBreakpadValueMax);
+  }
+  base::mac::SetCrashKeyValue(key, value);
+}
+
+ScopedCrashKey::ScopedCrashKey(NSString* key, NSString* value)
+    : crash_key_([key retain]) {
+  if (g_set_key_func)
+    g_set_key_func(crash_key_, value);
+}
+
+ScopedCrashKey::~ScopedCrashKey() {
+  if (g_clear_key_func)
+    g_clear_key_func(crash_key_);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h
new file mode 100644
index 0000000..e6ad784
--- /dev/null
+++ b/base/mac/foundation_util.h
@@ -0,0 +1,358 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_FOUNDATION_UTIL_H_
+#define BASE_MAC_FOUNDATION_UTIL_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
+#else  // __OBJC__
+#include <CoreFoundation/CoreFoundation.h>
+class NSBundle;
+class NSString;
+#endif  // __OBJC__
+
+#if defined(OS_IOS)
+#include <CoreText/CoreText.h>
+#else
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+class FilePath;
+
+// Adapted from NSPathUtilities.h and NSObjCRuntime.h.
+#if __LP64__ || NS_BUILD_32_LIKE_64
+typedef unsigned long NSSearchPathDirectory;
+typedef unsigned long NSSearchPathDomainMask;
+#else
+typedef unsigned int NSSearchPathDirectory;
+typedef unsigned int NSSearchPathDomainMask;
+#endif
+
+typedef struct OpaqueSecTrustRef* SecACLRef;
+typedef struct OpaqueSecTrustedApplicationRef* SecTrustedApplicationRef;
+
+namespace base {
+namespace mac {
+
+// Returns true if the application is running from a bundle
+BASE_EXPORT bool AmIBundled();
+BASE_EXPORT void SetOverrideAmIBundled(bool value);
+
+// 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);
+
+#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(CTRun);
+
+CF_CAST_DECL(SecACL);
+CF_CAST_DECL(SecTrustedApplication);
+
+#undef CF_CAST_DECL
+
+#if defined(__OBJC__)
+
+// ObjCCast<>() and ObjCCastStrict<>() cast a basic id to a more
+// specific (NSObject-derived) type. The compatibility of the passed
+// object is found by checking if it's a kind of the requested type
+// identifier. If the supplied object is not compatible with the
+// requested return type, ObjCCast<>() returns nil and
+// ObjCCastStrict<>() will DCHECK. Providing a nil pointer to either
+// variant results in nil being returned without triggering any DCHECK.
+//
+// The strict variant is useful when retrieving a value from a
+// collection which only has values of a specific type, e.g. an
+// NSArray of NSStrings. The non-strict variant is useful when
+// retrieving values from data that you can't fully control. For
+// example, a plist read from disk may be beyond your exclusive
+// control, so you'd only want to check that the values you retrieve
+// from it are of the expected types, but not crash if they're not.
+//
+// Example usage:
+// NSString* version = base::mac::ObjCCast<NSString>(
+//     [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
+//
+// NSString* str = base::mac::ObjCCastStrict<NSString>(
+//     [ns_arr_of_ns_strs objectAtIndex:0]);
+template<typename T>
+T* ObjCCast(id objc_val) {
+  if ([objc_val isKindOfClass:[T class]]) {
+    return reinterpret_cast<T*>(objc_val);
+  }
+  return nil;
+}
+
+template<typename T>
+T* ObjCCastStrict(id objc_val) {
+  T* rv = ObjCCast<T>(objc_val);
+  DCHECK(objc_val == nil || rv);
+  return rv;
+}
+
+#endif  // defined(__OBJC__)
+
+// Helper function for GetValueFromDictionary to create the error message
+// that appears when a type mismatch is encountered.
+BASE_EXPORT std::string GetValueFromDictionaryErrorMessage(
+    CFStringRef key, const std::string& expected_type, CFTypeRef value);
+
+// Utility function to pull out a value from a dictionary, check its type, and
+// return it. Returns NULL if the key is not present or of the wrong type.
+template<typename T>
+T GetValueFromDictionary(CFDictionaryRef dict, CFStringRef key) {
+  CFTypeRef value = CFDictionaryGetValue(dict, key);
+  T value_specific = CFCast<T>(value);
+
+  if (value && !value_specific) {
+    std::string expected_type = TypeNameForCFType(value_specific);
+    DLOG(WARNING) << GetValueFromDictionaryErrorMessage(key,
+                                                        expected_type,
+                                                        value);
+  }
+
+  return value_specific;
+}
+
+// Converts |path| to an autoreleased NSString. Returns nil if |path| is empty.
+BASE_EXPORT NSString* FilePathToNSString(const FilePath& path);
+
+// Converts |str| to a FilePath. Returns an empty path if |str| is nil.
+BASE_EXPORT FilePath NSStringToFilePath(NSString* str);
+
+}  // namespace mac
+}  // namespace base
+
+// Stream operations for CFTypes. They can be used with NSTypes as well
+// by using the NSToCFCast methods above.
+// e.g. LOG(INFO) << base::mac::NSToCFCast(@"foo");
+// Operator << can not be overloaded for ObjectiveC types as the compiler
+// can not distinguish between overloads for id with overloads for void*.
+BASE_EXPORT extern std::ostream& operator<<(std::ostream& o,
+                                            const CFErrorRef err);
+BASE_EXPORT extern std::ostream& operator<<(std::ostream& o,
+                                            const CFStringRef str);
+
+#endif  // BASE_MAC_FOUNDATION_UTIL_H_
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm
new file mode 100644
index 0000000..3fd9a57
--- /dev/null
+++ b/base/mac/foundation_util.mm
@@ -0,0 +1,401 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/foundation_util.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/mac_logging.h"
+#include "base/sys_string_conversions.h"
+
+#if !defined(OS_IOS)
+extern "C" {
+CFTypeID SecACLGetTypeID();
+CFTypeID SecTrustedApplicationGetTypeID();
+}  // extern "C"
+#endif
+
+namespace base {
+namespace mac {
+
+static bool g_override_am_i_bundled = false;
+static bool g_override_am_i_bundled_value = false;
+
+// Adapted from http://developer.apple.com/carbon/tipsandtricks.html#AmIBundled
+static 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;
+
+  ProcessSerialNumber psn = {0, kCurrentProcess};
+
+  FSRef fsref;
+  OSStatus pbErr;
+  if ((pbErr = GetProcessBundleLocation(&psn, &fsref)) != noErr) {
+    OSSTATUS_DLOG(ERROR, pbErr) << "GetProcessBundleLocation failed";
+    return false;
+  }
+
+  FSCatalogInfo info;
+  OSErr fsErr;
+  if ((fsErr = FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info,
+                                NULL, NULL, NULL)) != noErr) {
+    OSSTATUS_DLOG(ERROR, fsErr) << "FSGetCatalogInfo failed";
+    return false;
+  }
+
+  return info.nodeFlags & kFSNodeIsDirectoryMask;
+#endif
+}
+
+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 .
+  static bool result = UncachedAmIBundled();
+  DCHECK_EQ(result, UncachedAmIBundled())
+      << "The return value of AmIBundled() changed. This will confuse tests. "
+      << "Call SetAmIBundled() override manually if your test binary "
+      << "delay-loads the framework.";
+  return result;
+}
+
+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;
+}
+
+bool IsBackgroundOnlyProcess() {
+  // This function really does want to examine NSBundle's idea of the main
+  // bundle dictionary.  It needs to look at the actual running .app's
+  // Info.plist to access its LSUIElement property.
+  NSDictionary* info_dictionary = [base::mac::MainBundle() infoDictionary];
+  return [[info_dictionary objectForKey:@"LSUIElement"] boolValue] != NO;
+}
+
+FilePath PathForFrameworkBundleResource(CFStringRef resourceName) {
+  NSBundle* bundle = base::mac::FrameworkBundle();
+  NSString* resourcePath = [bundle pathForResource:(NSString*)resourceName
+                                            ofType:nil];
+  return NSStringToFilePath(resourcePath);
+}
+
+OSType CreatorCodeForCFBundleRef(CFBundleRef bundle) {
+  OSType creator = kUnknownType;
+  CFBundleGetPackageInfo(bundle, NULL, &creator);
+  return creator;
+}
+
+OSType CreatorCodeForApplication() {
+  CFBundleRef bundle = CFBundleGetMainBundle();
+  if (!bundle)
+    return kUnknownType;
+
+  return CreatorCodeForCFBundleRef(bundle);
+}
+
+bool GetSearchPathDirectory(NSSearchPathDirectory directory,
+                            NSSearchPathDomainMask domain_mask,
+                            FilePath* result) {
+  DCHECK(result);
+  NSArray* dirs =
+      NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES);
+  if ([dirs count] < 1) {
+    return false;
+  }
+  *result = NSStringToFilePath([dirs objectAtIndex:0]);
+  return true;
+}
+
+bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result) {
+  return GetSearchPathDirectory(directory, NSLocalDomainMask, result);
+}
+
+bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) {
+  return GetSearchPathDirectory(directory, NSUserDomainMask, result);
+}
+
+FilePath GetUserLibraryPath() {
+  FilePath user_library_path;
+  if (!GetUserDirectory(NSLibraryDirectory, &user_library_path)) {
+    DLOG(WARNING) << "Could not get user library path";
+  }
+  return user_library_path;
+}
+
+// Takes a path to an (executable) binary and tries to provide the path to an
+// application bundle containing it. It takes the outermost bundle that it can
+// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
+//   |exec_name| - path to the binary
+//   returns - path to the application bundle, or empty on error
+FilePath GetAppBundlePath(const FilePath& exec_name) {
+  const char kExt[] = ".app";
+  const size_t kExtLength = arraysize(kExt) - 1;
+
+  // Split the path into components.
+  std::vector<std::string> components;
+  exec_name.GetComponents(&components);
+
+  // It's an error if we don't get any components.
+  if (!components.size())
+    return FilePath();
+
+  // Don't prepend '/' to the first component.
+  std::vector<std::string>::const_iterator it = components.begin();
+  std::string bundle_name = *it;
+  DCHECK_GT(it->length(), 0U);
+  // If the first component ends in ".app", we're already done.
+  if (it->length() > kExtLength &&
+      !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
+    return FilePath(bundle_name);
+
+  // The first component may be "/" or "//", etc. Only append '/' if it doesn't
+  // already end in '/'.
+  if (bundle_name[bundle_name.length() - 1] != '/')
+    bundle_name += '/';
+
+  // Go through the remaining components.
+  for (++it; it != components.end(); ++it) {
+    DCHECK_GT(it->length(), 0U);
+
+    bundle_name += *it;
+
+    // If the current component ends in ".app", we're done.
+    if (it->length() > kExtLength &&
+        !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
+      return FilePath(bundle_name);
+
+    // Separate this component from the next one.
+    bundle_name += '/';
+  }
+
+  return FilePath();
+}
+
+#define TYPE_NAME_FOR_CF_TYPE_DEFN(TypeCF) \
+std::string TypeNameForCFType(TypeCF##Ref) { \
+  return #TypeCF; \
+}
+
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFArray);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFBag);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFBoolean);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFData);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFDate);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFDictionary);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFNull);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFNumber);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFSet);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFString);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFURL);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFUUID);
+
+TYPE_NAME_FOR_CF_TYPE_DEFN(CGColor);
+
+TYPE_NAME_FOR_CF_TYPE_DEFN(CTFont);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CTRun);
+
+#undef TYPE_NAME_FOR_CF_TYPE_DEFN
+
+void NSObjectRetain(void* obj) {
+  id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
+  [nsobj retain];
+}
+
+void NSObjectRelease(void* obj) {
+  id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
+  [nsobj release];
+}
+
+void* CFTypeRefToNSObjectAutorelease(CFTypeRef cf_object) {
+  // When GC is on, NSMakeCollectable marks cf_object for GC and autorelease
+  // is a no-op.
+  //
+  // In the traditional GC-less environment, NSMakeCollectable is a no-op,
+  // and cf_object is autoreleased, balancing out the caller's ownership claim.
+  //
+  // NSMakeCollectable returns nil when used on a NULL object.
+  return [NSMakeCollectable(cf_object) autorelease];
+}
+
+static const char* base_bundle_id;
+
+const char* BaseBundleID() {
+  if (base_bundle_id) {
+    return base_bundle_id;
+  }
+
+#if defined(GOOGLE_CHROME_BUILD)
+  return "com.google.Chrome";
+#else
+  return "org.chromium.Chromium";
+#endif
+}
+
+void SetBaseBundleID(const char* new_base_bundle_id) {
+  if (new_base_bundle_id != base_bundle_id) {
+    free((void*)base_bundle_id);
+    base_bundle_id = new_base_bundle_id ? strdup(new_base_bundle_id) : NULL;
+  }
+}
+
+// Definitions for the corresponding CF_TO_NS_CAST_DECL macros in
+// foundation_util.h.
+#define CF_TO_NS_CAST_DEFN(TypeCF, TypeNS) \
+\
+TypeNS* CFToNSCast(TypeCF##Ref cf_val) { \
+  DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
+  TypeNS* ns_val = \
+      const_cast<TypeNS*>(reinterpret_cast<const TypeNS*>(cf_val)); \
+  return ns_val; \
+} \
+\
+TypeCF##Ref NSToCFCast(TypeNS* ns_val) { \
+  TypeCF##Ref cf_val = reinterpret_cast<TypeCF##Ref>(ns_val); \
+  DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
+  return cf_val; \
+}
+
+#define CF_TO_NS_MUTABLE_CAST_DEFN(name) \
+CF_TO_NS_CAST_DEFN(CF##name, NS##name) \
+\
+NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val) { \
+  DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
+  NSMutable##name* ns_val = reinterpret_cast<NSMutable##name*>(cf_val); \
+  return ns_val; \
+} \
+\
+CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val) { \
+  CFMutable##name##Ref cf_val = \
+      reinterpret_cast<CFMutable##name##Ref>(ns_val); \
+  DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
+  return cf_val; \
+}
+
+CF_TO_NS_MUTABLE_CAST_DEFN(Array);
+CF_TO_NS_MUTABLE_CAST_DEFN(AttributedString);
+CF_TO_NS_CAST_DEFN(CFCalendar, NSCalendar);
+CF_TO_NS_MUTABLE_CAST_DEFN(CharacterSet);
+CF_TO_NS_MUTABLE_CAST_DEFN(Data);
+CF_TO_NS_CAST_DEFN(CFDate, NSDate);
+CF_TO_NS_MUTABLE_CAST_DEFN(Dictionary);
+CF_TO_NS_CAST_DEFN(CFError, NSError);
+CF_TO_NS_CAST_DEFN(CFLocale, NSLocale);
+CF_TO_NS_CAST_DEFN(CFNumber, NSNumber);
+CF_TO_NS_CAST_DEFN(CFRunLoopTimer, NSTimer);
+CF_TO_NS_CAST_DEFN(CFTimeZone, NSTimeZone);
+CF_TO_NS_MUTABLE_CAST_DEFN(Set);
+CF_TO_NS_CAST_DEFN(CFReadStream, NSInputStream);
+CF_TO_NS_CAST_DEFN(CFWriteStream, NSOutputStream);
+CF_TO_NS_MUTABLE_CAST_DEFN(String);
+CF_TO_NS_CAST_DEFN(CFURL, NSURL);
+
+#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(CTFont);
+CF_CAST_DEFN(CTRun);
+
+#if !defined(OS_IOS)
+CF_CAST_DEFN(SecACL);
+CF_CAST_DEFN(SecTrustedApplication);
+#endif
+
+#undef CF_CAST_DEFN
+
+std::string GetValueFromDictionaryErrorMessage(
+    CFStringRef key, const std::string& expected_type, CFTypeRef value) {
+  ScopedCFTypeRef<CFStringRef> actual_type_ref(
+      CFCopyTypeIDDescription(CFGetTypeID(value)));
+  return "Expected value for key " +
+      base::SysCFStringRefToUTF8(key) +
+      " to be " +
+      expected_type +
+      " but it was " +
+      base::SysCFStringRefToUTF8(actual_type_ref) +
+      " instead";
+}
+
+NSString* FilePathToNSString(const FilePath& path) {
+  if (path.empty())
+    return nil;
+  return [NSString stringWithUTF8String:path.value().c_str()];
+}
+
+FilePath NSStringToFilePath(NSString* str) {
+  if (![str length])
+    return FilePath();
+  return FilePath([str fileSystemRepresentation]);
+}
+
+}  // namespace mac
+}  // namespace base
+
+std::ostream& operator<<(std::ostream& o, const CFStringRef string) {
+  return o << base::SysCFStringRefToUTF8(string);
+}
+
+std::ostream& operator<<(std::ostream& o, const CFErrorRef err) {
+  base::mac::ScopedCFTypeRef<CFStringRef> desc(CFErrorCopyDescription(err));
+  base::mac::ScopedCFTypeRef<CFDictionaryRef> user_info(
+      CFErrorCopyUserInfo(err));
+  CFStringRef errorDesc = NULL;
+  if (user_info.get()) {
+    errorDesc = reinterpret_cast<CFStringRef>(
+        CFDictionaryGetValue(user_info.get(), kCFErrorDescriptionKey));
+  }
+  o << "Code: " << CFErrorGetCode(err)
+    << " Domain: " << CFErrorGetDomain(err)
+    << " Desc: " << desc.get();
+  if(errorDesc) {
+    o << "(" << errorDesc << ")";
+  }
+  return o;
+}
diff --git a/base/mac/foundation_util_unittest.mm b/base/mac/foundation_util_unittest.mm
new file mode 100644
index 0000000..4653006
--- /dev/null
+++ b/base/mac/foundation_util_unittest.mm
@@ -0,0 +1,334 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/foundation_util.h"
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+
+TEST(FoundationUtilTest, CFCast) {
+  // Build out the CF types to be tested as empty containers.
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_array(
+      CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks));
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_array_mutable(
+      CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_bag(
+      CFBagCreate(NULL, NULL, 0, &kCFTypeBagCallBacks));
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_bag_mutable(
+      CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks));
+  CFTypeRef test_bool = kCFBooleanTrue;
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_data(
+      CFDataCreate(NULL, NULL, 0));
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_data_mutable(
+      CFDataCreateMutable(NULL, 0));
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_date(
+      CFDateCreate(NULL, 0));
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_dict(
+      CFDictionaryCreate(NULL, NULL, NULL, 0,
+                         &kCFCopyStringDictionaryKeyCallBacks,
+                         &kCFTypeDictionaryValueCallBacks));
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_dict_mutable(
+      CFDictionaryCreateMutable(NULL, 0,
+                                &kCFCopyStringDictionaryKeyCallBacks,
+                                &kCFTypeDictionaryValueCallBacks));
+  int int_val = 256;
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_number(
+      CFNumberCreate(NULL, kCFNumberIntType, &int_val));
+  CFTypeRef test_null = kCFNull;
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_set(
+      CFSetCreate(NULL, NULL, 0, &kCFTypeSetCallBacks));
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_set_mutable(
+      CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks));
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_str(
+      CFStringCreateWithBytes(NULL, NULL, 0, kCFStringEncodingASCII,
+                              false));
+  CFTypeRef test_str_const = CFSTR("hello");
+  base::mac::ScopedCFTypeRef<CFTypeRef> test_str_mutable(
+      CFStringCreateMutable(NULL, 0));
+
+  // Make sure the allocations of CF types are good.
+  EXPECT_TRUE(test_array);
+  EXPECT_TRUE(test_array_mutable);
+  EXPECT_TRUE(test_bag);
+  EXPECT_TRUE(test_bag_mutable);
+  EXPECT_TRUE(test_bool);
+  EXPECT_TRUE(test_data);
+  EXPECT_TRUE(test_data_mutable);
+  EXPECT_TRUE(test_date);
+  EXPECT_TRUE(test_dict);
+  EXPECT_TRUE(test_dict_mutable);
+  EXPECT_TRUE(test_number);
+  EXPECT_TRUE(test_null);
+  EXPECT_TRUE(test_set);
+  EXPECT_TRUE(test_set_mutable);
+  EXPECT_TRUE(test_str);
+  EXPECT_TRUE(test_str_const);
+  EXPECT_TRUE(test_str_mutable);
+
+  // Casting the CFTypeRef objects correctly provides the same pointer.
+  EXPECT_EQ(test_array, base::mac::CFCast<CFArrayRef>(test_array));
+  EXPECT_EQ(test_array_mutable,
+            base::mac::CFCast<CFArrayRef>(test_array_mutable));
+  EXPECT_EQ(test_bag, base::mac::CFCast<CFBagRef>(test_bag));
+  EXPECT_EQ(test_bag_mutable,
+            base::mac::CFCast<CFBagRef>(test_bag_mutable));
+  EXPECT_EQ(test_bool, base::mac::CFCast<CFBooleanRef>(test_bool));
+  EXPECT_EQ(test_data, base::mac::CFCast<CFDataRef>(test_data));
+  EXPECT_EQ(test_data_mutable,
+            base::mac::CFCast<CFDataRef>(test_data_mutable));
+  EXPECT_EQ(test_date, base::mac::CFCast<CFDateRef>(test_date));
+  EXPECT_EQ(test_dict, base::mac::CFCast<CFDictionaryRef>(test_dict));
+  EXPECT_EQ(test_dict_mutable,
+            base::mac::CFCast<CFDictionaryRef>(test_dict_mutable));
+  EXPECT_EQ(test_number, base::mac::CFCast<CFNumberRef>(test_number));
+  EXPECT_EQ(test_null, base::mac::CFCast<CFNullRef>(test_null));
+  EXPECT_EQ(test_set, base::mac::CFCast<CFSetRef>(test_set));
+  EXPECT_EQ(test_set_mutable, base::mac::CFCast<CFSetRef>(test_set_mutable));
+  EXPECT_EQ(test_str, base::mac::CFCast<CFStringRef>(test_str));
+  EXPECT_EQ(test_str_const, base::mac::CFCast<CFStringRef>(test_str_const));
+  EXPECT_EQ(test_str_mutable,
+            base::mac::CFCast<CFStringRef>(test_str_mutable));
+
+  // When given an incorrect CF cast, provide NULL.
+  EXPECT_FALSE(base::mac::CFCast<CFStringRef>(test_array));
+  EXPECT_FALSE(base::mac::CFCast<CFStringRef>(test_array_mutable));
+  EXPECT_FALSE(base::mac::CFCast<CFStringRef>(test_bag));
+  EXPECT_FALSE(base::mac::CFCast<CFSetRef>(test_bag_mutable));
+  EXPECT_FALSE(base::mac::CFCast<CFSetRef>(test_bool));
+  EXPECT_FALSE(base::mac::CFCast<CFNullRef>(test_data));
+  EXPECT_FALSE(base::mac::CFCast<CFDictionaryRef>(test_data_mutable));
+  EXPECT_FALSE(base::mac::CFCast<CFDictionaryRef>(test_date));
+  EXPECT_FALSE(base::mac::CFCast<CFNumberRef>(test_dict));
+  EXPECT_FALSE(base::mac::CFCast<CFDateRef>(test_dict_mutable));
+  EXPECT_FALSE(base::mac::CFCast<CFDataRef>(test_number));
+  EXPECT_FALSE(base::mac::CFCast<CFDataRef>(test_null));
+  EXPECT_FALSE(base::mac::CFCast<CFBooleanRef>(test_set));
+  EXPECT_FALSE(base::mac::CFCast<CFBagRef>(test_set_mutable));
+  EXPECT_FALSE(base::mac::CFCast<CFBagRef>(test_str));
+  EXPECT_FALSE(base::mac::CFCast<CFArrayRef>(test_str_const));
+  EXPECT_FALSE(base::mac::CFCast<CFArrayRef>(test_str_mutable));
+
+  // Giving a NULL provides a NULL.
+  EXPECT_FALSE(base::mac::CFCast<CFArrayRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCast<CFBagRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCast<CFBooleanRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCast<CFDataRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCast<CFDateRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCast<CFDictionaryRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCast<CFNullRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCast<CFNumberRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCast<CFSetRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCast<CFStringRef>(NULL));
+
+  // CFCastStrict: correct cast results in correct pointer being returned.
+  EXPECT_EQ(test_array, base::mac::CFCastStrict<CFArrayRef>(test_array));
+  EXPECT_EQ(test_array_mutable,
+            base::mac::CFCastStrict<CFArrayRef>(test_array_mutable));
+  EXPECT_EQ(test_bag, base::mac::CFCastStrict<CFBagRef>(test_bag));
+  EXPECT_EQ(test_bag_mutable,
+            base::mac::CFCastStrict<CFBagRef>(test_bag_mutable));
+  EXPECT_EQ(test_bool, base::mac::CFCastStrict<CFBooleanRef>(test_bool));
+  EXPECT_EQ(test_data, base::mac::CFCastStrict<CFDataRef>(test_data));
+  EXPECT_EQ(test_data_mutable,
+            base::mac::CFCastStrict<CFDataRef>(test_data_mutable));
+  EXPECT_EQ(test_date, base::mac::CFCastStrict<CFDateRef>(test_date));
+  EXPECT_EQ(test_dict, base::mac::CFCastStrict<CFDictionaryRef>(test_dict));
+  EXPECT_EQ(test_dict_mutable,
+            base::mac::CFCastStrict<CFDictionaryRef>(test_dict_mutable));
+  EXPECT_EQ(test_number, base::mac::CFCastStrict<CFNumberRef>(test_number));
+  EXPECT_EQ(test_null, base::mac::CFCastStrict<CFNullRef>(test_null));
+  EXPECT_EQ(test_set, base::mac::CFCastStrict<CFSetRef>(test_set));
+  EXPECT_EQ(test_set_mutable,
+            base::mac::CFCastStrict<CFSetRef>(test_set_mutable));
+  EXPECT_EQ(test_str, base::mac::CFCastStrict<CFStringRef>(test_str));
+  EXPECT_EQ(test_str_const,
+            base::mac::CFCastStrict<CFStringRef>(test_str_const));
+  EXPECT_EQ(test_str_mutable,
+            base::mac::CFCastStrict<CFStringRef>(test_str_mutable));
+
+  // CFCastStrict: Giving a NULL provides a NULL.
+  EXPECT_FALSE(base::mac::CFCastStrict<CFArrayRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCastStrict<CFBagRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCastStrict<CFBooleanRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCastStrict<CFDataRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCastStrict<CFDateRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCastStrict<CFDictionaryRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCastStrict<CFNullRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCastStrict<CFNumberRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCastStrict<CFSetRef>(NULL));
+  EXPECT_FALSE(base::mac::CFCastStrict<CFStringRef>(NULL));
+}
+
+TEST(FoundationUtilTest, ObjCCast) {
+  base::mac::ScopedNSAutoreleasePool pool;
+
+  id test_array = [NSArray array];
+  id test_array_mutable = [NSMutableArray array];
+  id test_data = [NSData data];
+  id test_data_mutable = [NSMutableData dataWithCapacity:10];
+  id test_date = [NSDate date];
+  id test_dict =
+      [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:42]
+                                  forKey:@"meaning"];
+  id test_dict_mutable = [NSMutableDictionary dictionaryWithCapacity:10];
+  id test_number = [NSNumber numberWithInt:42];
+  id test_null = [NSNull null];
+  id test_set = [NSSet setWithObject:@"string object"];
+  id test_set_mutable = [NSMutableSet setWithCapacity:10];
+  id test_str = [NSString string];
+  id test_str_const = @"bonjour";
+  id test_str_mutable = [NSMutableString stringWithCapacity:10];
+
+  // Make sure the allocations of NS types are good.
+  EXPECT_TRUE(test_array);
+  EXPECT_TRUE(test_array_mutable);
+  EXPECT_TRUE(test_data);
+  EXPECT_TRUE(test_data_mutable);
+  EXPECT_TRUE(test_date);
+  EXPECT_TRUE(test_dict);
+  EXPECT_TRUE(test_dict_mutable);
+  EXPECT_TRUE(test_number);
+  EXPECT_TRUE(test_null);
+  EXPECT_TRUE(test_set);
+  EXPECT_TRUE(test_set_mutable);
+  EXPECT_TRUE(test_str);
+  EXPECT_TRUE(test_str_const);
+  EXPECT_TRUE(test_str_mutable);
+
+  // Casting the id correctly provides the same pointer.
+  EXPECT_EQ(test_array, base::mac::ObjCCast<NSArray>(test_array));
+  EXPECT_EQ(test_array_mutable,
+            base::mac::ObjCCast<NSArray>(test_array_mutable));
+  EXPECT_EQ(test_data, base::mac::ObjCCast<NSData>(test_data));
+  EXPECT_EQ(test_data_mutable,
+            base::mac::ObjCCast<NSData>(test_data_mutable));
+  EXPECT_EQ(test_date, base::mac::ObjCCast<NSDate>(test_date));
+  EXPECT_EQ(test_dict, base::mac::ObjCCast<NSDictionary>(test_dict));
+  EXPECT_EQ(test_dict_mutable,
+            base::mac::ObjCCast<NSDictionary>(test_dict_mutable));
+  EXPECT_EQ(test_number, base::mac::ObjCCast<NSNumber>(test_number));
+  EXPECT_EQ(test_null, base::mac::ObjCCast<NSNull>(test_null));
+  EXPECT_EQ(test_set, base::mac::ObjCCast<NSSet>(test_set));
+  EXPECT_EQ(test_set_mutable, base::mac::ObjCCast<NSSet>(test_set_mutable));
+  EXPECT_EQ(test_str, base::mac::ObjCCast<NSString>(test_str));
+  EXPECT_EQ(test_str_const, base::mac::ObjCCast<NSString>(test_str_const));
+  EXPECT_EQ(test_str_mutable,
+            base::mac::ObjCCast<NSString>(test_str_mutable));
+
+  // When given an incorrect ObjC cast, provide nil.
+  EXPECT_FALSE(base::mac::ObjCCast<NSString>(test_array));
+  EXPECT_FALSE(base::mac::ObjCCast<NSString>(test_array_mutable));
+  EXPECT_FALSE(base::mac::ObjCCast<NSString>(test_data));
+  EXPECT_FALSE(base::mac::ObjCCast<NSString>(test_data_mutable));
+  EXPECT_FALSE(base::mac::ObjCCast<NSSet>(test_date));
+  EXPECT_FALSE(base::mac::ObjCCast<NSSet>(test_dict));
+  EXPECT_FALSE(base::mac::ObjCCast<NSNumber>(test_dict_mutable));
+  EXPECT_FALSE(base::mac::ObjCCast<NSNull>(test_number));
+  EXPECT_FALSE(base::mac::ObjCCast<NSDictionary>(test_null));
+  EXPECT_FALSE(base::mac::ObjCCast<NSDictionary>(test_set));
+  EXPECT_FALSE(base::mac::ObjCCast<NSDate>(test_set_mutable));
+  EXPECT_FALSE(base::mac::ObjCCast<NSData>(test_str));
+  EXPECT_FALSE(base::mac::ObjCCast<NSData>(test_str_const));
+  EXPECT_FALSE(base::mac::ObjCCast<NSArray>(test_str_mutable));
+
+  // Giving a nil provides a nil.
+  EXPECT_FALSE(base::mac::ObjCCast<NSArray>(nil));
+  EXPECT_FALSE(base::mac::ObjCCast<NSData>(nil));
+  EXPECT_FALSE(base::mac::ObjCCast<NSDate>(nil));
+  EXPECT_FALSE(base::mac::ObjCCast<NSDictionary>(nil));
+  EXPECT_FALSE(base::mac::ObjCCast<NSNull>(nil));
+  EXPECT_FALSE(base::mac::ObjCCast<NSNumber>(nil));
+  EXPECT_FALSE(base::mac::ObjCCast<NSSet>(nil));
+  EXPECT_FALSE(base::mac::ObjCCast<NSString>(nil));
+
+  // ObjCCastStrict: correct cast results in correct pointer being returned.
+  EXPECT_EQ(test_array, base::mac::ObjCCastStrict<NSArray>(test_array));
+  EXPECT_EQ(test_array_mutable,
+            base::mac::ObjCCastStrict<NSArray>(test_array_mutable));
+  EXPECT_EQ(test_data, base::mac::ObjCCastStrict<NSData>(test_data));
+  EXPECT_EQ(test_data_mutable,
+            base::mac::ObjCCastStrict<NSData>(test_data_mutable));
+  EXPECT_EQ(test_date, base::mac::ObjCCastStrict<NSDate>(test_date));
+  EXPECT_EQ(test_dict, base::mac::ObjCCastStrict<NSDictionary>(test_dict));
+  EXPECT_EQ(test_dict_mutable,
+            base::mac::ObjCCastStrict<NSDictionary>(test_dict_mutable));
+  EXPECT_EQ(test_number, base::mac::ObjCCastStrict<NSNumber>(test_number));
+  EXPECT_EQ(test_null, base::mac::ObjCCastStrict<NSNull>(test_null));
+  EXPECT_EQ(test_set, base::mac::ObjCCastStrict<NSSet>(test_set));
+  EXPECT_EQ(test_set_mutable,
+            base::mac::ObjCCastStrict<NSSet>(test_set_mutable));
+  EXPECT_EQ(test_str, base::mac::ObjCCastStrict<NSString>(test_str));
+  EXPECT_EQ(test_str_const,
+            base::mac::ObjCCastStrict<NSString>(test_str_const));
+  EXPECT_EQ(test_str_mutable,
+            base::mac::ObjCCastStrict<NSString>(test_str_mutable));
+
+  // ObjCCastStrict: Giving a nil provides a nil.
+  EXPECT_FALSE(base::mac::ObjCCastStrict<NSArray>(nil));
+  EXPECT_FALSE(base::mac::ObjCCastStrict<NSData>(nil));
+  EXPECT_FALSE(base::mac::ObjCCastStrict<NSDate>(nil));
+  EXPECT_FALSE(base::mac::ObjCCastStrict<NSDictionary>(nil));
+  EXPECT_FALSE(base::mac::ObjCCastStrict<NSNull>(nil));
+  EXPECT_FALSE(base::mac::ObjCCastStrict<NSNumber>(nil));
+  EXPECT_FALSE(base::mac::ObjCCastStrict<NSSet>(nil));
+  EXPECT_FALSE(base::mac::ObjCCastStrict<NSString>(nil));
+}
+
+TEST(FoundationUtilTest, GetValueFromDictionary) {
+  int one = 1, two = 2, three = 3;
+
+  base::mac::ScopedCFTypeRef<CFNumberRef> cf_one(
+      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &one));
+  base::mac::ScopedCFTypeRef<CFNumberRef> cf_two(
+      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &two));
+  base::mac::ScopedCFTypeRef<CFNumberRef> cf_three(
+      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &three));
+
+  CFStringRef keys[] = { CFSTR("one"), CFSTR("two"), CFSTR("three") };
+  CFNumberRef values[] = { cf_one, cf_two, cf_three };
+
+  COMPILE_ASSERT(arraysize(keys) == arraysize(values),
+                 keys_and_values_arraysizes_are_different);
+
+  base::mac::ScopedCFTypeRef<CFDictionaryRef> test_dict(
+      CFDictionaryCreate(kCFAllocatorDefault,
+                         reinterpret_cast<const void**>(keys),
+                         reinterpret_cast<const void**>(values),
+                         arraysize(values),
+                         &kCFCopyStringDictionaryKeyCallBacks,
+                         &kCFTypeDictionaryValueCallBacks));
+
+  // base::mac::GetValueFromDictionary<>(_, _) should produce the correct
+  // expected output.
+  EXPECT_EQ(values[0],
+            base::mac::GetValueFromDictionary<CFNumberRef>(test_dict,
+                                                           CFSTR("one")));
+  EXPECT_EQ(values[1],
+            base::mac::GetValueFromDictionary<CFNumberRef>(test_dict,
+                                                           CFSTR("two")));
+  EXPECT_EQ(values[2],
+            base::mac::GetValueFromDictionary<CFNumberRef>(test_dict,
+                                                           CFSTR("three")));
+
+  // Bad input should produce bad output.
+  EXPECT_FALSE(base::mac::GetValueFromDictionary<CFNumberRef>(test_dict,
+                                                              CFSTR("four")));
+  EXPECT_FALSE(base::mac::GetValueFromDictionary<CFStringRef>(test_dict,
+                                                              CFSTR("one")));
+}
+
+TEST(FoundationUtilTest, FilePathToNSString) {
+  EXPECT_NSEQ(nil, base::mac::FilePathToNSString(FilePath()));
+  EXPECT_NSEQ(@"/a/b", base::mac::FilePathToNSString(FilePath("/a/b")));
+}
+
+TEST(FoundationUtilTest, NSStringToFilePath) {
+  EXPECT_EQ(FilePath(), base::mac::NSStringToFilePath(nil));
+  EXPECT_EQ(FilePath(), base::mac::NSStringToFilePath(@""));
+  EXPECT_EQ(FilePath("/a/b"), base::mac::NSStringToFilePath(@"/a/b"));
+}
diff --git a/base/mac/launchd.cc b/base/mac/launchd.cc
new file mode 100644
index 0000000..1d384c9
--- /dev/null
+++ b/base/mac/launchd.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/launchd.h"
+
+#include "base/logging.h"
+#include "base/mac/scoped_launch_data.h"
+
+namespace base {
+namespace mac {
+
+// MessageForJob sends a single message to launchd with a simple dictionary
+// mapping |operation| to |job_label|, and returns the result of calling
+// launch_msg to send that message. On failure, returns NULL. The caller
+// assumes ownership of the returned launch_data_t object.
+launch_data_t MessageForJob(const std::string& job_label,
+                            const char* operation) {
+  // launch_data_alloc returns something that needs to be freed.
+  ScopedLaunchData message(launch_data_alloc(LAUNCH_DATA_DICTIONARY));
+  if (!message) {
+    LOG(ERROR) << "launch_data_alloc";
+    return NULL;
+  }
+
+  // launch_data_new_string returns something that needs to be freed, but
+  // the dictionary will assume ownership when launch_data_dict_insert is
+  // called, so put it in a scoper and .release() it when given to the
+  // dictionary.
+  ScopedLaunchData job_label_launchd(launch_data_new_string(job_label.c_str()));
+  if (!job_label_launchd) {
+    LOG(ERROR) << "launch_data_new_string";
+    return NULL;
+  }
+
+  if (!launch_data_dict_insert(message,
+                               job_label_launchd.release(),
+                               operation)) {
+    return NULL;
+  }
+
+  return launch_msg(message);
+}
+
+pid_t PIDForJob(const std::string& job_label) {
+  ScopedLaunchData response(MessageForJob(job_label, LAUNCH_KEY_GETJOB));
+  if (!response) {
+    return -1;
+  }
+
+  launch_data_type_t response_type = launch_data_get_type(response);
+  if (response_type != LAUNCH_DATA_DICTIONARY) {
+    if (response_type == LAUNCH_DATA_ERRNO) {
+      LOG(ERROR) << "PIDForJob: error " << launch_data_get_errno(response);
+    } else {
+      LOG(ERROR) << "PIDForJob: expected dictionary, got " << response_type;
+    }
+    return -1;
+  }
+
+  launch_data_t pid_data = launch_data_dict_lookup(response,
+                                                   LAUNCH_JOBKEY_PID);
+  if (!pid_data)
+    return 0;
+
+  if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) {
+    LOG(ERROR) << "PIDForJob: expected integer";
+    return -1;
+  }
+
+  return launch_data_get_integer(pid_data);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/launchd.h b/base/mac/launchd.h
new file mode 100644
index 0000000..9e4514e
--- /dev/null
+++ b/base/mac/launchd.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_LAUNCHD_H_
+#define BASE_MAC_LAUNCHD_H_
+
+#include <launch.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// MessageForJob sends a single message to launchd with a simple dictionary
+// mapping |operation| to |job_label|, and returns the result of calling
+// launch_msg to send that message. On failure, returns NULL. The caller
+// assumes ownership of the returned launch_data_t object.
+BASE_EXPORT
+launch_data_t MessageForJob(const std::string& job_label,
+                            const char* operation);
+
+// Returns the process ID for |job_label| if the job is running, 0 if the job
+// is loaded but not running, or -1 on error.
+BASE_EXPORT
+pid_t PIDForJob(const std::string& job_label);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_LAUNCHD_H_
diff --git a/base/mac/mac_logging.cc b/base/mac/mac_logging.cc
new file mode 100644
index 0000000..d58220f
--- /dev/null
+++ b/base/mac/mac_logging.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/mac_logging.h"
+
+#include <iomanip>
+
+#if !defined(OS_IOS)
+#include <CoreServices/CoreServices.h>
+#endif
+
+namespace logging {
+
+OSStatusLogMessage::OSStatusLogMessage(const char* file_path,
+                                       int line,
+                                       LogSeverity severity,
+                                       OSStatus status)
+    : LogMessage(file_path, line, severity),
+      status_(status) {
+}
+
+OSStatusLogMessage::~OSStatusLogMessage() {
+#if defined(OS_IOS)
+  // TODO(ios): Consider using NSError with NSOSStatusErrorDomain to try to
+  // get a description of the failure.
+  stream() << ": " << status_;
+#else
+  stream() << ": "
+           << GetMacOSStatusErrorString(status_)
+           << " ("
+           << status_
+           << ")";
+#endif
+}
+
+}  // namespace logging
diff --git a/base/mac/mac_logging.h b/base/mac/mac_logging.h
new file mode 100644
index 0000000..9a0003e
--- /dev/null
+++ b/base/mac/mac_logging.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_MAC_MAC_LOGGING_H_
+#define BASE_MAC_MAC_LOGGING_H_
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(OS_IOS)
+#include <MacTypes.h>
+#else
+#include <libkern/OSTypes.h>
+#endif
+
+// Use the OSSTATUS_LOG family to log messages related to errors in Mac OS X
+// system routines that report status via an OSStatus or OSErr value. It is
+// similar to the PLOG family which operates on errno, but because there is no
+// global (or thread-local) OSStatus or OSErr value, the specific error must
+// be supplied as an argument to the OSSTATUS_LOG macro. The message logged
+// will contain the symbolic constant name corresponding to the status value,
+// along with the value itself.
+//
+// OSErr is just an older 16-bit form of the newer 32-bit OSStatus. Despite
+// the name, OSSTATUS_LOG can be used equally well for OSStatus and OSErr.
+
+namespace logging {
+
+class BASE_EXPORT OSStatusLogMessage : public logging::LogMessage {
+ public:
+  OSStatusLogMessage(const char* file_path,
+                     int line,
+                     LogSeverity severity,
+                     OSStatus status);
+  ~OSStatusLogMessage();
+
+ private:
+  OSStatus status_;
+
+  DISALLOW_COPY_AND_ASSIGN(OSStatusLogMessage);
+};
+
+}  // namespace logging
+
+#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_VPLOG_STREAM(verbose_level, status), \
+                DVLOG_IS_ON(verbose_level))
+#define OSSTATUS_DVLOG_IF(verbose_level, condition, status) \
+    LAZY_STREAM(OSSTATUS_VPLOG_STREAM(verbose_level, status) \
+                DVLOG_IS_ON(verbose_level) && (condition))
+
+#define OSSTATUS_DCHECK(condition, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), \
+                DCHECK_IS_ON() && !(condition)) \
+    << "Check failed: " # condition << ". "
+
+#endif  // BASE_MAC_MAC_LOGGING_H_
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
new file mode 100644
index 0000000..ff8b2b2
--- /dev/null
+++ b/base/mac/mac_util.h
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_MAC_UTIL_H_
+#define BASE_MAC_MAC_UTIL_H_
+
+#include <AvailabilityMacros.h>
+#include <Carbon/Carbon.h>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+
+// TODO(rohitrao): Clean up sites that include mac_util.h and remove this line.
+#include "base/mac/foundation_util.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
+#else  // __OBJC__
+class NSImage;
+#endif  // __OBJC__
+
+class FilePath;
+
+namespace base {
+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 color space being used by the main display.  The return value
+// is a static value; do not release it!
+BASE_EXPORT CGColorSpaceRef GetSystemColorSpace();
+
+// Add a full screen request for the given |mode|.  Must be paired with a
+// ReleaseFullScreen() call for the same |mode|.  This does not by itself create
+// a fullscreen window; rather, it manages per-application state related to
+// hiding the dock and menubar.  Must be called on the main thread.
+BASE_EXPORT void RequestFullScreen(FullScreenMode mode);
+
+// Release a request for full screen mode.  Must be matched with a
+// RequestFullScreen() call for the same |mode|.  As with RequestFullScreen(),
+// this does not affect windows directly, but rather manages per-application
+// state.  For example, if there are no other outstanding
+// |kFullScreenModeAutoHideAll| requests, this will reshow the menu bar.  Must
+// be called on main thread.
+BASE_EXPORT void ReleaseFullScreen(FullScreenMode mode);
+
+// Convenience method to switch the current fullscreen mode.  This has the same
+// net effect as a ReleaseFullScreen(from_mode) call followed immediately by a
+// RequestFullScreen(to_mode).  Must be called on the main thread.
+BASE_EXPORT void SwitchFullScreenModes(FullScreenMode from_mode,
+                                       FullScreenMode to_mode);
+
+// Set the visibility of the cursor.
+BASE_EXPORT void SetCursorVisibility(bool visible);
+
+// Should windows miniaturize on a double-click (on the title bar)?
+BASE_EXPORT bool ShouldWindowsMiniaturizeOnDoubleClick();
+
+// Activates the process with the given PID.
+BASE_EXPORT void ActivateProcess(pid_t pid);
+
+// Returns true if this process is in the foreground, meaning that it's the
+// frontmost process, the one whose menu bar is shown at the top of the main
+// display.
+BASE_EXPORT bool AmIForeground();
+
+// Excludes the file given by |file_path| from being backed up by Time Machine.
+BASE_EXPORT bool SetFileBackupExclusion(const FilePath& file_path);
+
+// Sets the process name as displayed in Activity Monitor to process_name.
+BASE_EXPORT void SetProcessName(CFStringRef process_name);
+
+// Converts a NSImage to a CGImageRef.  Normally, the system frameworks can do
+// this fine, especially on 10.6.  On 10.5, however, CGImage cannot handle
+// converting a PDF-backed NSImage into a CGImageRef.  This function will
+// rasterize the PDF into a bitmap CGImage.  The caller is responsible for
+// releasing the return value.
+BASE_EXPORT CGImageRef CopyNSImageToCGImage(NSImage* image);
+
+// 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' with 'hide on startup' flag. Used to suppress opening windows.
+BASE_EXPORT bool WasLaunchedAsHiddenLoginItem();
+
+// Run-time OS version checks. Use these instead of
+// base::SysInfo::OperatingSystemVersionNumbers. Prefer the "OrEarlier" and
+// "OrLater" variants to those that check for a specific version, unless you
+// know for sure that you need to check for a specific version.
+
+// Snow Leopard is Mac OS X 10.6, Darwin 10.
+BASE_EXPORT bool IsOSSnowLeopard();
+
+// Lion is Mac OS X 10.7, Darwin 11.
+BASE_EXPORT bool IsOSLion();
+BASE_EXPORT bool IsOSLionOrEarlier();
+BASE_EXPORT bool IsOSLionOrLater();
+
+// Mountain Lion is Mac OS X 10.8, Darwin 12.
+BASE_EXPORT bool IsOSMountainLion();
+BASE_EXPORT bool IsOSMountainLionOrLater();
+
+// 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 IsOSLaterThanMountainLion_DontCallThis();
+
+// When the deployment target is set, the code produced cannot run on earlier
+// OS releases. That enables some of the IsOS* family to be implemented as
+// constant-value inline functions. The MAC_OS_X_VERSION_MIN_REQUIRED macro
+// contains the value of the deployment target.
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7
+inline bool IsOSSnowLeopard() { return false; }
+inline bool IsOSLionOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_7
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7
+inline bool IsOSLion() { return false; }
+inline bool IsOSLionOrEarlier() { return false; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_8) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_8
+inline bool IsOSMountainLionOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_8) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_8
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_8
+inline bool IsOSMountainLion() { return false; }
+inline bool IsOSLaterThanMountainLion_DontCallThis() {
+  return true;
+}
+#endif
+
+// Retrieve the system's model identifier string from the IOKit registry:
+// for example, "MacPro4,1", "MacBookPro6,1". Returns empty string upon
+// failure.
+BASE_EXPORT std::string GetModelIdentifier();
+
+// Parse a model identifier string; for example, into ("MacBookPro", 6, 1).
+// If any error occurs, none of the input pointers are touched.
+BASE_EXPORT bool ParseModelIdentifier(const std::string& ident,
+                                      std::string* type,
+                                      int32* major,
+                                      int32* minor);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_MAC_UTIL_H_
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm
new file mode 100644
index 0000000..4fb1a42
--- /dev/null
+++ b/base/mac/mac_util.mm
@@ -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 "base/mac/mac_util.h"
+
+#import <Cocoa/Cocoa.h>
+#import <IOKit/IOKitLib.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_generic_obj.h"
+#include "base/memory/scoped_nsobject.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/sys_string_conversions.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+// The current count of outstanding requests for full screen mode from browser
+// windows, plugins, etc.
+int g_full_screen_requests[kNumFullScreenModes] = { 0, 0, 0};
+
+// Sets the appropriate SystemUIMode based on the current full screen requests.
+// Since only one SystemUIMode can be active at a given time, full screen
+// requests are ordered by priority.  If there are no outstanding full screen
+// requests, reverts to normal mode.  If the correct SystemUIMode is already
+// set, does nothing.
+void SetUIMode() {
+  // Get the current UI mode.
+  SystemUIMode current_mode;
+  GetSystemUIMode(&current_mode, NULL);
+
+  // Determine which mode should be active, based on which requests are
+  // currently outstanding.  More permissive requests take precedence.  For
+  // example, plugins request |kFullScreenModeAutoHideAll|, while browser
+  // windows request |kFullScreenModeHideDock| when the fullscreen overlay is
+  // down.  Precedence goes to plugins in this case, so AutoHideAll wins over
+  // HideDock.
+  SystemUIMode desired_mode = kUIModeNormal;
+  SystemUIOptions desired_options = 0;
+  if (g_full_screen_requests[kFullScreenModeAutoHideAll] > 0) {
+    desired_mode = kUIModeAllHidden;
+    desired_options = kUIOptionAutoShowMenuBar;
+  } else if (g_full_screen_requests[kFullScreenModeHideDock] > 0) {
+    desired_mode = kUIModeContentHidden;
+  } else if (g_full_screen_requests[kFullScreenModeHideAll] > 0) {
+    desired_mode = kUIModeAllHidden;
+  }
+
+  if (current_mode != desired_mode)
+    SetSystemUIMode(desired_mode, desired_options);
+}
+
+// Looks into Shared File Lists corresponding to Login Items for the item
+// representing the current application.  If such an item is found, returns a
+// retained reference to it. Caller is responsible for releasing the reference.
+LSSharedFileListItemRef GetLoginItemForApp() {
+  ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+      NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+  if (!login_items.get()) {
+    DLOG(ERROR) << "Couldn't get a Login Items list.";
+    return NULL;
+  }
+
+  scoped_nsobject<NSArray> login_items_array(
+      CFToNSCast(LSSharedFileListCopySnapshot(login_items, NULL)));
+
+  NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]];
+
+  for(NSUInteger i = 0; i < [login_items_array count]; ++i) {
+    LSSharedFileListItemRef item = reinterpret_cast<LSSharedFileListItemRef>(
+        [login_items_array objectAtIndex:i]);
+    CFURLRef item_url_ref = NULL;
+
+    if (LSSharedFileListItemResolve(item, 0, &item_url_ref, NULL) == noErr) {
+      ScopedCFTypeRef<CFURLRef> item_url(item_url_ref);
+      if (CFEqual(item_url, url)) {
+        CFRetain(item);
+        return item;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+bool IsHiddenLoginItem(LSSharedFileListItemRef item) {
+  ScopedCFTypeRef<CFBooleanRef> hidden(reinterpret_cast<CFBooleanRef>(
+      LSSharedFileListItemCopyProperty(item,
+          reinterpret_cast<CFStringRef>(kLSSharedFileListLoginItemHidden))));
+
+  return hidden && hidden == kCFBooleanTrue;
+}
+
+}  // namespace
+
+std::string PathFromFSRef(const FSRef& ref) {
+  ScopedCFTypeRef<CFURLRef> url(
+      CFURLCreateFromFSRef(kCFAllocatorDefault, &ref));
+  NSString *path_string = [(NSURL *)url.get() path];
+  return [path_string fileSystemRepresentation];
+}
+
+bool FSRefFromPath(const std::string& path, FSRef* ref) {
+  OSStatus status = FSPathMakeRef((const UInt8*)path.c_str(),
+                                  ref, nil);
+  return status == noErr;
+}
+
+CGColorSpaceRef GetSRGBColorSpace() {
+  // Leaked.  That's OK, it's scoped to the lifetime of the application.
+  static CGColorSpaceRef g_color_space_sRGB =
+      CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
+  DLOG_IF(ERROR, !g_color_space_sRGB) << "Couldn't get the sRGB color space";
+  return g_color_space_sRGB;
+}
+
+CGColorSpaceRef GetSystemColorSpace() {
+  // Leaked.  That's OK, it's scoped to the lifetime of the application.
+  // Try to get the main display's color space.
+  static CGColorSpaceRef g_system_color_space =
+      CGDisplayCopyColorSpace(CGMainDisplayID());
+
+  if (!g_system_color_space) {
+    // Use a generic RGB color space.  This is better than nothing.
+    g_system_color_space = CGColorSpaceCreateDeviceRGB();
+
+    if (g_system_color_space) {
+      DLOG(WARNING) <<
+          "Couldn't get the main display's color space, using generic";
+    } else {
+      DLOG(ERROR) << "Couldn't get any color space";
+    }
+  }
+
+  return g_system_color_space;
+}
+
+// Add a request for full screen mode.  Must be called on the main thread.
+void RequestFullScreen(FullScreenMode mode) {
+  DCHECK_LT(mode, kNumFullScreenModes);
+  if (mode >= kNumFullScreenModes)
+    return;
+
+  DCHECK_GE(g_full_screen_requests[mode], 0);
+  g_full_screen_requests[mode] = std::max(g_full_screen_requests[mode] + 1, 1);
+  SetUIMode();
+}
+
+// Release a request for full screen mode.  Must be called on the main thread.
+void ReleaseFullScreen(FullScreenMode mode) {
+  DCHECK_LT(mode, kNumFullScreenModes);
+  if (mode >= kNumFullScreenModes)
+    return;
+
+  DCHECK_GT(g_full_screen_requests[mode], 0);
+  g_full_screen_requests[mode] = std::max(g_full_screen_requests[mode] - 1, 0);
+  SetUIMode();
+}
+
+// Switches full screen modes.  Releases a request for |from_mode| and adds a
+// new request for |to_mode|.  Must be called on the main thread.
+void SwitchFullScreenModes(FullScreenMode from_mode, FullScreenMode to_mode) {
+  DCHECK_LT(from_mode, kNumFullScreenModes);
+  DCHECK_LT(to_mode, kNumFullScreenModes);
+  if (from_mode >= kNumFullScreenModes || to_mode >= kNumFullScreenModes)
+    return;
+
+  DCHECK_GT(g_full_screen_requests[from_mode], 0);
+  DCHECK_GE(g_full_screen_requests[to_mode], 0);
+  g_full_screen_requests[from_mode] =
+      std::max(g_full_screen_requests[from_mode] - 1, 0);
+  g_full_screen_requests[to_mode] =
+      std::max(g_full_screen_requests[to_mode] + 1, 1);
+  SetUIMode();
+}
+
+void SetCursorVisibility(bool visible) {
+  if (visible)
+    [NSCursor unhide];
+  else
+    [NSCursor hide];
+}
+
+bool ShouldWindowsMiniaturizeOnDoubleClick() {
+  // We use an undocumented method in Cocoa; if it doesn't exist, default to
+  // |true|. If it ever goes away, we can do (using an undocumented pref key):
+  //   NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  //   return ![defaults objectForKey:@"AppleMiniaturizeOnDoubleClick"] ||
+  //          [defaults boolForKey:@"AppleMiniaturizeOnDoubleClick"];
+  BOOL methodImplemented =
+      [NSWindow respondsToSelector:@selector(_shouldMiniaturizeOnDoubleClick)];
+  DCHECK(methodImplemented);
+  return !methodImplemented ||
+      [NSWindow performSelector:@selector(_shouldMiniaturizeOnDoubleClick)];
+}
+
+void ActivateProcess(pid_t pid) {
+  ProcessSerialNumber process;
+  OSStatus status = GetProcessForPID(pid, &process);
+  if (status == noErr) {
+    SetFrontProcess(&process);
+  } else {
+    OSSTATUS_DLOG(WARNING, status) << "Unable to get process for pid " << pid;
+  }
+}
+
+bool AmIForeground() {
+  ProcessSerialNumber foreground_psn = { 0 };
+  OSErr err = GetFrontProcess(&foreground_psn);
+  if (err != noErr) {
+    OSSTATUS_DLOG(WARNING, err) << "GetFrontProcess";
+    return false;
+  }
+
+  ProcessSerialNumber my_psn = { 0, kCurrentProcess };
+
+  Boolean result = FALSE;
+  err = SameProcess(&foreground_psn, &my_psn, &result);
+  if (err != noErr) {
+    OSSTATUS_DLOG(WARNING, err) << "SameProcess";
+    return false;
+  }
+
+  return result;
+}
+
+bool SetFileBackupExclusion(const FilePath& file_path) {
+  NSString* file_path_ns =
+      [NSString stringWithUTF8String:file_path.value().c_str()];
+  NSURL* file_url = [NSURL fileURLWithPath:file_path_ns];
+
+  // When excludeByPath is true the application must be running with root
+  // privileges (admin for 10.6 and earlier) but the URL does not have to
+  // already exist. When excludeByPath is false the URL must already exist but
+  // can be used in non-root (or admin as above) mode. We use false so that
+  // non-root (or admin) users don't get their TimeMachine drive filled up with
+  // unnecessary backups.
+  OSStatus os_err =
+      CSBackupSetItemExcluded(base::mac::NSToCFCast(file_url), TRUE, FALSE);
+  if (os_err != noErr) {
+    OSSTATUS_DLOG(WARNING, os_err)
+        << "Failed to set backup exclusion for file '"
+        << file_path.value().c_str() << "'";
+  }
+  return os_err == noErr;
+}
+
+void SetProcessName(CFStringRef process_name) {
+  if (!process_name || CFStringGetLength(process_name) == 0) {
+    NOTREACHED() << "SetProcessName given bad name.";
+    return;
+  }
+
+  if (![NSThread isMainThread]) {
+    NOTREACHED() << "Should only set process name from main thread.";
+    return;
+  }
+
+  // Warning: here be dragons! This is SPI reverse-engineered from WebKit's
+  // plugin host, and could break at any time (although realistically it's only
+  // likely to break in a new major release).
+  // When 10.7 is available, check that this still works, and update this
+  // comment for 10.8.
+
+  // Private CFType used in these LaunchServices calls.
+  typedef CFTypeRef PrivateLSASN;
+  typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
+  typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
+                                                          CFStringRef,
+                                                          CFStringRef,
+                                                          CFDictionaryRef*);
+
+  static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
+      NULL;
+  static LSSetApplicationInformationItemType
+      ls_set_application_information_item_func = NULL;
+  static CFStringRef ls_display_name_key = NULL;
+
+  static bool did_symbol_lookup = false;
+  if (!did_symbol_lookup) {
+    did_symbol_lookup = true;
+    CFBundleRef launch_services_bundle =
+        CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
+    if (!launch_services_bundle) {
+      DLOG(ERROR) << "Failed to look up LaunchServices bundle";
+      return;
+    }
+
+    ls_get_current_application_asn_func =
+        reinterpret_cast<LSGetCurrentApplicationASNType>(
+            CFBundleGetFunctionPointerForName(
+                launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
+    if (!ls_get_current_application_asn_func)
+      DLOG(ERROR) << "Could not find _LSGetCurrentApplicationASN";
+
+    ls_set_application_information_item_func =
+        reinterpret_cast<LSSetApplicationInformationItemType>(
+            CFBundleGetFunctionPointerForName(
+                launch_services_bundle,
+                CFSTR("_LSSetApplicationInformationItem")));
+    if (!ls_set_application_information_item_func)
+      DLOG(ERROR) << "Could not find _LSSetApplicationInformationItem";
+
+    CFStringRef* key_pointer = reinterpret_cast<CFStringRef*>(
+        CFBundleGetDataPointerForName(launch_services_bundle,
+                                      CFSTR("_kLSDisplayNameKey")));
+    ls_display_name_key = key_pointer ? *key_pointer : NULL;
+    if (!ls_display_name_key)
+      DLOG(ERROR) << "Could not find _kLSDisplayNameKey";
+
+    // Internally, this call relies on the Mach ports that are started up by the
+    // Carbon Process Manager.  In debug builds this usually happens due to how
+    // the logging layers are started up; but in release, it isn't started in as
+    // much of a defined order.  So if the symbols had to be loaded, go ahead
+    // and force a call to make sure the manager has been initialized and hence
+    // the ports are opened.
+    ProcessSerialNumber psn;
+    GetCurrentProcess(&psn);
+  }
+  if (!ls_get_current_application_asn_func ||
+      !ls_set_application_information_item_func ||
+      !ls_display_name_key) {
+    return;
+  }
+
+  PrivateLSASN asn = ls_get_current_application_asn_func();
+  // Constant used by WebKit; what exactly it means is unknown.
+  const int magic_session_constant = -2;
+  OSErr err =
+      ls_set_application_information_item_func(magic_session_constant, asn,
+                                               ls_display_name_key,
+                                               process_name,
+                                               NULL /* optional out param */);
+  OSSTATUS_DLOG_IF(ERROR, err != noErr, err)
+      << "Call to set process name failed";
+}
+
+// Converts a NSImage to a CGImageRef.  Normally, the system frameworks can do
+// this fine, especially on 10.6.  On 10.5, however, CGImage cannot handle
+// converting a PDF-backed NSImage into a CGImageRef.  This function will
+// rasterize the PDF into a bitmap CGImage.  The caller is responsible for
+// releasing the return value.
+CGImageRef CopyNSImageToCGImage(NSImage* image) {
+  // This is based loosely on http://www.cocoadev.com/index.pl?CGImageRef .
+  NSSize size = [image size];
+  ScopedCFTypeRef<CGContextRef> context(
+      CGBitmapContextCreate(NULL,  // Allow CG to allocate memory.
+                            size.width,
+                            size.height,
+                            8,  // bitsPerComponent
+                            0,  // bytesPerRow - CG will calculate by default.
+                            [[NSColorSpace genericRGBColorSpace] CGColorSpace],
+                            kCGBitmapByteOrder32Host |
+                                kCGImageAlphaPremultipliedFirst));
+  if (!context.get())
+    return NULL;
+
+  [NSGraphicsContext saveGraphicsState];
+  [NSGraphicsContext setCurrentContext:
+      [NSGraphicsContext graphicsContextWithGraphicsPort:context.get()
+                                                 flipped:NO]];
+  [image drawInRect:NSMakeRect(0,0, size.width, size.height)
+           fromRect:NSZeroRect
+          operation:NSCompositeCopy
+           fraction:1.0];
+  [NSGraphicsContext restoreGraphicsState];
+
+  return CGBitmapContextCreateImage(context);
+}
+
+bool CheckLoginItemStatus(bool* is_hidden) {
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (!item.get())
+    return false;
+
+  if (is_hidden)
+    *is_hidden = IsHiddenLoginItem(item);
+
+  return true;
+}
+
+void AddToLoginItems(bool hide_on_startup) {
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (item.get() && (IsHiddenLoginItem(item) == hide_on_startup)) {
+    return;  // Already is a login item with required hide flag.
+  }
+
+  ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+      NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+  if (!login_items.get()) {
+    DLOG(ERROR) << "Couldn't get a Login Items list.";
+    return;
+  }
+
+  // Remove the old item, it has wrong hide flag, we'll create a new one.
+  if (item.get()) {
+    LSSharedFileListItemRemove(login_items, item);
+  }
+
+  NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]];
+
+  BOOL hide = hide_on_startup ? YES : NO;
+  NSDictionary* properties =
+      [NSDictionary
+        dictionaryWithObject:[NSNumber numberWithBool:hide]
+                      forKey:(NSString*)kLSSharedFileListLoginItemHidden];
+
+  ScopedCFTypeRef<LSSharedFileListItemRef> new_item;
+  new_item.reset(LSSharedFileListInsertItemURL(
+      login_items, kLSSharedFileListItemLast, NULL, NULL,
+      reinterpret_cast<CFURLRef>(url),
+      reinterpret_cast<CFDictionaryRef>(properties), NULL));
+
+  if (!new_item.get()) {
+    DLOG(ERROR) << "Couldn't insert current app into Login Items list.";
+  }
+}
+
+void RemoveFromLoginItems() {
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (!item.get())
+    return;
+
+  ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+      NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+  if (!login_items.get()) {
+    DLOG(ERROR) << "Couldn't get a Login Items list.";
+    return;
+  }
+
+  LSSharedFileListItemRemove(login_items, item);
+}
+
+bool WasLaunchedAsLoginOrResumeItem() {
+  ProcessSerialNumber psn = { 0, kCurrentProcess };
+
+  scoped_nsobject<NSDictionary> process_info(
+      CFToNSCast(ProcessInformationCopyDictionary(&psn,
+                     kProcessDictionaryIncludeAllInformationMask)));
+
+  long long temp = [[process_info objectForKey:@"ParentPSN"] longLongValue];
+  ProcessSerialNumber parent_psn =
+      { (temp >> 32) & 0x00000000FFFFFFFFLL, temp & 0x00000000FFFFFFFFLL };
+
+  scoped_nsobject<NSDictionary> parent_info(
+      CFToNSCast(ProcessInformationCopyDictionary(&parent_psn,
+                     kProcessDictionaryIncludeAllInformationMask)));
+
+  // Check that creator process code is that of loginwindow.
+  BOOL result =
+      [[parent_info objectForKey:@"FileCreator"] isEqualToString:@"lgnw"];
+
+  return result == YES;
+}
+
+bool WasLaunchedAsHiddenLoginItem() {
+  if (!WasLaunchedAsLoginOrResumeItem())
+    return false;
+
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (!item.get()) {
+    // Lion can launch items for the resume feature.  So log an error only for
+    // Snow Leopard or earlier.
+    if (IsOSSnowLeopard())
+      DLOG(ERROR) <<
+          "Process launched at Login but can't access Login Item List.";
+
+    return false;
+  }
+  return IsHiddenLoginItem(item);
+}
+
+namespace {
+
+// Returns the running system's Darwin major version. Don't call this, it's
+// an implementation detail and its result is meant to be cached by
+// MacOSXMinorVersion.
+int DarwinMajorVersionInternal() {
+  // base::OperatingSystemVersionNumbers calls Gestalt, which is a
+  // higher-level operation than is needed. It might perform unnecessary
+  // operations. On 10.6, it was observed to be able to spawn threads (see
+  // http://crbug.com/53200). It might also read files or perform other
+  // blocking operations. Actually, nobody really knows for sure just what
+  // Gestalt might do, or what it might be taught to do in the future.
+  //
+  // uname, on the other hand, is implemented as a simple series of sysctl
+  // system calls to obtain the relevant data from the kernel. The data is
+  // compiled right into the kernel, so no threads or blocking or other
+  // funny business is necessary.
+
+  struct utsname uname_info;
+  if (uname(&uname_info) != 0) {
+    DPLOG(ERROR) << "uname";
+    return 0;
+  }
+
+  if (strcmp(uname_info.sysname, "Darwin") != 0) {
+    DLOG(ERROR) << "unexpected uname sysname " << uname_info.sysname;
+    return 0;
+  }
+
+  int darwin_major_version = 0;
+  char* dot = strchr(uname_info.release, '.');
+  if (dot) {
+    if (!base::StringToInt(base::StringPiece(uname_info.release,
+                                             dot - uname_info.release),
+                           &darwin_major_version)) {
+      dot = NULL;
+    }
+  }
+
+  if (!dot) {
+    DLOG(ERROR) << "could not parse uname release " << uname_info.release;
+    return 0;
+  }
+
+  return darwin_major_version;
+}
+
+// Returns the running system's Mac OS X minor version. This is the |y| value
+// in 10.y or 10.y.z. Don't call this, it's an implementation detail and the
+// result is meant to be cached by MacOSXMinorVersion.
+int MacOSXMinorVersionInternal() {
+  int darwin_major_version = DarwinMajorVersionInternal();
+
+  // The Darwin major version is always 4 greater than the Mac OS X minor
+  // version for Darwin versions beginning with 6, corresponding to Mac OS X
+  // 10.2. Since this correspondence may change in the future, warn when
+  // encountering a version higher than anything seen before. Older Darwin
+  // versions, or versions that can't be determined, result in
+  // immediate death.
+  CHECK(darwin_major_version >= 6);
+  int mac_os_x_minor_version = darwin_major_version - 4;
+  DLOG_IF(WARNING, darwin_major_version > 12) << "Assuming Darwin "
+      << base::IntToString(darwin_major_version) << " is Mac OS X 10."
+      << base::IntToString(mac_os_x_minor_version);
+
+  return mac_os_x_minor_version;
+}
+
+// Returns the running system's Mac OS X minor version. This is the |y| value
+// in 10.y or 10.y.z.
+int MacOSXMinorVersion() {
+  static int mac_os_x_minor_version = MacOSXMinorVersionInternal();
+  return mac_os_x_minor_version;
+}
+
+enum {
+  SNOW_LEOPARD_MINOR_VERSION = 6,
+  LION_MINOR_VERSION = 7,
+  MOUNTAIN_LION_MINOR_VERSION = 8,
+};
+
+}  // namespace
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7)
+bool IsOSSnowLeopard() {
+  return MacOSXMinorVersion() == SNOW_LEOPARD_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7)
+bool IsOSLion() {
+  return MacOSXMinorVersion() == LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7)
+bool IsOSLionOrEarlier() {
+  return MacOSXMinorVersion() <= LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7)
+bool IsOSLionOrLater() {
+  return MacOSXMinorVersion() >= LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_8)
+bool IsOSMountainLion() {
+  return MacOSXMinorVersion() == MOUNTAIN_LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_8)
+bool IsOSMountainLionOrLater() {
+  return MacOSXMinorVersion() >= MOUNTAIN_LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_8)
+bool IsOSLaterThanMountainLion_DontCallThis() {
+  return MacOSXMinorVersion() > MOUNTAIN_LION_MINOR_VERSION;
+}
+#endif
+
+namespace {
+
+// ScopedGenericObj functor for IOObjectRelease().
+class ScopedReleaseIOObject {
+ public:
+  void operator()(io_object_t x) const {
+    IOObjectRelease(x);
+  }
+};
+
+}  // namespace
+
+std::string GetModelIdentifier() {
+  ScopedGenericObj<io_service_t, ScopedReleaseIOObject>
+      platform_expert(IOServiceGetMatchingService(
+          kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")));
+  if (!platform_expert)
+    return "";
+  ScopedCFTypeRef<CFDataRef> model_data(
+      static_cast<CFDataRef>(IORegistryEntryCreateCFProperty(
+          platform_expert,
+          CFSTR("model"),
+          kCFAllocatorDefault,
+          0)));
+  if (!model_data)
+    return "";
+  return reinterpret_cast<const char*>(
+      CFDataGetBytePtr(model_data));
+}
+
+bool ParseModelIdentifier(const std::string& ident,
+                          std::string* type,
+                          int32* major,
+                          int32* minor) {
+  size_t number_loc = ident.find_first_of("0123456789");
+  if (number_loc == std::string::npos)
+    return false;
+  size_t comma_loc = ident.find(',', number_loc);
+  if (comma_loc == std::string::npos)
+    return false;
+  int32 major_tmp, minor_tmp;
+  std::string::const_iterator begin = ident.begin();
+  if (!StringToInt(
+          StringPiece(begin + number_loc, begin + comma_loc), &major_tmp) ||
+      !StringToInt(
+          StringPiece(begin + comma_loc + 1, ident.end()), &minor_tmp))
+    return false;
+  *type = ident.substr(0, number_loc);
+  *major = major_tmp;
+  *minor = minor_tmp;
+  return true;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm
new file mode 100644
index 0000000..2984fee
--- /dev/null
+++ b/base/mac/mac_util_unittest.mm
@@ -0,0 +1,212 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/mac_util.h"
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_nsobject.h"
+#include "base/scoped_temp_dir.h"
+#include "base/sys_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+typedef PlatformTest MacUtilTest;
+
+TEST_F(MacUtilTest, TestFSRef) {
+  FSRef ref;
+  std::string path("/System/Library");
+
+  ASSERT_TRUE(FSRefFromPath(path, &ref));
+  EXPECT_EQ(path, PathFromFSRef(ref));
+}
+
+TEST_F(MacUtilTest, GetUserDirectoryTest) {
+  // Try a few keys, make sure they come back with non-empty paths.
+  FilePath caches_dir;
+  EXPECT_TRUE(GetUserDirectory(NSCachesDirectory, &caches_dir));
+  EXPECT_FALSE(caches_dir.empty());
+
+  FilePath application_support_dir;
+  EXPECT_TRUE(GetUserDirectory(NSApplicationSupportDirectory,
+                               &application_support_dir));
+  EXPECT_FALSE(application_support_dir.empty());
+
+  FilePath library_dir;
+  EXPECT_TRUE(GetUserDirectory(NSLibraryDirectory, &library_dir));
+  EXPECT_FALSE(library_dir.empty());
+}
+
+TEST_F(MacUtilTest, TestLibraryPath) {
+  FilePath library_dir = GetUserLibraryPath();
+  // Make sure the string isn't empty.
+  EXPECT_FALSE(library_dir.value().empty());
+}
+
+TEST_F(MacUtilTest, TestGetAppBundlePath) {
+  FilePath out;
+
+  // Make sure it doesn't crash.
+  out = GetAppBundlePath(FilePath());
+  EXPECT_TRUE(out.empty());
+
+  // Some more invalid inputs.
+  const char* invalid_inputs[] = {
+    "/", "/foo", "foo", "/foo/bar.", "foo/bar.", "/foo/bar./bazquux",
+    "foo/bar./bazquux", "foo/.app", "//foo",
+  };
+  for (size_t i = 0; i < arraysize(invalid_inputs); i++) {
+    out = GetAppBundlePath(FilePath(invalid_inputs[i]));
+    EXPECT_TRUE(out.empty()) << "loop: " << i;
+  }
+
+  // Some valid inputs; this and |expected_outputs| should be in sync.
+  struct {
+    const char *in;
+    const char *expected_out;
+  } valid_inputs[] = {
+    { "FooBar.app/", "FooBar.app" },
+    { "/FooBar.app", "/FooBar.app" },
+    { "/FooBar.app/", "/FooBar.app" },
+    { "//FooBar.app", "//FooBar.app" },
+    { "/Foo/Bar.app", "/Foo/Bar.app" },
+    { "/Foo/Bar.app/", "/Foo/Bar.app" },
+    { "/F/B.app", "/F/B.app" },
+    { "/F/B.app/", "/F/B.app" },
+    { "/Foo/Bar.app/baz", "/Foo/Bar.app" },
+    { "/Foo/Bar.app/baz/", "/Foo/Bar.app" },
+    { "/Foo/Bar.app/baz/quux.app/quuux", "/Foo/Bar.app" },
+    { "/Applications/Google Foo.app/bar/Foo Helper.app/quux/Foo Helper",
+        "/Applications/Google Foo.app" },
+  };
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(valid_inputs); i++) {
+    out = GetAppBundlePath(FilePath(valid_inputs[i].in));
+    EXPECT_FALSE(out.empty()) << "loop: " << i;
+    EXPECT_STREQ(valid_inputs[i].expected_out,
+        out.value().c_str()) << "loop: " << i;
+  }
+}
+
+TEST_F(MacUtilTest, TestExcludeFileFromBackups) {
+  // The file must already exist in order to set its exclusion property.
+  ScopedTempDir temp_dir_;
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  FilePath dummy_file_path = temp_dir_.path().Append("DummyFile");
+  const char dummy_data[] = "All your base are belong to us!";
+  // Dump something real into the file.
+  ASSERT_EQ(static_cast<int>(arraysize(dummy_data)),
+      file_util::WriteFile(dummy_file_path, dummy_data, arraysize(dummy_data)));
+  NSString* fileURLString =
+      [NSString stringWithUTF8String:dummy_file_path.value().c_str()];
+  NSURL* fileURL = [NSURL URLWithString:fileURLString];
+  // Initial state should be non-excluded.
+  EXPECT_FALSE(CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), NULL));
+  // Exclude the file.
+  EXPECT_TRUE(SetFileBackupExclusion(dummy_file_path));
+  // SetFileBackupExclusion never excludes by path.
+  Boolean excluded_by_path = FALSE;
+  Boolean excluded =
+      CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), &excluded_by_path);
+  EXPECT_TRUE(excluded);
+  EXPECT_FALSE(excluded_by_path);
+}
+
+TEST_F(MacUtilTest, CopyNSImageToCGImage) {
+  scoped_nsobject<NSImage> nsImage(
+      [[NSImage alloc] initWithSize:NSMakeSize(20, 20)]);
+  [nsImage lockFocus];
+  [[NSColor redColor] set];
+  NSRect rect = NSZeroRect;
+  rect.size = [nsImage size];
+  NSRectFill(rect);
+  [nsImage unlockFocus];
+
+  ScopedCFTypeRef<CGImageRef> cgImage(CopyNSImageToCGImage(nsImage.get()));
+  EXPECT_TRUE(cgImage.get());
+}
+
+TEST_F(MacUtilTest, NSObjectRetainRelease) {
+  scoped_nsobject<NSArray> array([[NSArray alloc] initWithObjects:@"foo", nil]);
+  EXPECT_EQ(1U, [array retainCount]);
+
+  NSObjectRetain(array);
+  EXPECT_EQ(2U, [array retainCount]);
+
+  NSObjectRelease(array);
+  EXPECT_EQ(1U, [array retainCount]);
+}
+
+TEST_F(MacUtilTest, IsOSEllipsis) {
+  int32 major, minor, bugfix;
+  base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+
+  if (major == 10) {
+    if (minor == 6) {
+      EXPECT_TRUE(IsOSSnowLeopard());
+      EXPECT_FALSE(IsOSLion());
+      EXPECT_TRUE(IsOSLionOrEarlier());
+      EXPECT_FALSE(IsOSLionOrLater());
+      EXPECT_FALSE(IsOSMountainLion());
+      EXPECT_FALSE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSLaterThanMountainLion_DontCallThis());
+    } else if (minor == 7) {
+      EXPECT_FALSE(IsOSSnowLeopard());
+      EXPECT_TRUE(IsOSLion());
+      EXPECT_TRUE(IsOSLionOrEarlier());
+      EXPECT_TRUE(IsOSLionOrLater());
+      EXPECT_FALSE(IsOSMountainLion());
+      EXPECT_FALSE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSLaterThanMountainLion_DontCallThis());
+    } else if (minor == 8) {
+      EXPECT_FALSE(IsOSSnowLeopard());
+      EXPECT_FALSE(IsOSLion());
+      EXPECT_FALSE(IsOSLionOrEarlier());
+      EXPECT_TRUE(IsOSLionOrLater());
+      EXPECT_TRUE(IsOSMountainLion());
+      EXPECT_TRUE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSLaterThanMountainLion_DontCallThis());
+    } else {
+      // Not five, six, seven, or eight. Ah, ah, ah.
+      EXPECT_TRUE(false);
+    }
+  } else {
+    // Not ten. What you gonna do?
+    EXPECT_FALSE(true);
+  }
+}
+
+TEST_F(MacUtilTest, ParseModelIdentifier) {
+  std::string model;
+  int32 major = 1, minor = 2;
+
+  EXPECT_FALSE(ParseModelIdentifier("", &model, &major, &minor));
+  EXPECT_EQ(0U, model.length());
+  EXPECT_EQ(1, major);
+  EXPECT_EQ(2, minor);
+  EXPECT_FALSE(ParseModelIdentifier("FooBar", &model, &major, &minor));
+
+  EXPECT_TRUE(ParseModelIdentifier("MacPro4,1", &model, &major, &minor));
+  EXPECT_EQ(model, "MacPro");
+  EXPECT_EQ(4, major);
+  EXPECT_EQ(1, minor);
+
+  EXPECT_TRUE(ParseModelIdentifier("MacBookPro6,2", &model, &major, &minor));
+  EXPECT_EQ(model, "MacBookPro");
+  EXPECT_EQ(6, major);
+  EXPECT_EQ(2, minor);
+}
+
+}  // namespace
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/objc_property_releaser.h b/base/mac/objc_property_releaser.h
new file mode 100644
index 0000000..973d793
--- /dev/null
+++ b/base/mac/objc_property_releaser.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_OBJC_PROPERTY_RELEASER_H_
+#define BASE_MAC_OBJC_PROPERTY_RELEASER_H_
+
+#import <Foundation/Foundation.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// ObjCPropertyReleaser is a C++ class that can automatically release
+// synthesized Objective-C properties marked "retain" or "copy". The expected
+// use is to place an ObjCPropertyReleaser object within an Objective-C class
+// definition. When built with the -fobjc-call-cxx-cdtors compiler option,
+// the ObjCPropertyReleaser's destructor will be called when the Objective-C
+// object that owns it is deallocated, and it will send a -release message to
+// the instance variables backing the appropriate properties. If
+// -fobjc-call-cxx-cdtors is not in use, ObjCPropertyReleaser's
+// ReleaseProperties method can be called from -dealloc to achieve the same
+// effect.
+//
+// Example usage:
+//
+// @interface AllaysIBF : NSObject {
+//  @private
+//   NSString* string_;
+//   NSMutableDictionary* dictionary_;
+//   NSString* notAProperty_;
+//   IBFDelegate* delegate_;  // weak
+//
+//   // It's recommended to put the class name into the property releaser's
+//   // instance variable name to gracefully handle subclassing, where
+//   // multiple classes in a hierarchy might want their own property
+//   // releasers.
+//   base::mac::ObjCPropertyReleaser propertyReleaser_AllaysIBF_;
+// }
+//
+// @property(retain, nonatomic) NSString* string;
+// @property(copy, nonatomic) NSMutableDictionary* dictionary;
+// @property(assign, nonatomic) IBFDelegate* delegate;
+// @property(retain, nonatomic) NSString* autoProp;
+//
+// @end  // @interface AllaysIBF
+//
+// @implementation AllaysIBF
+//
+// @synthesize string = string_;
+// @synthesize dictionary = dictionary_;
+// @synthesize delegate = delegate_;
+// @synthesize autoProp;
+//
+// - (id)init {
+//   if ((self = [super init])) {
+//     // Initialize with [AllaysIBF class]. Never use [self class] because
+//     // in the case of subclassing, it will return the most specific class
+//     // for |self|, which may not be the same as [AllaysIBF class]. This
+//     // would cause AllaysIBF's -.cxx_destruct or -dealloc to release
+//     // instance variables that only exist in subclasses, likely causing
+//     // mass disaster.
+//     propertyReleaser_AllaysIBF_.Init(self, [AllaysIBF class]);
+//   }
+//   return self;
+// }
+//
+// @end  // @implementation AllaysIBF
+//
+// When an instance of AllaysIBF is deallocated, the ObjCPropertyReleaser will
+// send a -release message to string_, dictionary_, and the compiler-created
+// autoProp instance variables. No -release will be sent to delegate_ as it
+// is marked "assign" and not "retain" or "copy". No -release will be sent to
+// notAProperty_ because it doesn't correspond to any declared @property.
+//
+// Another way of doing this would be to provide a base class that others can
+// inherit from, and to have the base class' -dealloc walk the property lists
+// of all subclasses in an object to send the -release messages. Since this
+// involves a base reaching into its subclasses, it's deemed scary, so don't
+// do it. ObjCPropertyReleaser's design ensures that the property releaser
+// will only operate on instance variables in the immediate object in which
+// the property releaser is placed.
+
+class BASE_EXPORT ObjCPropertyReleaser {
+ public:
+  // ObjCPropertyReleaser can only be owned by an Objective-C object, so its
+  // memory is always guaranteed to be 0-initialized. Not defining the default
+  // constructor can prevent an otherwise no-op -.cxx_construct method from
+  // showing up in Objective-C classes that contain a ObjCPropertyReleaser.
+
+  // Upon destruction (expected to occur from an Objective-C object's
+  // -.cxx_destruct method), release all properties.
+  ~ObjCPropertyReleaser() {
+    ReleaseProperties();
+  }
+
+  // Initialize this object so that it's armed to release the properties of
+  // object |object|, which must be of type |classy|. The class argument must
+  // be supplied separately and cannot be gleaned from the object's own type
+  // because an object will allays identify itself as the most-specific type
+  // that describes it, but the ObjCPropertyReleaser needs to know which class
+  // type in the class hierarchy it's responsible for releasing properties
+  // for. For the same reason, Init must be called with a |classy| argument
+  // initialized using a +class (class) method such as [MyClass class], and
+  // never a -class (instance) method such as [self class].
+  //
+  // -.cxx_construct can only call the default constructor, but
+  // ObjCPropertyReleaser needs to know about the Objective-C object that owns
+  // it, so this can't be handled in a constructor, it needs to be a distinct
+  // Init method.
+  void Init(id object, Class classy);
+
+  // Release all of the properties in object_ defined in class_ as either
+  // "retain" or "copy" and with an identifiable backing instance variable.
+  // Properties must be synthesized to have identifiable instance variables.
+  void ReleaseProperties();
+
+ private:
+  id object_;
+  Class class_;
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_OBJC_PROPERTY_RELEASER_H_
diff --git a/base/mac/objc_property_releaser.mm b/base/mac/objc_property_releaser.mm
new file mode 100644
index 0000000..f7ee88f
--- /dev/null
+++ b/base/mac/objc_property_releaser.mm
@@ -0,0 +1,131 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/objc_property_releaser.h"
+
+#import <objc/runtime.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+// Returns the name of the instance variable backing the property, if known,
+// if the property is marked "retain" or "copy". If the instance variable name
+// is not known (perhaps because it was not automatically associated with the
+// property by @synthesize) or if the property is not "retain" or "copy",
+// returns an empty string.
+std::string ReleasableInstanceName(objc_property_t property) {
+  // TODO(mark): Starting in newer system releases, the Objective-C runtime
+  // provides a function to break the property attribute string into
+  // individual attributes (property_copyAttributeList), as well as a function
+  // to look up the value of a specific attribute
+  // (property_copyAttributeValue). When the SDK defining that interface is
+  // final, this function should be adapted to walk the attribute list as
+  // returned by property_copyAttributeList when that function is available in
+  // preference to scanning through the attribute list manually.
+
+  // The format of the string returned by property_getAttributes is documented
+  // at
+  // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW6
+  const char* property_attributes = property_getAttributes(property);
+
+  std::string instance_name;
+  bool releasable = false;
+  while (*property_attributes) {
+    char name = *property_attributes;
+
+    const char* value = ++property_attributes;
+    while (*property_attributes && *property_attributes != ',') {
+      ++property_attributes;
+    }
+
+    switch (name) {
+      // It might seem intelligent to check the type ('T') attribute to verify
+      // that it identifies an NSObject-derived type (the attribute value
+      // begins with '@'.) This is a bad idea beacuse it fails to identify
+      // CFTypeRef-based properties declared as __attribute__((NSObject)),
+      // which just show up as pointers to their underlying CFType structs.
+      //
+      // Quoting
+      // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW27
+      //
+      // > In Mac OS X v10.6 and later, you can use the __attribute__ keyword
+      // > to specify that a Core Foundation property should be treated like
+      // > an Objective-C object for memory management:
+      // >   @property(retain) __attribute__((NSObject)) CFDictionaryRef
+      // >       myDictionary;
+      case 'C':  // copy
+      case '&':  // retain
+        releasable = true;
+        break;
+      case 'V':  // instance variable name
+        // 'V' is specified as the last attribute to occur in the
+        // documentation, but empirically, it's not always the last. In
+        // GC-supported or GC-required code, the 'P' (GC-eligible) attribute
+        // occurs after 'V'.
+        instance_name.assign(value, property_attributes - value);
+        break;
+    }
+
+    if (*property_attributes) {
+      ++property_attributes;
+    }
+  }
+
+  if (releasable) {
+    return instance_name;
+  }
+
+  return std::string();
+}
+
+}  // namespace
+
+void ObjCPropertyReleaser::Init(id object, Class classy) {
+  DCHECK(!object_);
+  DCHECK(!class_);
+  CHECK([object isKindOfClass:classy]);
+
+  object_ = object;
+  class_ = classy;
+}
+
+void ObjCPropertyReleaser::ReleaseProperties() {
+  DCHECK(object_);
+  DCHECK(class_);
+
+  unsigned int property_count = 0;
+  objc_property_t* properties = class_copyPropertyList(class_, &property_count);
+
+  for (unsigned int property_index = 0;
+       property_index < property_count;
+       ++property_index) {
+    objc_property_t property = properties[property_index];
+    std::string instance_name = ReleasableInstanceName(property);
+    if (!instance_name.empty()) {
+      id instance_value = nil;
+      Ivar instance_variable =
+          object_getInstanceVariable(object_, instance_name.c_str(),
+                                     (void**)&instance_value);
+      DCHECK(instance_variable);
+      [instance_value release];
+    }
+  }
+
+  free(properties);
+
+  // Clear object_ and class_ in case this ObjCPropertyReleaser will live on.
+  // It's only expected to release the properties it supervises once per Init.
+  object_ = nil;
+  class_ = nil;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/objc_property_releaser_unittest.mm b/base/mac/objc_property_releaser_unittest.mm
new file mode 100644
index 0000000..50f81a8
--- /dev/null
+++ b/base/mac/objc_property_releaser_unittest.mm
@@ -0,0 +1,350 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Foundation/Foundation.h>
+
+#import "base/mac/objc_property_releaser.h"
+#import "base/mac/scoped_nsautorelease_pool.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// "When I'm alone, I count myself."
+//   --Count von Count, http://www.youtube.com/watch?v=FKzszqa9WA4
+
+namespace {
+
+// The number of CountVonCounts outstanding.
+int ah_ah_ah;
+
+// NumberHolder exists to exercise the property attribute string parser by
+// providing a named struct and an anonymous union.
+struct NumberHolder {
+  union {
+    long long sixty_four;
+    int thirty_two;
+    short sixteen;
+    char eight;
+  } what;
+  enum {
+    SIXTY_FOUR,
+    THIRTY_TWO,
+    SIXTEEN,
+    EIGHT
+  } how;
+};
+
+}  // namespace
+
+@interface CountVonCount : NSObject<NSCopying>
+
++ (CountVonCount*)countVonCount;
+
+@end  // @interface CountVonCount
+
+@implementation CountVonCount
+
++ (CountVonCount*)countVonCount {
+  return [[[CountVonCount alloc] init] autorelease];
+}
+
+- (id)init {
+  ++ah_ah_ah;
+  return [super init];
+}
+
+- (void)dealloc {
+  --ah_ah_ah;
+  [super dealloc];
+}
+
+- (id)copyWithZone:(NSZone*)zone {
+  return [[CountVonCount allocWithZone:zone] init];
+}
+
+@end  // @implementation CountVonCount
+
+@interface ObjCPropertyTestBase : NSObject {
+ @private
+  CountVonCount* baseCvcRetain_;
+  CountVonCount* baseCvcCopy_;
+  CountVonCount* baseCvcAssign_;
+  CountVonCount* baseCvcNotProperty_;
+  CountVonCount* baseCvcNil_;
+  CountVonCount* baseCvcCustom_;
+  int baseInt_;
+  double baseDouble_;
+  void* basePointer_;
+  NumberHolder baseStruct_;
+
+  base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestBase_;
+}
+
+@property(retain, nonatomic) CountVonCount* baseCvcRetain;
+@property(copy, nonatomic) CountVonCount* baseCvcCopy;
+@property(assign, nonatomic) CountVonCount* baseCvcAssign;
+@property(retain, nonatomic) CountVonCount* baseCvcNil;
+@property(retain, nonatomic, getter=baseCustom, setter=setBaseCustom:)
+    CountVonCount* baseCvcCustom;
+@property(retain, nonatomic) CountVonCount* baseCvcDynamic;
+@property(assign, nonatomic) int baseInt;
+@property(assign, nonatomic) double baseDouble;
+@property(assign, nonatomic) void* basePointer;
+@property(assign, nonatomic) NumberHolder baseStruct;
+
+- (void)setBaseCvcNotProperty:(CountVonCount*)cvc;
+
+@end  // @interface ObjCPropertyTestBase
+
+@implementation ObjCPropertyTestBase
+
+@synthesize baseCvcRetain = baseCvcRetain_;
+@synthesize baseCvcCopy = baseCvcCopy_;
+@synthesize baseCvcAssign = baseCvcAssign_;
+@synthesize baseCvcNil = baseCvcNil_;
+@synthesize baseCvcCustom = baseCvcCustom_;
+@dynamic baseCvcDynamic;
+@synthesize baseInt = baseInt_;
+@synthesize baseDouble = baseDouble_;
+@synthesize basePointer = basePointer_;
+@synthesize baseStruct = baseStruct_;
+
+- (id)init {
+  if ((self = [super init])) {
+    propertyReleaser_ObjCPropertyTestBase_.Init(
+        self, [ObjCPropertyTestBase class]);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [baseCvcNotProperty_ release];
+  [super dealloc];
+}
+
+- (void)setBaseCvcNotProperty:(CountVonCount*)cvc {
+  if (cvc != baseCvcNotProperty_) {
+    [baseCvcNotProperty_ release];
+    baseCvcNotProperty_ = [cvc retain];
+  }
+}
+
+@end  // @implementation ObjCPropertyTestBase
+
+@protocol ObjCPropertyTestProtocol
+
+@property(retain, nonatomic) CountVonCount* protoCvcRetain;
+@property(copy, nonatomic) CountVonCount* protoCvcCopy;
+@property(assign, nonatomic) CountVonCount* protoCvcAssign;
+@property(retain, nonatomic) CountVonCount* protoCvcNil;
+@property(retain, nonatomic, getter=protoCustom, setter=setProtoCustom:)
+    CountVonCount* protoCvcCustom;
+@property(retain, nonatomic) CountVonCount* protoCvcDynamic;
+@property(assign, nonatomic) int protoInt;
+@property(assign, nonatomic) double protoDouble;
+@property(assign, nonatomic) void* protoPointer;
+@property(assign, nonatomic) NumberHolder protoStruct;
+
+@end  // @protocol ObjCPropertyTestProtocol
+
+@interface ObjCPropertyTestDerived
+    : ObjCPropertyTestBase<ObjCPropertyTestProtocol> {
+ @private
+  CountVonCount* derivedCvcRetain_;
+  CountVonCount* derivedCvcCopy_;
+  CountVonCount* derivedCvcAssign_;
+  CountVonCount* derivedCvcNotProperty_;
+  CountVonCount* derivedCvcNil_;
+  CountVonCount* derivedCvcCustom_;
+  int derivedInt_;
+  double derivedDouble_;
+  void* derivedPointer_;
+  NumberHolder derivedStruct_;
+
+  CountVonCount* protoCvcRetain_;
+  CountVonCount* protoCvcCopy_;
+  CountVonCount* protoCvcAssign_;
+  CountVonCount* protoCvcNil_;
+  CountVonCount* protoCvcCustom_;
+  int protoInt_;
+  double protoDouble_;
+  void* protoPointer_;
+  NumberHolder protoStruct_;
+
+  base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestDerived_;
+}
+
+@property(retain, nonatomic) CountVonCount* derivedCvcRetain;
+@property(copy, nonatomic) CountVonCount* derivedCvcCopy;
+@property(assign, nonatomic) CountVonCount* derivedCvcAssign;
+@property(retain, nonatomic) CountVonCount* derivedCvcNil;
+@property(retain, nonatomic, getter=derivedCustom, setter=setDerivedCustom:)
+    CountVonCount* derivedCvcCustom;
+@property(retain, nonatomic) CountVonCount* derivedCvcDynamic;
+@property(assign, nonatomic) int derivedInt;
+@property(assign, nonatomic) double derivedDouble;
+@property(assign, nonatomic) void* derivedPointer;
+@property(assign, nonatomic) NumberHolder derivedStruct;
+
+- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc;
+
+@end  // @interface ObjCPropertyTestDerived
+
+@implementation ObjCPropertyTestDerived
+
+@synthesize derivedCvcRetain = derivedCvcRetain_;
+@synthesize derivedCvcCopy = derivedCvcCopy_;
+@synthesize derivedCvcAssign = derivedCvcAssign_;
+@synthesize derivedCvcNil = derivedCvcNil_;
+@synthesize derivedCvcCustom = derivedCvcCustom_;
+@dynamic derivedCvcDynamic;
+@synthesize derivedInt = derivedInt_;
+@synthesize derivedDouble = derivedDouble_;
+@synthesize derivedPointer = derivedPointer_;
+@synthesize derivedStruct = derivedStruct_;
+
+@synthesize protoCvcRetain = protoCvcRetain_;
+@synthesize protoCvcCopy = protoCvcCopy_;
+@synthesize protoCvcAssign = protoCvcAssign_;
+@synthesize protoCvcNil = protoCvcNil_;
+@synthesize protoCvcCustom = protoCvcCustom_;
+@dynamic protoCvcDynamic;
+@synthesize protoInt = protoInt_;
+@synthesize protoDouble = protoDouble_;
+@synthesize protoPointer = protoPointer_;
+@synthesize protoStruct = protoStruct_;
+
+- (id)init {
+  if ((self = [super init])) {
+    propertyReleaser_ObjCPropertyTestDerived_.Init(
+        self, [ObjCPropertyTestDerived class]);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [derivedCvcNotProperty_ release];
+  [super dealloc];
+}
+
+- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc {
+  if (cvc != derivedCvcNotProperty_) {
+    [derivedCvcNotProperty_ release];
+    derivedCvcNotProperty_ = [cvc retain];
+  }
+}
+
+@end  // @implementation ObjCPropertyTestDerived
+
+namespace {
+
+TEST(ObjCPropertyReleaserTest, SesameStreet) {
+  ObjCPropertyTestDerived* test_object = [[ObjCPropertyTestDerived alloc] init];
+
+  // Assure a clean slate.
+  EXPECT_EQ(0, ah_ah_ah);
+  EXPECT_EQ(1U, [test_object retainCount]);
+
+  CountVonCount* baseAssign = [[CountVonCount alloc] init];
+  CountVonCount* derivedAssign = [[CountVonCount alloc] init];
+  CountVonCount* protoAssign = [[CountVonCount alloc] init];
+
+  // Make sure that worked before things get more involved.
+  EXPECT_EQ(3, ah_ah_ah);
+
+  {
+    base::mac::ScopedNSAutoreleasePool pool;
+
+    test_object.baseCvcRetain = [CountVonCount countVonCount];
+    test_object.baseCvcCopy = [CountVonCount countVonCount];
+    test_object.baseCvcAssign = baseAssign;
+    test_object.baseCvcCustom = [CountVonCount countVonCount];
+    [test_object setBaseCvcNotProperty:[CountVonCount countVonCount]];
+
+    // That added 4 objects, plus 1 more that was copied.
+    EXPECT_EQ(8, ah_ah_ah);
+
+    test_object.derivedCvcRetain = [CountVonCount countVonCount];
+    test_object.derivedCvcCopy = [CountVonCount countVonCount];
+    test_object.derivedCvcAssign = derivedAssign;
+    test_object.derivedCvcCustom = [CountVonCount countVonCount];
+    [test_object setDerivedCvcNotProperty:[CountVonCount countVonCount]];
+
+    // That added 4 objects, plus 1 more that was copied.
+    EXPECT_EQ(13, ah_ah_ah);
+
+    test_object.protoCvcRetain = [CountVonCount countVonCount];
+    test_object.protoCvcCopy = [CountVonCount countVonCount];
+    test_object.protoCvcAssign = protoAssign;
+    test_object.protoCvcCustom = [CountVonCount countVonCount];
+
+    // That added 3 objects, plus 1 more that was copied.
+    EXPECT_EQ(17, ah_ah_ah);
+  }
+
+  // Now that the autorelease pool has been popped, the 3 objects that were
+  // copied when placed into the test object will have been deallocated.
+  EXPECT_EQ(14, ah_ah_ah);
+
+  // Make sure that the setters work and have the expected semantics.
+  test_object.baseCvcRetain = nil;
+  test_object.baseCvcCopy = nil;
+  test_object.baseCvcAssign = nil;
+  test_object.baseCvcCustom = nil;
+  test_object.derivedCvcRetain = nil;
+  test_object.derivedCvcCopy = nil;
+  test_object.derivedCvcAssign = nil;
+  test_object.derivedCvcCustom = nil;
+  test_object.protoCvcRetain = nil;
+  test_object.protoCvcCopy = nil;
+  test_object.protoCvcAssign = nil;
+  test_object.protoCvcCustom = nil;
+
+  // The CountVonCounts marked "retain" and "copy" should have been
+  // deallocated. Those marked assign should not have been. The only ones that
+  // should exist now are the ones marked "assign" and the ones held in
+  // non-property instance variables.
+  EXPECT_EQ(5, ah_ah_ah);
+
+  {
+    base::mac::ScopedNSAutoreleasePool pool;
+
+    // Put things back to how they were.
+    test_object.baseCvcRetain = [CountVonCount countVonCount];
+    test_object.baseCvcCopy = [CountVonCount countVonCount];
+    test_object.baseCvcAssign = baseAssign;
+    test_object.baseCvcCustom = [CountVonCount countVonCount];
+    test_object.derivedCvcRetain = [CountVonCount countVonCount];
+    test_object.derivedCvcCopy = [CountVonCount countVonCount];
+    test_object.derivedCvcAssign = derivedAssign;
+    test_object.derivedCvcCustom = [CountVonCount countVonCount];
+    test_object.protoCvcRetain = [CountVonCount countVonCount];
+    test_object.protoCvcCopy = [CountVonCount countVonCount];
+    test_object.protoCvcAssign = protoAssign;
+    test_object.protoCvcCustom = [CountVonCount countVonCount];
+
+    // 9 more CountVonCounts, 3 of which were copied.
+    EXPECT_EQ(17, ah_ah_ah);
+  }
+
+  // Now that the autorelease pool has been popped, the 3 copies are gone.
+  EXPECT_EQ(14, ah_ah_ah);
+
+  // Releasing the test object should get rid of everything that it owns.
+  [test_object release];
+
+  // The property releaser should have released all of the CountVonCounts
+  // associated with properties marked "retain" or "copy". The -dealloc
+  // methods in each should have released the single non-property objects in
+  // each. Only the CountVonCounts assigned to the properties marked "assign"
+  // should remain.
+  EXPECT_EQ(3, ah_ah_ah);
+
+  [baseAssign release];
+  [derivedAssign release];
+  [protoAssign release];
+
+  // Zero! Zero counts! Ah, ah, ah.
+  EXPECT_EQ(0, ah_ah_ah);
+}
+
+}  // namespace
diff --git a/base/mac/os_crash_dumps.cc b/base/mac/os_crash_dumps.cc
new file mode 100644
index 0000000..e82fd73
--- /dev/null
+++ b/base/mac/os_crash_dumps.cc
@@ -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.
+
+#include "base/mac/os_crash_dumps.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+void ExitSignalHandler(int sig) {
+  // A call to exit() can call atexit() handlers.  If we SIGSEGV due
+  // to a corrupt heap, and if we have an atexit handler that
+  // allocates or frees memory, we are in trouble if we do not _exit.
+  _exit(128 + sig);
+}
+
+}  // namespace
+
+void DisableOSCrashDumps() {
+  // These are the POSIX signals corresponding to the Mach exceptions that
+  // Apple Crash Reporter handles.  See ux_exception() in xnu's
+  // bsd/uxkern/ux_exception.c and machine_exception() in xnu's
+  // bsd/dev/*/unix_signal.c.
+  const int signals_to_intercept[] = {
+    SIGILL,   // EXC_BAD_INSTRUCTION
+    SIGTRAP,  // EXC_BREAKPOINT
+    SIGFPE,   // EXC_ARITHMETIC
+    SIGBUS,   // EXC_BAD_ACCESS
+    SIGSEGV   // EXC_BAD_ACCESS
+  };
+
+  // For all these signals, just wire things up so we exit immediately.
+  for (size_t i = 0; i < arraysize(signals_to_intercept); ++i)
+    signal(signals_to_intercept[i], ExitSignalHandler);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/os_crash_dumps.h b/base/mac/os_crash_dumps.h
new file mode 100644
index 0000000..31d90fb
--- /dev/null
+++ b/base/mac/os_crash_dumps.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_OS_CRASH_DUMPS_H_
+#define BASE_MAC_OS_CRASH_DUMPS_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// On Mac OS X, it can take a really long time for the OS crash handler to
+// process a Chrome crash when debugging symbols are available.  This
+// translates into a long wait until the process actually dies.  This call
+// disables Apple Crash Reporter entirely.
+BASE_EXPORT void DisableOSCrashDumps();
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_OS_CRASH_DUMPS_H_
diff --git a/base/mac/scoped_aedesc.h b/base/mac/scoped_aedesc.h
new file mode 100644
index 0000000..a1323c0
--- /dev/null
+++ b/base/mac/scoped_aedesc.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_AEDESC_H_
+#define BASE_MAC_SCOPED_AEDESC_H_
+
+#import <CoreServices/CoreServices.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace mac {
+
+// The ScopedAEDesc is used to scope AppleEvent descriptors.  On creation,
+// it will store a NULL descriptor.  On destruction, it will dispose of the
+// descriptor.
+//
+// This class is parameterized for additional type safety checks.  You can use
+// the generic AEDesc type by not providing a template parameter:
+//  ScopedAEDesc<> desc;
+template <typename AEDescType = AEDesc>
+class ScopedAEDesc {
+ public:
+  ScopedAEDesc() {
+    AECreateDesc(typeNull, NULL, 0, &desc_);
+  }
+
+  ~ScopedAEDesc() {
+    AEDisposeDesc(&desc_);
+  }
+
+  // Used for in parameters.
+  operator const AEDescType*() {
+    return &desc_;
+  }
+
+  // Used for out parameters.
+  AEDescType* OutPointer() {
+    return &desc_;
+  }
+
+ private:
+  AEDescType desc_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedAEDesc);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_AEDESC_H_
diff --git a/base/mac/scoped_authorizationref.h b/base/mac/scoped_authorizationref.h
new file mode 100644
index 0000000..6413f2e
--- /dev/null
+++ b/base/mac/scoped_authorizationref.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_MAC_SCOPED_AUTHORIZATIONREF_H_
+#define BASE_MAC_SCOPED_AUTHORIZATIONREF_H_
+
+#include <Security/Authorization.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+// ScopedAuthorizationRef maintains ownership of an AuthorizationRef.  It is
+// patterned after the scoped_ptr interface.
+
+namespace base {
+namespace mac {
+
+class ScopedAuthorizationRef {
+ public:
+  explicit ScopedAuthorizationRef(AuthorizationRef authorization = NULL)
+      : authorization_(authorization) {
+  }
+
+  ~ScopedAuthorizationRef() {
+    if (authorization_) {
+      AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights);
+    }
+  }
+
+  void reset(AuthorizationRef authorization = NULL) {
+    if (authorization_ != authorization) {
+      if (authorization_) {
+        AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights);
+      }
+      authorization_ = authorization;
+    }
+  }
+
+  bool operator==(AuthorizationRef that) const {
+    return authorization_ == that;
+  }
+
+  bool operator!=(AuthorizationRef that) const {
+    return authorization_ != that;
+  }
+
+  operator AuthorizationRef() const {
+    return authorization_;
+  }
+
+  AuthorizationRef* operator&() {
+    return &authorization_;
+  }
+
+  AuthorizationRef get() const {
+    return authorization_;
+  }
+
+  void swap(ScopedAuthorizationRef& that) {
+    AuthorizationRef temp = that.authorization_;
+    that.authorization_ = authorization_;
+    authorization_ = temp;
+  }
+
+  // ScopedAuthorizationRef::release() is like scoped_ptr<>::release.  It is
+  // NOT a wrapper for AuthorizationFree().  To force a
+  // ScopedAuthorizationRef object to call AuthorizationFree(), use
+  // ScopedAuthorizationRef::reset().
+  AuthorizationRef release() WARN_UNUSED_RESULT {
+    AuthorizationRef temp = authorization_;
+    authorization_ = NULL;
+    return temp;
+  }
+
+ private:
+  AuthorizationRef authorization_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedAuthorizationRef);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_AUTHORIZATIONREF_H_
diff --git a/base/mac/scoped_cftyperef.h b/base/mac/scoped_cftyperef.h
new file mode 100644
index 0000000..c6ca46a
--- /dev/null
+++ b/base/mac/scoped_cftyperef.h
@@ -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.
+
+#ifndef BASE_MAC_SCOPED_CFTYPEREF_H_
+#define BASE_MAC_SCOPED_CFTYPEREF_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_policy.h"
+
+namespace base {
+namespace mac {
+
+// ScopedCFTypeRef<> is patterned after scoped_ptr<>, but maintains ownership
+// of a CoreFoundation object: any object that can be represented as a
+// CFTypeRef.  Style deviations here are solely for compatibility with
+// scoped_ptr<>'s interface, with which everyone is already familiar.
+//
+// By default, ScopedCFTypeRef<> takes ownership of an object (in the
+// constructor or in reset()) by taking over the caller's existing ownership
+// claim.  The caller must own the object it gives to ScopedCFTypeRef<>, and
+// relinquishes an ownership claim to that object.  ScopedCFTypeRef<> does not
+// call CFRetain(). This behavior is parameterized by the |OwnershipPolicy|
+// enum. If the value |RETAIN| is passed (in the constructor or in reset()),
+// then ScopedCFTypeRef<> will call CFRetain() on the object, and the initial
+// ownership is not changed.
+
+template<typename CFT>
+class ScopedCFTypeRef {
+ public:
+  typedef CFT element_type;
+
+  explicit ScopedCFTypeRef(
+      CFT object = NULL,
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : object_(object) {
+    if (object_ && policy == base::scoped_policy::RETAIN)
+      CFRetain(object_);
+  }
+
+  ScopedCFTypeRef(const ScopedCFTypeRef<CFT>& that)
+      : object_(that.object_) {
+    if (object_)
+      CFRetain(object_);
+  }
+
+  ~ScopedCFTypeRef() {
+    if (object_)
+      CFRelease(object_);
+  }
+
+  ScopedCFTypeRef& operator=(const ScopedCFTypeRef<CFT>& that) {
+    reset(that.get(), base::scoped_policy::RETAIN);
+    return *this;
+  }
+
+  void reset(CFT object = NULL,
+             base::scoped_policy::OwnershipPolicy policy =
+                base::scoped_policy::ASSUME) {
+    if (object && policy == base::scoped_policy::RETAIN)
+      CFRetain(object);
+    if (object_)
+      CFRelease(object_);
+    object_ = object;
+  }
+
+  bool operator==(CFT that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(CFT that) const {
+    return object_ != that;
+  }
+
+  operator CFT() const {
+    return object_;
+  }
+
+  CFT get() const {
+    return object_;
+  }
+
+  void swap(ScopedCFTypeRef& that) {
+    CFT temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  // ScopedCFTypeRef<>::release() is like scoped_ptr<>::release.  It is NOT
+  // a wrapper for CFRelease().  To force a ScopedCFTypeRef<> object to call
+  // CFRelease(), use ScopedCFTypeRef<>::reset().
+  CFT release() WARN_UNUSED_RESULT {
+    CFT temp = object_;
+    object_ = NULL;
+    return temp;
+  }
+
+ private:
+  CFT object_;
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_CFTYPEREF_H_
diff --git a/base/mac/scoped_ioobject.h b/base/mac/scoped_ioobject.h
new file mode 100644
index 0000000..854039b
--- /dev/null
+++ b/base/mac/scoped_ioobject.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_IOOBJECT_H_
+#define BASE_MAC_SCOPED_IOOBJECT_H_
+
+#include <IOKit/IOKitLib.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// Just like ScopedCFTypeRef but for io_object_t and subclasses.
+template<typename IOT>
+class ScopedIOObject {
+ public:
+  typedef IOT element_type;
+
+  explicit ScopedIOObject(IOT object = IO_OBJECT_NULL)
+      : object_(object) {
+  }
+
+  ~ScopedIOObject() {
+    if (object_)
+      IOObjectRelease(object_);
+  }
+
+  void reset(IOT object = IO_OBJECT_NULL) {
+    if (object_)
+      IOObjectRelease(object_);
+    object_ = object;
+  }
+
+  bool operator==(IOT that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(IOT that) const {
+    return object_ != that;
+  }
+
+  operator IOT() const {
+    return object_;
+  }
+
+  IOT get() const {
+    return object_;
+  }
+
+  void swap(ScopedIOObject& that) {
+    IOT temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  IOT release() WARN_UNUSED_RESULT {
+    IOT temp = object_;
+    object_ = IO_OBJECT_NULL;
+    return temp;
+  }
+
+ private:
+  IOT object_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedIOObject);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_IOOBJECT_H_
diff --git a/base/mac/scoped_launch_data.h b/base/mac/scoped_launch_data.h
new file mode 100644
index 0000000..e4343b8
--- /dev/null
+++ b/base/mac/scoped_launch_data.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_LAUNCH_DATA_H_
+#define BASE_MAC_SCOPED_LAUNCH_DATA_H_
+
+#include <launch.h>
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// Just like scoped_ptr<> but for launch_data_t.
+class ScopedLaunchData {
+ public:
+  typedef launch_data_t element_type;
+
+  explicit ScopedLaunchData(launch_data_t object = NULL)
+      : object_(object) {
+  }
+
+  ~ScopedLaunchData() {
+    if (object_)
+      launch_data_free(object_);
+  }
+
+  void reset(launch_data_t object = NULL) {
+    if (object != object_) {
+      if (object_)
+        launch_data_free(object_);
+      object_ = object;
+    }
+  }
+
+  bool operator==(launch_data_t that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(launch_data_t that) const {
+    return object_ != that;
+  }
+
+  operator launch_data_t() const {
+    return object_;
+  }
+
+  launch_data_t get() const {
+    return object_;
+  }
+
+  void swap(ScopedLaunchData& that) {
+    std::swap(object_, that.object_);
+  }
+
+  launch_data_t release() WARN_UNUSED_RESULT {
+    launch_data_t temp = object_;
+    object_ = NULL;
+    return temp;
+  }
+
+ private:
+  launch_data_t object_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedLaunchData);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_LAUNCH_DATA_H_
diff --git a/base/mac/scoped_mach_port.cc b/base/mac/scoped_mach_port.cc
new file mode 100644
index 0000000..652e3f4
--- /dev/null
+++ b/base/mac/scoped_mach_port.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All 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"
+
+namespace base {
+namespace mac {
+
+ScopedMachPort::ScopedMachPort(mach_port_t port) : port_(port) {
+}
+
+ScopedMachPort::~ScopedMachPort() {
+  if (port_ != MACH_PORT_NULL) {
+    mach_port_deallocate(mach_task_self(), port_);
+  }
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_mach_port.h b/base/mac/scoped_mach_port.h
new file mode 100644
index 0000000..d2aa2f7
--- /dev/null
+++ b/base/mac/scoped_mach_port.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_MAC_SCOPED_MACH_PORT_H_
+#define BASE_MAC_SCOPED_MACH_PORT_H_
+
+#include <mach/mach.h>
+
+#include "base/basictypes.h"
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// A class for managing the life of a Mach port, releasing via
+// mach_port_deallocate either its send and/or receive rights.
+class BASE_EXPORT ScopedMachPort {
+ public:
+  // Creates a scoper by taking ownership of the port.
+  explicit ScopedMachPort(mach_port_t port);
+
+  ~ScopedMachPort();
+
+  operator mach_port_t() const {
+    return port_;
+  }
+
+  mach_port_t get() const {
+    return port_;
+  }
+
+ private:
+  mach_port_t port_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedMachPort);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_MACH_PORT_H_
diff --git a/base/mac/scoped_nsautorelease_pool.h b/base/mac/scoped_nsautorelease_pool.h
new file mode 100644
index 0000000..60af71a
--- /dev/null
+++ b/base/mac/scoped_nsautorelease_pool.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_
+#define BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(__OBJC__)
+@class NSAutoreleasePool;
+#else  // __OBJC__
+class NSAutoreleasePool;
+#endif  // __OBJC__
+
+namespace base {
+namespace mac {
+
+// ScopedNSAutoreleasePool allocates an NSAutoreleasePool when instantiated and
+// sends it a -drain message when destroyed.  This allows an autorelease pool to
+// be maintained in ordinary C++ code without bringing in any direct Objective-C
+// dependency.
+
+class BASE_EXPORT ScopedNSAutoreleasePool {
+ public:
+  ScopedNSAutoreleasePool();
+  ~ScopedNSAutoreleasePool();
+
+  // Clear out the pool in case its position on the stack causes it to be
+  // alive for long periods of time (such as the entire length of the app).
+  // Only use then when you're certain the items currently in the pool are
+  // no longer needed.
+  void Recycle();
+ private:
+  NSAutoreleasePool* autorelease_pool_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedNSAutoreleasePool);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_
diff --git a/base/mac/scoped_nsautorelease_pool.mm b/base/mac/scoped_nsautorelease_pool.mm
new file mode 100644
index 0000000..e542ca8
--- /dev/null
+++ b/base/mac/scoped_nsautorelease_pool.mm
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+ScopedNSAutoreleasePool::ScopedNSAutoreleasePool()
+    : autorelease_pool_([[NSAutoreleasePool alloc] init]) {
+  DCHECK(autorelease_pool_);
+}
+
+ScopedNSAutoreleasePool::~ScopedNSAutoreleasePool() {
+  [autorelease_pool_ drain];
+}
+
+// Cycle the internal pool, allowing everything there to get cleaned up and
+// start anew.
+void ScopedNSAutoreleasePool::Recycle() {
+  [autorelease_pool_ drain];
+  autorelease_pool_ = [[NSAutoreleasePool alloc] init];
+  DCHECK(autorelease_pool_);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_nsexception_enabler.h b/base/mac/scoped_nsexception_enabler.h
new file mode 100644
index 0000000..e1d0b3c
--- /dev/null
+++ b/base/mac/scoped_nsexception_enabler.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_
+#define BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_
+
+#import <Foundation/Foundation.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace mac {
+
+// BrowserCrApplication attempts to restrict throwing of NSExceptions
+// because they interact badly with C++ scoping rules.  Unfortunately,
+// there are some cases where exceptions must be supported, such as
+// when third-party printer drivers are used.  These helpers can be
+// used to enable exceptions for narrow windows.
+
+// Make it easy to safely allow NSException to be thrown in a limited
+// scope.  Note that if an exception is thrown, then this object will
+// not be appropriately destructed!  If the exception ends up in the
+// top-level event loop, things are cleared in -reportException:.  If
+// the exception is caught at a lower level, a higher level scoper
+// should eventually reset things.
+class BASE_EXPORT ScopedNSExceptionEnabler {
+ public:
+  ScopedNSExceptionEnabler();
+  ~ScopedNSExceptionEnabler();
+
+ private:
+  bool was_enabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedNSExceptionEnabler);
+};
+
+// Access the exception setting for the current thread.  This is for
+// the support code in BrowserCrApplication, other code should use
+// the scoper.
+BASE_EXPORT bool GetNSExceptionsAllowed();
+BASE_EXPORT void SetNSExceptionsAllowed(bool allowed);
+
+// Executes [target performSelector:sel] with fatal-exceptions turned
+// off, and returns the result.  If an exception is thrown during the
+// perform, nil is returned.
+BASE_EXPORT id PerformSelectorIgnoringExceptions(NSObject* target, SEL sel);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_
diff --git a/base/mac/scoped_nsexception_enabler.mm b/base/mac/scoped_nsexception_enabler.mm
new file mode 100644
index 0000000..9898789
--- /dev/null
+++ b/base/mac/scoped_nsexception_enabler.mm
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/scoped_nsexception_enabler.h"
+
+#import "base/lazy_instance.h"
+#import "base/threading/thread_local.h"
+
+// To make the |g_exceptionsAllowed| declaration readable.
+using base::LazyInstance;
+using base::ThreadLocalBoolean;
+
+// When C++ exceptions are disabled, the C++ library defines |try| and
+// |catch| so as to allow exception-expecting C++ code to build properly when
+// language support for exceptions is not present.  These macros interfere
+// with the use of |@try| and |@catch| in Objective-C files such as this one.
+// Undefine these macros here, after everything has been #included, since
+// there will be no C++ uses and only Objective-C uses from this point on.
+#undef try
+#undef catch
+
+namespace {
+
+// Whether to allow NSExceptions to be raised on the current thread.
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_exceptionsAllowed = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+namespace mac {
+
+bool GetNSExceptionsAllowed() {
+  return g_exceptionsAllowed.Get().Get();
+}
+
+void SetNSExceptionsAllowed(bool allowed) {
+  return g_exceptionsAllowed.Get().Set(allowed);
+}
+
+id PerformSelectorIgnoringExceptions(NSObject* target, SEL sel) {
+  id ret = nil;
+  @try {
+    base::mac::ScopedNSExceptionEnabler enable;
+    ret = [target performSelector:sel];
+  }
+  @catch(id exception) {
+  }
+  return ret;
+}
+
+ScopedNSExceptionEnabler::ScopedNSExceptionEnabler() {
+  was_enabled_ = GetNSExceptionsAllowed();
+  SetNSExceptionsAllowed(true);
+}
+
+ScopedNSExceptionEnabler::~ScopedNSExceptionEnabler() {
+  SetNSExceptionsAllowed(was_enabled_);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_sending_event.h b/base/mac/scoped_sending_event.h
new file mode 100644
index 0000000..f7637bb
--- /dev/null
+++ b/base/mac/scoped_sending_event.h
@@ -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.
+
+#ifndef BASE_MAC_SCOPED_SENDING_EVENT_H_
+#define BASE_MAC_SCOPED_SENDING_EVENT_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_nsobject.h"
+#include "base/message_pump_mac.h"
+
+// Nested event loops can pump IPC messages, including
+// script-initiated tab closes, which could release objects that the
+// nested event loop might message.  CrAppProtocol defines how to ask
+// the embedding NSApplication subclass if an event is currently being
+// handled, in which case such closes are deferred to the top-level
+// event loop.
+//
+// ScopedSendingEvent allows script-initiated event loops to work like
+// a nested event loop, as such events do not arrive via -sendEvent:.
+// CrAppControlProtocol lets ScopedSendingEvent tell the embedding
+// NSApplication what to return from -handlingSendEvent.
+
+@protocol CrAppControlProtocol<CrAppProtocol>
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
+@end
+
+namespace base {
+namespace mac {
+
+class BASE_EXPORT ScopedSendingEvent {
+ public:
+  ScopedSendingEvent();
+  ~ScopedSendingEvent();
+
+ private:
+  // The NSApp in control at the time the constructor was run, to be
+  // sure the |handling_| setting is restored appropriately.
+  NSObject<CrAppControlProtocol>* app_;
+  BOOL handling_;  // Value of -[app_ handlingSendEvent] at construction.
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSendingEvent);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_SENDING_EVENT_H_
diff --git a/base/mac/scoped_sending_event.mm b/base/mac/scoped_sending_event.mm
new file mode 100644
index 0000000..c3813d8
--- /dev/null
+++ b/base/mac/scoped_sending_event.mm
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/scoped_sending_event.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+ScopedSendingEvent::ScopedSendingEvent()
+    : app_(static_cast<NSObject<CrAppControlProtocol>*>(NSApp)) {
+  DCHECK([app_ conformsToProtocol:@protocol(CrAppControlProtocol)]);
+  handling_ = [app_ isHandlingSendEvent];
+  [app_ setHandlingSendEvent:YES];
+}
+
+ScopedSendingEvent::~ScopedSendingEvent() {
+  [app_ setHandlingSendEvent:handling_];
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_sending_event_unittest.mm b/base/mac/scoped_sending_event_unittest.mm
new file mode 100644
index 0000000..9ae9985
--- /dev/null
+++ b/base/mac/scoped_sending_event_unittest.mm
@@ -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.
+
+#import "base/mac/scoped_sending_event.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Sets the flag within scope, resets when leaving scope.
+TEST(ScopedSendingEventTest, SetHandlingSendEvent) {
+  id<CrAppProtocol> app = NSApp;
+  EXPECT_FALSE([app isHandlingSendEvent]);
+  {
+    base::mac::ScopedSendingEvent is_handling_send_event;
+    EXPECT_TRUE([app isHandlingSendEvent]);
+  }
+  EXPECT_FALSE([app isHandlingSendEvent]);
+}
+
+// Nested call restores previous value rather than resetting flag.
+TEST(ScopedSendingEventTest, NestedSetHandlingSendEvent) {
+  id<CrAppProtocol> app = NSApp;
+  EXPECT_FALSE([app isHandlingSendEvent]);
+  {
+    base::mac::ScopedSendingEvent is_handling_send_event;
+    EXPECT_TRUE([app isHandlingSendEvent]);
+    {
+      base::mac::ScopedSendingEvent nested_is_handling_send_event;
+      EXPECT_TRUE([app isHandlingSendEvent]);
+    }
+    EXPECT_TRUE([app isHandlingSendEvent]);
+  }
+  EXPECT_FALSE([app isHandlingSendEvent]);
+}
+
+}  // namespace
diff --git a/base/mach_ipc_mac.h b/base/mach_ipc_mac.h
new file mode 100644
index 0000000..1730d37
--- /dev/null
+++ b/base/mach_ipc_mac.h
@@ -0,0 +1,326 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MACH_IPC_MAC_H_
+#define BASE_MACH_IPC_MAC_H_
+
+#include <mach/mach.h>
+#include <mach/message.h>
+#include <servers/bootstrap.h>
+#include <sys/types.h>
+
+#include <CoreServices/CoreServices.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+//==============================================================================
+// DISCUSSION:
+//
+// The three main classes of interest are
+//
+//  MachMessage:    a wrapper for a Mach message of the following form
+//   mach_msg_header_t
+//   mach_msg_body_t
+//   optional descriptors
+//   optional extra message data
+//
+//  MachReceiveMessage and MachSendMessage subclass MachMessage
+//    and are used instead of MachMessage which is an abstract base class
+//
+//  ReceivePort:
+//    Represents a Mach port for which we have receive rights
+//
+//  MachPortSender:
+//    Represents a Mach port for which we have send rights
+//
+// Here's an example to receive a message on a server port:
+//
+//        // This creates our named server port
+//        ReceivePort receivePort("com.Google.MyService");
+//
+//        MachReceiveMessage message;
+//        kern_return_t result = receivePort.WaitForMessage(&message, 0);
+//
+//        if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
+//          mach_port_t task = message.GetTranslatedPort(0);
+//          mach_port_t thread = message.GetTranslatedPort(1);
+//
+//          char *messageString = message.GetData();
+//
+//          printf("message string = %s\n", messageString);
+//        }
+//
+// Here is an example of using these classes to send a message to this port:
+//
+//    // send to already named port
+//    MachPortSender sender("com.Google.MyService");
+//    MachSendMessage message(57);      // our message ID is 57
+//
+//    // add some ports to be translated for us
+//    message.AddDescriptor(mach_task_self());     // our task
+//    message.AddDescriptor(mach_thread_self());   // this thread
+//
+//    char messageString[] = "Hello server!\n";
+//    message.SetData(messageString, strlen(messageString)+1);
+//    // timeout 1000ms
+//    kern_return_t result = sender.SendMessage(message, 1000);
+//
+
+#define PRINT_MACH_RESULT(result_, message_) \
+  printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
+
+namespace base {
+
+//==============================================================================
+// A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
+// with convenient constructors and accessors
+class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
+ public:
+  // General-purpose constructor
+  MachMsgPortDescriptor(mach_port_t in_name,
+                        mach_msg_type_name_t in_disposition) {
+    name = in_name;
+    pad1 = 0;
+    pad2 = 0;
+    disposition = in_disposition;
+    type = MACH_MSG_PORT_DESCRIPTOR;
+  }
+
+  // For passing send rights to a port
+  MachMsgPortDescriptor(mach_port_t in_name) {
+    name = in_name;
+    pad1 = 0;
+    pad2 = 0;
+    disposition = MACH_MSG_TYPE_PORT_SEND;
+    type = MACH_MSG_PORT_DESCRIPTOR;
+  }
+
+  // Copy constructor
+  MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
+    name = desc.name;
+    pad1 = desc.pad1;
+    pad2 = desc.pad2;
+    disposition = desc.disposition;
+    type = desc.type;
+  }
+
+  mach_port_t GetMachPort() const {
+    return name;
+  }
+
+  mach_msg_type_name_t GetDisposition() const {
+    return disposition;
+  }
+
+  // For convenience
+  operator mach_port_t() const {
+    return GetMachPort();
+  }
+};
+
+//==============================================================================
+// MachMessage: a wrapper for a Mach message
+//  (mach_msg_header_t, mach_msg_body_t, extra data)
+//
+//  This considerably simplifies the construction of a message for sending
+//  and the getting at relevant data and descriptors for the receiver.
+//
+//  This class can be initialized using external storage of an arbitrary size
+//  or it can manage storage internally.
+//  1. If storage is allocated internally, the combined size of the descriptors
+//  plus data must be less than 1024.  But as a benefit no memory allocation is
+//  necessary.
+//  2. For external storage, a buffer of at least EmptyMessageSize() must be
+//  provided.
+//
+//  A MachMessage object is used by ReceivePort::WaitForMessage
+//  and MachPortSender::SendMessage
+//
+class BASE_EXPORT MachMessage {
+ public:
+  static const size_t kEmptyMessageSize;
+
+  virtual ~MachMessage();
+
+  // The receiver of the message can retrieve the raw data this way
+  u_int8_t *GetData() {
+    return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
+  }
+
+  u_int32_t GetDataLength() {
+    return EndianU32_LtoN(GetDataPacket()->data_length);
+  }
+
+  // The message ID may be used as a code identifying the type of message
+  void SetMessageID(int32_t message_id) {
+    GetDataPacket()->id = EndianU32_NtoL(message_id);
+  }
+
+  int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
+
+  // Adds a descriptor (typically a Mach port) to be translated
+  // returns true if successful, otherwise not enough space
+  bool AddDescriptor(const MachMsgPortDescriptor &desc);
+
+  int GetDescriptorCount() const {
+    return storage_->body.msgh_descriptor_count;
+  }
+
+  MachMsgPortDescriptor *GetDescriptor(int n);
+
+  // Convenience method which gets the Mach port described by the descriptor
+  mach_port_t GetTranslatedPort(int n);
+
+  // A simple message is one with no descriptors
+  bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
+
+  // Sets raw data for the message (returns false if not enough space)
+  bool SetData(const void* data, int32_t data_length);
+
+ protected:
+  // Consider this an abstract base class - must create an actual instance
+  // of MachReceiveMessage or MachSendMessage
+  MachMessage();
+
+  // Constructor for use with preallocate storage.
+  // storage_length must be >= EmptyMessageSize()
+  MachMessage(void *storage, size_t storage_length);
+
+  friend class ReceivePort;
+  friend class MachPortSender;
+
+  // Represents raw data in our message
+  struct MessageDataPacket {
+    int32_t  id;          // little-endian
+    int32_t  data_length; // little-endian
+    u_int8_t data[1];     // actual size limited by storage_length_bytes_
+  };
+
+  MessageDataPacket* GetDataPacket();
+
+  void SetDescriptorCount(int n);
+  void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
+
+  // Returns total message size setting msgh_size in the header to this value
+  int CalculateSize();
+
+  // Returns total storage size that this object can grow to, this is inclusive
+  // of the Mach header.
+  size_t MaxSize() const { return storage_length_bytes_; }
+
+  mach_msg_header_t *Head() { return &(storage_->head); }
+
+ private:
+  struct MachMessageData {
+    mach_msg_header_t  head;
+    mach_msg_body_t    body;
+    // descriptors and data may be embedded here.
+    u_int8_t           padding[1024];
+  };
+
+  MachMessageData *storage_;
+  size_t storage_length_bytes_;
+  bool own_storage_;  // Is storage owned by this object?
+};
+
+//==============================================================================
+// MachReceiveMessage and MachSendMessage are useful to separate the idea
+// of a Mach message being sent and being received, and adds increased type
+// safety:
+//  ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
+//  MachPortSender::SendMessage() only accepts a MachSendMessage
+
+//==============================================================================
+class MachReceiveMessage : public MachMessage {
+ public:
+  MachReceiveMessage() : MachMessage() {}
+  MachReceiveMessage(void *storage, size_t storage_length)
+      : MachMessage(storage, storage_length) {}
+
+ private:
+    DISALLOW_COPY_AND_ASSIGN(MachReceiveMessage);
+};
+
+//==============================================================================
+class BASE_EXPORT MachSendMessage : public MachMessage {
+ public:
+  explicit MachSendMessage(int32_t message_id);
+  MachSendMessage(void *storage, size_t storage_length, int32_t message_id);
+
+ private:
+  void Initialize(int32_t message_id);
+
+  DISALLOW_COPY_AND_ASSIGN(MachSendMessage);
+};
+
+//==============================================================================
+// Represents a Mach port for which we have receive rights
+class BASE_EXPORT ReceivePort {
+ public:
+  // Creates a new Mach port for receiving messages and registers a name for it
+  explicit ReceivePort(const char *receive_port_name);
+
+  // Given an already existing Mach port, use it.  We take ownership of the
+  // port and deallocate it in our destructor.
+  explicit ReceivePort(mach_port_t receive_port);
+
+  // Create a new Mach port for receiving messages
+  ReceivePort();
+
+  ~ReceivePort();
+
+  // Waits on the Mach port until message received or timeout.  If |timeout| is
+  // MACH_MSG_TIMEOUT_NONE, this method waits forever.
+  kern_return_t WaitForMessage(MachReceiveMessage *out_message,
+                               mach_msg_timeout_t timeout);
+
+  // The underlying Mach port that we wrap
+  mach_port_t  GetPort() const { return port_; }
+
+ private:
+  mach_port_t   port_;
+  kern_return_t init_result_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReceivePort);
+};
+
+//==============================================================================
+// Represents a Mach port for which we have send rights
+class BASE_EXPORT MachPortSender {
+ public:
+  // get a port with send rights corresponding to a named registered service
+  explicit MachPortSender(const char *receive_port_name);
+
+
+  // Given an already existing Mach port, use it. Does not take ownership of
+  // |send_port|.
+  explicit MachPortSender(mach_port_t send_port);
+
+  kern_return_t SendMessage(MachSendMessage &message,
+                            mach_msg_timeout_t timeout);
+
+ private:
+  mach_port_t   send_port_;
+  kern_return_t init_result_;
+
+  DISALLOW_COPY_AND_ASSIGN(MachPortSender);
+};
+
+//==============================================================================
+// Static utility functions.
+
+namespace mac {
+
+// Returns the number of Mach ports to which the given task has a right.
+// Note that unless the calling task has send rights to the passed task port,
+// this will fail unless the calling task is running as root.
+kern_return_t BASE_EXPORT GetNumberOfMachPorts(mach_port_t task_port,
+                                               int* port_count);
+
+}  // namespace mac
+
+}  // namespace base
+
+#endif // BASE_MACH_IPC_MAC_H_
diff --git a/base/mach_ipc_mac.mm b/base/mach_ipc_mac.mm
new file mode 100644
index 0000000..3d45dd7
--- /dev/null
+++ b/base/mach_ipc_mac.mm
@@ -0,0 +1,358 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mach_ipc_mac.h"
+
+#import <Foundation/Foundation.h>
+#include <mach/vm_map.h>
+
+#include <stdio.h>
+#include "base/logging.h"
+
+namespace base {
+
+// static
+const size_t MachMessage::kEmptyMessageSize = sizeof(mach_msg_header_t) +
+    sizeof(mach_msg_body_t) + sizeof(MessageDataPacket);
+
+//==============================================================================
+MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
+  Initialize(message_id);
+}
+
+MachSendMessage::MachSendMessage(void *storage, size_t storage_length,
+                                 int32_t message_id)
+    : MachMessage(storage, storage_length) {
+  Initialize(message_id);
+}
+
+void MachSendMessage::Initialize(int32_t message_id) {
+  Head()->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
+
+  // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
+  Head()->msgh_local_port = MACH_PORT_NULL;
+  Head()->msgh_reserved = 0;
+  Head()->msgh_id = 0;
+
+  SetDescriptorCount(0);  // start out with no descriptors
+
+  SetMessageID(message_id);
+  SetData(NULL, 0);       // client may add data later
+}
+
+//==============================================================================
+MachMessage::MachMessage()
+    : storage_(new MachMessageData),  // Allocate storage_ ourselves
+      storage_length_bytes_(sizeof(MachMessageData)),
+      own_storage_(true) {
+  memset(storage_, 0, storage_length_bytes_);
+}
+
+//==============================================================================
+MachMessage::MachMessage(void *storage, size_t storage_length)
+    : storage_(static_cast<MachMessageData*>(storage)),
+      storage_length_bytes_(storage_length),
+      own_storage_(false) {
+  DCHECK(storage);
+  DCHECK_GE(storage_length, kEmptyMessageSize);
+}
+
+//==============================================================================
+MachMessage::~MachMessage() {
+  if (own_storage_) {
+    delete storage_;
+    storage_ = NULL;
+  }
+}
+
+//==============================================================================
+// returns true if successful
+bool MachMessage::SetData(const void* data,
+                          int32_t data_length) {
+  // Enforce the fact that it's only safe to call this method once on a
+  // message.
+  DCHECK(GetDataPacket()->data_length == 0);
+
+  // first check to make sure we have enough space
+  int size = CalculateSize();
+  int new_size = size + data_length;
+
+  if ((unsigned)new_size > storage_length_bytes_) {
+    return false;  // not enough space
+  }
+
+  GetDataPacket()->data_length = EndianU32_NtoL(data_length);
+  if (data) memcpy(GetDataPacket()->data, data, data_length);
+
+  // Update the Mach header with the new aligned size of the message.
+  CalculateSize();
+
+  return true;
+}
+
+//==============================================================================
+// calculates and returns the total size of the message
+// Currently, the entire message MUST fit inside of the MachMessage
+//    messsage size <= EmptyMessageSize()
+int MachMessage::CalculateSize() {
+  int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
+
+  // add space for MessageDataPacket
+  int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
+  size += 2*sizeof(int32_t) + alignedDataLength;
+
+  // add space for descriptors
+  size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
+
+  Head()->msgh_size = size;
+
+  return size;
+}
+
+//==============================================================================
+MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
+  int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
+  MessageDataPacket *packet =
+    reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size);
+
+  return packet;
+}
+
+//==============================================================================
+void MachMessage::SetDescriptor(int n,
+                                const MachMsgPortDescriptor &desc) {
+  MachMsgPortDescriptor *desc_array =
+    reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
+  desc_array[n] = desc;
+}
+
+//==============================================================================
+// returns true if successful otherwise there was not enough space
+bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
+  // first check to make sure we have enough space
+  int size = CalculateSize();
+  int new_size = size + sizeof(MachMsgPortDescriptor);
+
+  if ((unsigned)new_size > storage_length_bytes_) {
+    return false;  // not enough space
+  }
+
+  // unfortunately, we need to move the data to allow space for the
+  // new descriptor
+  u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
+  bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
+
+  SetDescriptor(GetDescriptorCount(), desc);
+  SetDescriptorCount(GetDescriptorCount() + 1);
+
+  CalculateSize();
+
+  return true;
+}
+
+//==============================================================================
+void MachMessage::SetDescriptorCount(int n) {
+  storage_->body.msgh_descriptor_count = n;
+
+  if (n > 0) {
+    Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
+  } else {
+    Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
+  }
+}
+
+//==============================================================================
+MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
+  if (n < GetDescriptorCount()) {
+    MachMsgPortDescriptor *desc =
+        reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
+    return desc + n;
+  }
+
+  return nil;
+}
+
+//==============================================================================
+mach_port_t MachMessage::GetTranslatedPort(int n) {
+  if (n < GetDescriptorCount()) {
+    return GetDescriptor(n)->GetMachPort();
+  }
+  return MACH_PORT_NULL;
+}
+
+#pragma mark -
+
+//==============================================================================
+// create a new mach port for receiving messages and register a name for it
+ReceivePort::ReceivePort(const char *receive_port_name) {
+  mach_port_t current_task = mach_task_self();
+
+  init_result_ = mach_port_allocate(current_task,
+                                    MACH_PORT_RIGHT_RECEIVE,
+                                    &port_);
+
+  if (init_result_ != KERN_SUCCESS)
+    return;
+
+  init_result_ = mach_port_insert_right(current_task,
+                                        port_,
+                                        port_,
+                                        MACH_MSG_TYPE_MAKE_SEND);
+
+  if (init_result_ != KERN_SUCCESS)
+    return;
+
+  // Without |NSMachPortDeallocateNone|, the NSMachPort seems to deallocate
+  // receive rights on port when it is eventually released.  It is not necessary
+  // to deallocate any rights here as |port_| is fully deallocated in the
+  // ReceivePort destructor.
+  NSPort *ns_port = [NSMachPort portWithMachPort:port_
+                                         options:NSMachPortDeallocateNone];
+  NSString *port_name = [NSString stringWithUTF8String:receive_port_name];
+  [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name];
+}
+
+//==============================================================================
+// create a new mach port for receiving messages
+ReceivePort::ReceivePort() {
+  mach_port_t current_task = mach_task_self();
+
+  init_result_ = mach_port_allocate(current_task,
+                                    MACH_PORT_RIGHT_RECEIVE,
+                                    &port_);
+
+  if (init_result_ != KERN_SUCCESS)
+    return;
+
+  init_result_ = mach_port_insert_right(current_task,
+                                        port_,
+                                        port_,
+                                        MACH_MSG_TYPE_MAKE_SEND);
+}
+
+//==============================================================================
+// Given an already existing mach port, use it.  We take ownership of the
+// port and deallocate it in our destructor.
+ReceivePort::ReceivePort(mach_port_t receive_port)
+  : port_(receive_port),
+    init_result_(KERN_SUCCESS) {
+}
+
+//==============================================================================
+ReceivePort::~ReceivePort() {
+  if (init_result_ == KERN_SUCCESS)
+    mach_port_deallocate(mach_task_self(), port_);
+}
+
+//==============================================================================
+kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
+                                          mach_msg_timeout_t timeout) {
+  if (!out_message) {
+    return KERN_INVALID_ARGUMENT;
+  }
+
+  // return any error condition encountered in constructor
+  if (init_result_ != KERN_SUCCESS)
+    return init_result_;
+
+  out_message->Head()->msgh_bits = 0;
+  out_message->Head()->msgh_local_port = port_;
+  out_message->Head()->msgh_remote_port = MACH_PORT_NULL;
+  out_message->Head()->msgh_reserved = 0;
+  out_message->Head()->msgh_id = 0;
+
+  mach_msg_option_t rcv_options = MACH_RCV_MSG;
+  if (timeout != MACH_MSG_TIMEOUT_NONE)
+    rcv_options |= MACH_RCV_TIMEOUT;
+
+  kern_return_t result = mach_msg(out_message->Head(),
+                                  rcv_options,
+                                  0,
+                                  out_message->MaxSize(),
+                                  port_,
+                                  timeout,              // timeout in ms
+                                  MACH_PORT_NULL);
+
+  return result;
+}
+
+#pragma mark -
+
+//==============================================================================
+// get a port with send rights corresponding to a named registered service
+MachPortSender::MachPortSender(const char *receive_port_name) {
+  mach_port_t bootstrap_port = 0;
+  init_result_ = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
+
+  if (init_result_ != KERN_SUCCESS)
+    return;
+
+  init_result_ = bootstrap_look_up(bootstrap_port,
+                    const_cast<char*>(receive_port_name),
+                    &send_port_);
+}
+
+//==============================================================================
+MachPortSender::MachPortSender(mach_port_t send_port)
+  : send_port_(send_port),
+    init_result_(KERN_SUCCESS) {
+}
+
+//==============================================================================
+kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
+                                          mach_msg_timeout_t timeout) {
+  if (message.Head()->msgh_size == 0) {
+    NOTREACHED();
+    return KERN_INVALID_VALUE;    // just for safety -- never should occur
+  };
+
+  if (init_result_ != KERN_SUCCESS)
+    return init_result_;
+
+  message.Head()->msgh_remote_port = send_port_;
+
+  kern_return_t result = mach_msg(message.Head(),
+                                  MACH_SEND_MSG | MACH_SEND_TIMEOUT,
+                                  message.Head()->msgh_size,
+                                  0,
+                                  MACH_PORT_NULL,
+                                  timeout,              // timeout in ms
+                                  MACH_PORT_NULL);
+
+  return result;
+}
+
+//==============================================================================
+
+namespace mac {
+
+kern_return_t GetNumberOfMachPorts(mach_port_t task_port, int* num_ports) {
+  mach_port_name_array_t names;
+  mach_msg_type_number_t names_count;
+  mach_port_type_array_t types;
+  mach_msg_type_number_t types_count;
+
+  // A friendlier interface would allow NULL buffers to only get the counts.
+  kern_return_t kr = mach_port_names(task_port, &names, &names_count,
+                                     &types, &types_count);
+  if (kr != KERN_SUCCESS)
+    return kr;
+
+  // The documentation states this is an invariant.
+  DCHECK_EQ(names_count, types_count);
+  *num_ports = names_count;
+
+  kr = vm_deallocate(mach_task_self(),
+      reinterpret_cast<vm_address_t>(names),
+      names_count * sizeof(mach_port_name_array_t));
+  kr = vm_deallocate(mach_task_self(),
+      reinterpret_cast<vm_address_t>(types),
+      types_count * sizeof(mach_port_type_array_t));
+
+  return kr;
+}
+
+}  // namespace mac
+
+}  // namespace base
diff --git a/base/md5.cc b/base/md5.cc
new file mode 100644
index 0000000..754994c
--- /dev/null
+++ b/base/md5.cc
@@ -0,0 +1,292 @@
+// Copyright (c) 2011 The Chromium 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 "base/basictypes.h"
+
+namespace {
+
+struct Context {
+  uint32 buf[4];
+  uint32 bits[2];
+  unsigned char in[64];
+};
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs) {
+        uint32 t;
+        do {
+                t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
+                            ((unsigned)buf[1]<<8 | buf[0]);
+                *(uint32 *)buf = t;
+                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 buf[4], const uint32 in[16]) {
+        register uint32 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 = (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) {
+        const unsigned char* inbuf = (const unsigned char*)data.data();
+        size_t len = data.size();
+        struct Context *ctx = (struct Context *)context;
+        const unsigned char* buf = (const unsigned char*)inbuf;
+        uint32 t;
+
+        /* Update bitcount */
+
+        t = ctx->bits[0];
+        if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
+                ctx->bits[1]++; /* Carry from low to high */
+        ctx->bits[1] += static_cast<uint32>(len >> 29);
+
+        t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
+
+        /* Handle any leading odd-sized chunks */
+
+        if (t) {
+                unsigned char *p = (unsigned char *)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, (uint32 *)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, (uint32 *)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 = (struct Context *)context;
+        unsigned count;
+        unsigned char *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, (uint32 *)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 */
+        ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
+        ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
+
+        MD5Transform(ctx->buf, (uint32 *)ctx->in);
+        byteReverse((unsigned char *)ctx->buf, 4);
+        memcpy(digest->a, ctx->buf, 16);
+        memset(ctx, 0, sizeof(*ctx));    /* In case it's sensitive */
+}
+
+std::string MD5DigestToBase16(const MD5Digest& digest) {
+  static char const zEncode[] = "0123456789abcdef";
+
+  std::string ret;
+  ret.resize(32);
+
+  int j = 0;
+  for (int i = 0; i < 16; i ++) {
+    int a = digest.a[i];
+    ret[j++] = zEncode[(a>>4)&0xf];
+    ret[j++] = zEncode[a & 0xf];
+  }
+  return ret;
+}
+
+void MD5Sum(const void* data, size_t length, MD5Digest* digest) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+  MD5Update(&ctx,
+            StringPiece(reinterpret_cast<const char*>(data), length));
+  MD5Final(digest, &ctx);
+}
+
+std::string MD5String(const StringPiece& str) {
+  MD5Digest digest;
+  MD5Sum(str.data(), str.length(), &digest);
+  return MD5DigestToBase16(digest);
+}
+
+}  // namespace base
diff --git a/base/md5.h b/base/md5.h
new file mode 100644
index 0000000..4a29a2d
--- /dev/null
+++ b/base/md5.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2011 The Chromium Authors. All 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 "base/base_export.h"
+#include "base/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 {
+  unsigned char a[16];
+};
+
+// Used for storing intermediate data during an MD5 computation. Callers
+// should not access the data.
+typedef char MD5Context[88];
+
+// 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);
+
+// 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);
+
+// Converts a digest into human-readable hexadecimal.
+BASE_EXPORT std::string MD5DigestToBase16(const MD5Digest& digest);
+
+// Returns the MD5 (in hexadecimal) of a string.
+BASE_EXPORT std::string MD5String(const StringPiece& str);
+
+}  // namespace base
+
+#endif  // BASE_MD5_H_
diff --git a/base/md5_unittest.cc b/base/md5_unittest.cc
new file mode 100644
index 0000000..a20d819
--- /dev/null
+++ b/base/md5_unittest.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/md5.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(MD5, DigestToBase16) {
+  MD5Digest digest;
+
+  int data[] = {
+    0xd4, 0x1d, 0x8c, 0xd9,
+    0x8f, 0x00, 0xb2, 0x04,
+    0xe9, 0x80, 0x09, 0x98,
+    0xec, 0xf8, 0x42, 0x7e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    digest.a[i] = data[i] & 0xff;
+
+  std::string actual = MD5DigestToBase16(digest);
+  std::string expected = "d41d8cd98f00b204e9800998ecf8427e";
+
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5SumEmtpyData) {
+  MD5Digest digest;
+  const char* data = "";
+
+  MD5Sum(data, strlen(data), &digest);
+
+  int expected[] = {
+    0xd4, 0x1d, 0x8c, 0xd9,
+    0x8f, 0x00, 0xb2, 0x04,
+    0xe9, 0x80, 0x09, 0x98,
+    0xec, 0xf8, 0x42, 0x7e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, MD5SumOneByteData) {
+  MD5Digest digest;
+  const char* data = "a";
+
+  MD5Sum(data, strlen(data), &digest);
+
+  int expected[] = {
+    0x0c, 0xc1, 0x75, 0xb9,
+    0xc0, 0xf1, 0xb6, 0xa8,
+    0x31, 0xc3, 0x99, 0xe2,
+    0x69, 0x77, 0x26, 0x61
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, MD5SumLongData) {
+  const int length = 10 * 1024 * 1024 + 1;
+  scoped_array<char> data(new char[length]);
+
+  for (int i = 0; i < length; ++i)
+    data[i] = i & 0xFF;
+
+  MD5Digest digest;
+  MD5Sum(data.get(), length, &digest);
+
+  int expected[] = {
+    0x90, 0xbd, 0x6a, 0xd9,
+    0x0a, 0xce, 0xf5, 0xad,
+    0xaa, 0x92, 0x20, 0x3e,
+    0x21, 0xc7, 0xa1, 0x3e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, ContextWithEmptyData) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+
+  MD5Digest digest;
+  MD5Final(&digest, &ctx);
+
+  int expected[] = {
+    0xd4, 0x1d, 0x8c, 0xd9,
+    0x8f, 0x00, 0xb2, 0x04,
+    0xe9, 0x80, 0x09, 0x98,
+    0xec, 0xf8, 0x42, 0x7e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, ContextWithLongData) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+
+  const int length = 10 * 1024 * 1024 + 1;
+  scoped_array<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);
+}
+
+}  // namespace base
diff --git a/base/memory/aligned_memory.cc b/base/memory/aligned_memory.cc
new file mode 100644
index 0000000..b6278ab
--- /dev/null
+++ b/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"
+
+#if defined(OS_ANDROID) || defined(OS_NACL)
+#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);
+// Both Android and NaCl technically support posix_memalign(), but do not expose
+// it in the current version of the library headers used by Chrome.  Luckily,
+// memalign() on both platforms returns pointers which can safely be used with
+// free(), so we can use it instead.  Issues filed with each project for docs:
+// http://code.google.com/p/android/issues/detail?id=35391
+// http://code.google.com/p/chromium/issues/detail?id=138579
+#elif defined(OS_ANDROID) || defined(OS_NACL)
+  ptr = memalign(alignment, size);
+#else
+  if (posix_memalign(&ptr, alignment, size))
+    ptr = NULL;
+#endif
+  // Since aligned allocations may fail for non-memory related reasons, force a
+  // crash if we encounter a failed allocation; maintaining consistent behavior
+  // with a normal allocation failure in Chrome.
+  if (!ptr) {
+    DLOG(ERROR) << "If you crashed here, your aligned allocation is incorrect: "
+                << "size=" << size << ", alignment=" << alignment;
+    CHECK(false);
+  }
+  // Sanity check alignment just to be safe.
+  DCHECK_EQ(reinterpret_cast<uintptr_t>(ptr) & (alignment - 1), 0U);
+  return ptr;
+}
+
+}  // namespace base
diff --git a/base/memory/aligned_memory.h b/base/memory/aligned_memory.h
new file mode 100644
index 0000000..6719599
--- /dev/null
+++ b/base/memory/aligned_memory.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// AlignedMemory is a POD type that gives you a portable way to specify static
+// or local stack data of a given alignment and size. For example, if you need
+// static storage for a class, but you want manual control over when the object
+// is constructed and destructed (you don't want static initialization and
+// destruction), use AlignedMemory:
+//
+//   static AlignedMemory<sizeof(MyClass), ALIGNOF(MyClass)> my_class;
+//
+//   // ... at runtime:
+//   new(my_class.void_data()) MyClass();
+//
+//   // ... use it:
+//   MyClass* mc = my_class.data_as<MyClass>();
+//
+//   // ... later, to destruct my_class:
+//   my_class.data_as<MyClass>()->MyClass::~MyClass();
+//
+// Alternatively, a runtime sized aligned allocation can be created:
+//
+//   float* my_array = static_cast<float*>(AlignedAlloc(size, alignment));
+//
+//   // ... later, to release the memory:
+//   AlignedFree(my_array);
+//
+// Or using scoped_ptr_malloc:
+//
+//   scoped_ptr_malloc<float, ScopedPtrAlignedFree> my_array(
+//       static_cast<float*>(AlignedAlloc(size, alignment)));
+
+#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
+#define BASE_MEMORY_ALIGNED_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+#if defined(COMPILER_MSVC)
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+
+namespace base {
+
+// AlignedMemory is specialized for all supported alignments.
+// Make sure we get a compiler error if someone uses an unsupported alignment.
+template <size_t Size, size_t ByteAlignment>
+struct AlignedMemory {};
+
+#define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \
+    template <size_t Size> \
+    class AlignedMemory<Size, byte_alignment> { \
+     public: \
+      ALIGNAS(byte_alignment) uint8 data_[Size]; \
+      void* void_data() { return static_cast<void*>(data_); } \
+      const void* void_data() const { \
+        return static_cast<const void*>(data_); \
+      } \
+      template<typename Type> \
+      Type* data_as() { return static_cast<Type*>(void_data()); } \
+      template<typename Type> \
+      const Type* data_as() const { \
+        return static_cast<const Type*>(void_data()); \
+      } \
+     private: \
+      void* operator new(size_t); \
+      void operator delete(void*); \
+    }
+
+// Specialization for all alignments is required because MSVC (as of VS 2008)
+// does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param).
+// Greater than 4096 alignment is not supported by some compilers, so 4096 is
+// the maximum specified here.
+BASE_DECL_ALIGNED_MEMORY(1);
+BASE_DECL_ALIGNED_MEMORY(2);
+BASE_DECL_ALIGNED_MEMORY(4);
+BASE_DECL_ALIGNED_MEMORY(8);
+BASE_DECL_ALIGNED_MEMORY(16);
+BASE_DECL_ALIGNED_MEMORY(32);
+BASE_DECL_ALIGNED_MEMORY(64);
+BASE_DECL_ALIGNED_MEMORY(128);
+BASE_DECL_ALIGNED_MEMORY(256);
+BASE_DECL_ALIGNED_MEMORY(512);
+BASE_DECL_ALIGNED_MEMORY(1024);
+BASE_DECL_ALIGNED_MEMORY(2048);
+BASE_DECL_ALIGNED_MEMORY(4096);
+
+#undef BASE_DECL_ALIGNED_MEMORY
+
+BASE_EXPORT void* AlignedAlloc(size_t size, size_t alignment);
+
+inline void AlignedFree(void* ptr) {
+#if defined(COMPILER_MSVC)
+  _aligned_free(ptr);
+#else
+  free(ptr);
+#endif
+}
+
+// Helper class for use with scoped_ptr_malloc.
+class BASE_EXPORT ScopedPtrAlignedFree {
+ public:
+  inline void operator()(void* ptr) const {
+    AlignedFree(ptr);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_ALIGNED_MEMORY_H_
diff --git a/base/memory/aligned_memory_unittest.cc b/base/memory/aligned_memory_unittest.cc
new file mode 100644
index 0000000..c337751
--- /dev/null
+++ b/base/memory/aligned_memory_unittest.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/memory/aligned_memory.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+namespace {
+
+using base::AlignedMemory;
+
+TEST(AlignedMemoryTest, StaticAlignment) {
+  static AlignedMemory<8, 8> raw8;
+  static AlignedMemory<8, 16> raw16;
+  static AlignedMemory<8, 256> raw256;
+  static AlignedMemory<8, 4096> raw4096;
+
+  EXPECT_EQ(8u, ALIGNOF(raw8));
+  EXPECT_EQ(16u, ALIGNOF(raw16));
+  EXPECT_EQ(256u, ALIGNOF(raw256));
+  EXPECT_EQ(4096u, ALIGNOF(raw4096));
+
+  EXPECT_ALIGNED(raw8.void_data(), 8);
+  EXPECT_ALIGNED(raw16.void_data(), 16);
+  EXPECT_ALIGNED(raw256.void_data(), 256);
+  EXPECT_ALIGNED(raw4096.void_data(), 4096);
+}
+
+TEST(AlignedMemoryTest, StackAlignment) {
+  AlignedMemory<8, 8> raw8;
+  AlignedMemory<8, 16> raw16;
+  AlignedMemory<8, 256> raw256;
+
+  EXPECT_EQ(8u, ALIGNOF(raw8));
+  EXPECT_EQ(16u, ALIGNOF(raw16));
+  EXPECT_EQ(256u, ALIGNOF(raw256));
+
+  EXPECT_ALIGNED(raw8.void_data(), 8);
+  EXPECT_ALIGNED(raw16.void_data(), 16);
+  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))
+}
+
+TEST(AlignedMemoryTest, DynamicAllocation) {
+  void* p = base::AlignedAlloc(8, 8);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 8);
+  base::AlignedFree(p);
+
+  p = base::AlignedAlloc(8, 16);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 16);
+  base::AlignedFree(p);
+
+  p = base::AlignedAlloc(8, 256);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 256);
+  base::AlignedFree(p);
+
+  p = base::AlignedAlloc(8, 4096);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 4096);
+  base::AlignedFree(p);
+}
+
+TEST(AlignedMemoryTest, ScopedDynamicAllocation) {
+  scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> p(
+      static_cast<float*>(base::AlignedAlloc(8, 8)));
+  EXPECT_TRUE(p.get());
+  EXPECT_ALIGNED(p.get(), 8);
+}
+
+}  // namespace
diff --git a/base/memory/linked_ptr.h b/base/memory/linked_ptr.h
new file mode 100644
index 0000000..80044ad
--- /dev/null
+++ b/base/memory/linked_ptr.h
@@ -0,0 +1,181 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A "smart" pointer type with reference tracking.  Every pointer to a
+// particular object is kept on a circular linked list.  When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is released, the entire list of pointers to that
+//   object is traversed.  This class is therefore NOT SUITABLE when there
+//   will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+//   will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Thread Safety:
+//   A linked_ptr is NOT thread safe. Copying a linked_ptr object is
+//   effectively a read-write operation.
+//
+// Alternative: to linked_ptr is shared_ptr, which
+//  - is also two pointers in size (8 bytes for 32 bit addresses)
+//  - is thread safe for copying and deletion
+//  - supports weak_ptrs
+
+#ifndef BASE_MEMORY_LINKED_PTR_H_
+#define BASE_MEMORY_LINKED_PTR_H_
+
+#include "base/logging.h"  // for CHECK macros
+
+// This is used internally by all instances of linked_ptr<>.  It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.
+class linked_ptr_internal {
+ public:
+  // Create a new circle that includes only this instance.
+  void join_new() {
+    next_ = this;
+  }
+
+  // Join an existing circle.
+  void join(linked_ptr_internal const* ptr) {
+    next_ = ptr->next_;
+    ptr->next_ = this;
+  }
+
+  // Leave whatever circle we're part of.  Returns true iff we were the
+  // last member of the circle.  Once this is done, you can join() another.
+  bool depart() {
+    if (next_ == this) return true;
+    linked_ptr_internal const* p = next_;
+    while (p->next_ != this) p = p->next_;
+    p->next_ = next_;
+    return false;
+  }
+
+ private:
+  mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr {
+ public:
+  typedef T element_type;
+
+  // Take over ownership of a raw pointer.  This should happen as soon as
+  // possible after the object is created.
+  explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+  ~linked_ptr() { depart(); }
+
+  // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+  template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
+
+  linked_ptr(linked_ptr const& ptr) {
+    DCHECK_NE(&ptr, this);
+    copy(&ptr);
+  }
+
+  // Assignment releases the old value and acquires the new.
+  template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
+    depart();
+    copy(&ptr);
+    return *this;
+  }
+
+  linked_ptr& operator=(linked_ptr const& ptr) {
+    if (&ptr != this) {
+      depart();
+      copy(&ptr);
+    }
+    return *this;
+  }
+
+  // Smart pointer members.
+  void reset(T* ptr = NULL) {
+    depart();
+    capture(ptr);
+  }
+  T* get() const { return value_; }
+  T* operator->() const { return value_; }
+  T& operator*() const { return *value_; }
+  // Release ownership of the pointed object and returns it.
+  // Sole ownership by this linked_ptr object is required.
+  T* release() {
+    bool last = link_.depart();
+    CHECK(last);
+    T* v = value_;
+    value_ = NULL;
+    return v;
+  }
+
+  bool operator==(const T* p) const { return value_ == p; }
+  bool operator!=(const T* p) const { return value_ != p; }
+  template <typename U>
+  bool operator==(linked_ptr<U> const& ptr) const {
+    return value_ == ptr.get();
+  }
+  template <typename U>
+  bool operator!=(linked_ptr<U> const& ptr) const {
+    return value_ != ptr.get();
+  }
+
+ private:
+  template <typename U>
+  friend class linked_ptr;
+
+  T* value_;
+  linked_ptr_internal link_;
+
+  void depart() {
+    if (link_.depart()) delete value_;
+  }
+
+  void capture(T* ptr) {
+    value_ = ptr;
+    link_.join_new();
+  }
+
+  template <typename U> void copy(linked_ptr<U> const* ptr) {
+    value_ = ptr->get();
+    if (value_)
+      link_.join(&ptr->link_);
+    else
+      link_.join_new();
+  }
+};
+
+template<typename T> inline
+bool operator==(T* ptr, const linked_ptr<T>& x) {
+  return ptr == x.get();
+}
+
+template<typename T> inline
+bool operator!=(T* ptr, const linked_ptr<T>& x) {
+  return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr) {
+  return linked_ptr<T>(ptr);
+}
+
+#endif  // BASE_MEMORY_LINKED_PTR_H_
diff --git a/base/memory/linked_ptr_unittest.cc b/base/memory/linked_ptr_unittest.cc
new file mode 100644
index 0000000..4550350
--- /dev/null
+++ b/base/memory/linked_ptr_unittest.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 <string>
+
+#include "base/memory/linked_ptr.h"
+#include "base/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); }
+  virtual ~B() { history += base::StringPrintf("B%d dtor\n", mynum); }
+  virtual void Use() OVERRIDE {
+    history += base::StringPrintf("B%d use\n", mynum);
+  }
+};
+
+}  // namespace
+
+TEST(LinkedPtrTest, Test) {
+  {
+    linked_ptr<A> a0, a1, a2;
+    a0 = a0;
+    a1 = a2;
+    ASSERT_EQ(a0.get(), static_cast<A*>(NULL));
+    ASSERT_EQ(a1.get(), static_cast<A*>(NULL));
+    ASSERT_EQ(a2.get(), static_cast<A*>(NULL));
+    ASSERT_TRUE(a0 == NULL);
+    ASSERT_TRUE(a1 == NULL);
+    ASSERT_TRUE(a2 == NULL);
+
+    {
+      linked_ptr<A> a3(new A);
+      a0 = a3;
+      ASSERT_TRUE(a0 == a3);
+      ASSERT_TRUE(a0 != NULL);
+      ASSERT_TRUE(a0.get() == a3);
+      ASSERT_TRUE(a0 == a3.get());
+      linked_ptr<A> a4(a0);
+      a1 = a4;
+      linked_ptr<A> a5(new A);
+      ASSERT_TRUE(a5.get() != a3);
+      ASSERT_TRUE(a5 != a3.get());
+      a2 = a5;
+      linked_ptr<B> b0(new B);
+      linked_ptr<A> a6(b0);
+      ASSERT_TRUE(b0 == a6);
+      ASSERT_TRUE(a6 == b0);
+      ASSERT_TRUE(b0 != NULL);
+      a5 = b0;
+      a5 = b0;
+      a3->Use();
+      a4->Use();
+      a5->Use();
+      a6->Use();
+      b0->Use();
+      (*b0).Use();
+      b0.get()->Use();
+    }
+
+    a0->Use();
+    a1->Use();
+    a2->Use();
+
+    a1 = a2;
+    a2.reset(new A);
+    a0.reset();
+
+    linked_ptr<A> a7;
+  }
+
+  ASSERT_EQ(history,
+    "A0 ctor\n"
+    "A1 ctor\n"
+    "A2 ctor\n"
+    "B2 ctor\n"
+    "A0 use\n"
+    "A0 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 dtor\n"
+    "A2 dtor\n"
+    "A0 use\n"
+    "A0 use\n"
+    "A1 use\n"
+    "A3 ctor\n"
+    "A0 dtor\n"
+    "A3 dtor\n"
+    "A1 dtor\n"
+  );
+}
diff --git a/base/memory/manual_constructor.h b/base/memory/manual_constructor.h
new file mode 100644
index 0000000..9275f73
--- /dev/null
+++ b/base/memory/manual_constructor.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// 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/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) {
+#if defined(COMPILER_MSVC)
+    return AlignedAlloc(size, __alignof(Type));
+#else
+    return AlignedAlloc(size, __alignof__(Type));
+#endif
+  }
+  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(); }
+
+  // You can pass up to eight constructor arguments as arguments of Init().
+  inline void Init() {
+    new(space_.void_data()) Type;
+  }
+
+  template <typename T1>
+  inline void Init(const T1& p1) {
+    new(space_.void_data()) Type(p1);
+  }
+
+  template <typename T1, typename T2>
+  inline void Init(const T1& p1, const T2& p2) {
+    new(space_.void_data()) Type(p1, p2);
+  }
+
+  template <typename T1, typename T2, typename T3>
+  inline void Init(const T1& p1, const T2& p2, const T3& p3) {
+    new(space_.void_data()) Type(p1, p2, p3);
+  }
+
+  template <typename T1, typename T2, typename T3, typename T4>
+  inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4) {
+    new(space_.void_data()) Type(p1, p2, p3, p4);
+  }
+
+  template <typename T1, typename T2, typename T3, typename T4, typename T5>
+  inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+                   const T5& p5) {
+    new(space_.void_data()) Type(p1, p2, p3, p4, p5);
+  }
+
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6>
+  inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+                   const T5& p5, const T6& p6) {
+    new(space_.void_data()) Type(p1, p2, p3, p4, p5, p6);
+  }
+
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7>
+  inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+                   const T5& p5, const T6& p6, const T7& p7) {
+    new(space_.void_data()) Type(p1, p2, p3, p4, p5, p6, p7);
+  }
+
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8>
+  inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+                   const T5& p5, const T6& p6, const T7& p7, const T8& p8) {
+    new(space_.void_data()) Type(p1, p2, p3, p4, p5, p6, p7, p8);
+  }
+
+  inline void Destroy() {
+    get()->~Type();
+  }
+
+ private:
+#if defined(COMPILER_MSVC)
+  AlignedMemory<sizeof(Type), __alignof(Type)> space_;
+#else
+  AlignedMemory<sizeof(Type), __alignof__(Type)> space_;
+#endif
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
diff --git a/base/memory/mru_cache.h b/base/memory/mru_cache.h
new file mode 100644
index 0000000..915d2b5
--- /dev/null
+++ b/base/memory/mru_cache.h
@@ -0,0 +1,305 @@
+// Copyright (c) 2011 The Chromium 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_MEMORY_MRU_CACHE_H_
+#define BASE_MEMORY_MRU_CACHE_H_
+
+#include <list>
+#include <map>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/logging.h"
+
+namespace base {
+
+// MRUCacheBase ----------------------------------------------------------------
+
+// This template is used to standardize map type containers that can be used
+// by MRUCacheBase. This level of indirection is necessary because of the way
+// that template template params and default template params interact.
+template <class KeyType, class ValueType>
+struct MRUCacheStandardMap {
+  typedef std::map<KeyType, ValueType> Type;
+};
+
+// Base class for the MRU cache specializations defined below.
+// The deletor will get called on all payloads that are being removed or
+// replaced.
+template <class KeyType, class PayloadType, class DeletorType,
+          template <typename, typename> class MapType = MRUCacheStandardMap>
+class MRUCacheBase {
+ public:
+  // The payload of the list. This maintains a copy of the key so we can
+  // efficiently delete things given an element of the list.
+  typedef std::pair<KeyType, PayloadType> value_type;
+
+ private:
+  typedef std::list<value_type> PayloadList;
+  typedef typename MapType<KeyType,
+                           typename PayloadList::iterator>::Type KeyIndex;
+
+ public:
+  typedef typename PayloadList::size_type size_type;
+
+  typedef typename PayloadList::iterator iterator;
+  typedef typename PayloadList::const_iterator const_iterator;
+  typedef typename PayloadList::reverse_iterator reverse_iterator;
+  typedef typename PayloadList::const_reverse_iterator const_reverse_iterator;
+
+  enum { NO_AUTO_EVICT = 0 };
+
+  // The max_size is the size at which the cache will prune its members to when
+  // a new item is inserted. If the caller wants to manager this itself (for
+  // example, maybe it has special work to do when something is evicted), it
+  // can pass NO_AUTO_EVICT to not restrict the cache size.
+  explicit MRUCacheBase(size_type max_size) : max_size_(max_size) {
+  }
+
+  MRUCacheBase(size_type max_size, const DeletorType& deletor)
+      : max_size_(max_size), deletor_(deletor) {
+  }
+
+  virtual ~MRUCacheBase() {
+    iterator i = begin();
+    while (i != end())
+      i = Erase(i);
+  }
+
+  size_type max_size() const { return max_size_; }
+
+  // Inserts a payload item with the given key. If an existing item has
+  // the same key, it is removed prior to insertion. An iterator indicating the
+  // inserted item will be returned (this will always be the front of the list).
+  //
+  // The payload will be copied. In the case of an OwningMRUCache, this function
+  // will take ownership of the pointer.
+  iterator Put(const KeyType& key, const PayloadType& payload) {
+    // Remove any existing payload with that key.
+    typename KeyIndex::iterator index_iter = index_.find(key);
+    if (index_iter != index_.end()) {
+      // Erase the reference to it. This will call the deletor on the removed
+      // element. The index reference will be replaced in the code below.
+      Erase(index_iter->second);
+    } else if (max_size_ != NO_AUTO_EVICT) {
+      // New item is being inserted which might make it larger than the maximum
+      // size: kick the oldest thing out if necessary.
+      ShrinkToSize(max_size_ - 1);
+    }
+
+    ordering_.push_front(value_type(key, payload));
+    index_.insert(std::make_pair(key, ordering_.begin()));
+    return ordering_.begin();
+  }
+
+  // Retrieves the contents of the given key, or end() if not found. This method
+  // has the side effect of moving the requested item to the front of the
+  // recency list.
+  //
+  // TODO(brettw) We may want a const version of this function in the future.
+  iterator Get(const KeyType& key) {
+    typename KeyIndex::iterator index_iter = index_.find(key);
+    if (index_iter == index_.end())
+      return end();
+    typename PayloadList::iterator iter = index_iter->second;
+
+    // Move the touched item to the front of the recency ordering.
+    ordering_.splice(ordering_.begin(), ordering_, iter);
+    return ordering_.begin();
+  }
+
+  // Retrieves the payload associated with a given key and returns it via
+  // result without affecting the ordering (unlike Get).
+  //
+  // TODO(brettw) We may want a const version of this function in the future.
+  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;
+  }
+
+  // Erases the item referenced by the given iterator. An iterator to the item
+  // following it will be returned. The iterator must be valid.
+  iterator Erase(iterator pos) {
+    deletor_(pos->second);
+    index_.erase(pos->first);
+    return ordering_.erase(pos);
+  }
+
+  // MRUCache entries are often processed in reverse order, so we add this
+  // convenience function (not typically defined by STL containers).
+  reverse_iterator Erase(reverse_iterator pos) {
+    // We have to actually give it the incremented iterator to delete, since
+    // the forward iterator that base() returns is actually one past the item
+    // being iterated over.
+    return reverse_iterator(Erase((++pos).base()));
+  }
+
+  // Shrinks the cache so it only holds |new_size| items. If |new_size| is
+  // bigger or equal to the current number of items, this will do nothing.
+  void ShrinkToSize(size_type new_size) {
+    for (size_type i = size(); i > new_size; i--)
+      Erase(rbegin());
+  }
+
+  // Deletes everything from the cache.
+  void Clear() {
+    for (typename PayloadList::iterator i(ordering_.begin());
+         i != ordering_.end(); ++i)
+      deletor_(i->second);
+    index_.clear();
+    ordering_.clear();
+  }
+
+  // Returns the number of elements in the cache.
+  size_type size() const {
+    // We don't use ordering_.size() for the return value because
+    // (as a linked list) it can be O(n).
+    DCHECK(index_.size() == ordering_.size());
+    return index_.size();
+  }
+
+  // Allows iteration over the list. Forward iteration starts with the most
+  // recent item and works backwards.
+  //
+  // Note that since these iterators are actually iterators over a list, you
+  // can keep them as you insert or delete things (as long as you don't delete
+  // the one you are pointing to) and they will still be valid.
+  iterator begin() { return ordering_.begin(); }
+  const_iterator begin() const { return ordering_.begin(); }
+  iterator end() { return ordering_.end(); }
+  const_iterator end() const { return ordering_.end(); }
+
+  reverse_iterator rbegin() { return ordering_.rbegin(); }
+  const_reverse_iterator rbegin() const { return ordering_.rbegin(); }
+  reverse_iterator rend() { return ordering_.rend(); }
+  const_reverse_iterator rend() const { return ordering_.rend(); }
+
+  bool empty() const { return ordering_.empty(); }
+
+ private:
+  PayloadList ordering_;
+  KeyIndex index_;
+
+  size_type max_size_;
+
+  DeletorType deletor_;
+
+  DISALLOW_COPY_AND_ASSIGN(MRUCacheBase);
+};
+
+// MRUCache --------------------------------------------------------------------
+
+// A functor that does nothing. Used by the MRUCache.
+template<class PayloadType>
+class MRUCacheNullDeletor {
+ public:
+  void operator()(PayloadType& payload) {
+  }
+};
+
+// A container that does not do anything to free its data. Use this when storing
+// value types (as opposed to pointers) in the list.
+template <class KeyType, class PayloadType>
+class MRUCache : public MRUCacheBase<KeyType,
+                                     PayloadType,
+                                     MRUCacheNullDeletor<PayloadType> > {
+ private:
+  typedef MRUCacheBase<KeyType, PayloadType,
+      MRUCacheNullDeletor<PayloadType> > ParentType;
+
+ public:
+  // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
+  explicit MRUCache(typename ParentType::size_type max_size)
+      : ParentType(max_size) {
+  }
+  virtual ~MRUCache() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MRUCache);
+};
+
+// OwningMRUCache --------------------------------------------------------------
+
+template<class PayloadType>
+class MRUCachePointerDeletor {
+ public:
+  void operator()(PayloadType& payload) {
+    delete payload;
+  }
+};
+
+// A cache that owns the payload type, which must be a non-const pointer type.
+// The pointers will be deleted when they are removed, replaced, or when the
+// cache is destroyed.
+template <class KeyType, class PayloadType>
+class OwningMRUCache
+    : public MRUCacheBase<KeyType,
+                          PayloadType,
+                          MRUCachePointerDeletor<PayloadType> > {
+ private:
+  typedef MRUCacheBase<KeyType, PayloadType,
+      MRUCachePointerDeletor<PayloadType> > ParentType;
+
+ public:
+  // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
+  explicit OwningMRUCache(typename ParentType::size_type max_size)
+      : ParentType(max_size) {
+  }
+  virtual ~OwningMRUCache() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OwningMRUCache);
+};
+
+// HashingMRUCache ------------------------------------------------------------
+
+template <class KeyType, class ValueType>
+struct MRUCacheHashMap {
+  typedef base::hash_map<KeyType, ValueType> Type;
+};
+
+// This class is similar to MRUCache, except that it uses base::hash_map as
+// the map type instead of std::map. Note that your KeyType must be hashable
+// to use this cache.
+template <class KeyType, class PayloadType>
+class HashingMRUCache : public MRUCacheBase<KeyType,
+                                            PayloadType,
+                                            MRUCacheNullDeletor<PayloadType>,
+                                            MRUCacheHashMap> {
+ private:
+  typedef MRUCacheBase<KeyType, PayloadType,
+                       MRUCacheNullDeletor<PayloadType>,
+                       MRUCacheHashMap> ParentType;
+
+ public:
+  // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
+  explicit HashingMRUCache(typename ParentType::size_type max_size)
+      : ParentType(max_size) {
+  }
+  virtual ~HashingMRUCache() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HashingMRUCache);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MRU_CACHE_H_
diff --git a/base/memory/mru_cache_unittest.cc b/base/memory/mru_cache_unittest.cc
new file mode 100644
index 0000000..1fe9ce2
--- /dev/null
+++ b/base/memory/mru_cache_unittest.cc
@@ -0,0 +1,271 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/memory/mru_cache.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int cached_item_live_count = 0;
+
+struct CachedItem {
+  CachedItem() : value(0) {
+    cached_item_live_count++;
+  }
+
+  explicit CachedItem(int new_value) : value(new_value) {
+    cached_item_live_count++;
+  }
+
+  explicit CachedItem(const CachedItem& other) : value(other.value) {
+    cached_item_live_count++;
+  }
+
+  ~CachedItem() {
+    cached_item_live_count--;
+  }
+
+  int value;
+};
+
+}  // namespace
+
+TEST(MRUCacheTest, Basic) {
+  typedef base::MRUCache<int, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  // Check failure conditions
+  {
+    CachedItem test_item;
+    EXPECT_TRUE(cache.Get(0) == cache.end());
+    EXPECT_TRUE(cache.Peek(0) == cache.end());
+  }
+
+  static const int kItem1Key = 5;
+  CachedItem item1(10);
+  Cache::iterator inserted_item = cache.Put(kItem1Key, item1);
+  EXPECT_EQ(1U, cache.size());
+
+  // Check that item1 was properly inserted.
+  {
+    Cache::iterator found = cache.Get(kItem1Key);
+    EXPECT_TRUE(inserted_item == cache.begin());
+    EXPECT_TRUE(found != cache.end());
+
+    found = cache.Peek(kItem1Key);
+    EXPECT_TRUE(found != cache.end());
+
+    EXPECT_EQ(kItem1Key, found->first);
+    EXPECT_EQ(item1.value, found->second.value);
+  }
+
+  static const int kItem2Key = 7;
+  CachedItem item2(12);
+  cache.Put(kItem2Key, item2);
+  EXPECT_EQ(2U, cache.size());
+
+  // Check that item1 is the oldest since item2 was added afterwards.
+  {
+    Cache::reverse_iterator oldest = cache.rbegin();
+    ASSERT_TRUE(oldest != cache.rend());
+    EXPECT_EQ(kItem1Key, oldest->first);
+    EXPECT_EQ(item1.value, oldest->second.value);
+  }
+
+  // Check that item1 is still accessible by key.
+  {
+    Cache::iterator test_item = cache.Get(kItem1Key);
+    ASSERT_TRUE(test_item != cache.end());
+    EXPECT_EQ(kItem1Key, test_item->first);
+    EXPECT_EQ(item1.value, test_item->second.value);
+  }
+
+  // Check that retrieving item1 pushed item2 to oldest.
+  {
+    Cache::reverse_iterator oldest = cache.rbegin();
+    ASSERT_TRUE(oldest != cache.rend());
+    EXPECT_EQ(kItem2Key, oldest->first);
+    EXPECT_EQ(item2.value, oldest->second.value);
+  }
+
+  // Remove the oldest item and check that item1 is now the only member.
+  {
+    Cache::reverse_iterator next = cache.Erase(cache.rbegin());
+
+    EXPECT_EQ(1U, cache.size());
+
+    EXPECT_TRUE(next == cache.rbegin());
+    EXPECT_EQ(kItem1Key, next->first);
+    EXPECT_EQ(item1.value, next->second.value);
+
+    cache.Erase(cache.begin());
+    EXPECT_EQ(0U, cache.size());
+  }
+
+  // Check that Clear() works properly.
+  cache.Put(kItem1Key, item1);
+  cache.Put(kItem2Key, item2);
+  EXPECT_EQ(2U, cache.size());
+  cache.Clear();
+  EXPECT_EQ(0U, cache.size());
+}
+
+TEST(MRUCacheTest, GetVsPeek) {
+  typedef base::MRUCache<int, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  static const int kItem1Key = 1;
+  CachedItem item1(10);
+  cache.Put(kItem1Key, item1);
+
+  static const int kItem2Key = 2;
+  CachedItem item2(20);
+  cache.Put(kItem2Key, item2);
+
+  // This should do nothing since the size is bigger than the number of items.
+  cache.ShrinkToSize(100);
+
+  // Check that item1 starts out as oldest
+  {
+    Cache::reverse_iterator iter = cache.rbegin();
+    ASSERT_TRUE(iter != cache.rend());
+    EXPECT_EQ(kItem1Key, iter->first);
+    EXPECT_EQ(item1.value, iter->second.value);
+  }
+
+  // Check that Peek doesn't change ordering
+  {
+    Cache::iterator peekiter = cache.Peek(kItem1Key);
+    ASSERT_TRUE(peekiter != cache.end());
+
+    Cache::reverse_iterator iter = cache.rbegin();
+    ASSERT_TRUE(iter != cache.rend());
+    EXPECT_EQ(kItem1Key, iter->first);
+    EXPECT_EQ(item1.value, iter->second.value);
+  }
+}
+
+TEST(MRUCacheTest, KeyReplacement) {
+  typedef base::MRUCache<int, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  static const int kItem1Key = 1;
+  CachedItem item1(10);
+  cache.Put(kItem1Key, item1);
+
+  static const int kItem2Key = 2;
+  CachedItem item2(20);
+  cache.Put(kItem2Key, item2);
+
+  static const int kItem3Key = 3;
+  CachedItem item3(30);
+  cache.Put(kItem3Key, item3);
+
+  static const int kItem4Key = 4;
+  CachedItem item4(40);
+  cache.Put(kItem4Key, item4);
+
+  CachedItem item5(50);
+  cache.Put(kItem3Key, item5);
+
+  EXPECT_EQ(4U, cache.size());
+  for (int i = 0; i < 3; ++i) {
+    Cache::reverse_iterator iter = cache.rbegin();
+    ASSERT_TRUE(iter != cache.rend());
+  }
+
+  // Make it so only the most important element is there.
+  cache.ShrinkToSize(1);
+
+  Cache::iterator iter = cache.begin();
+  EXPECT_EQ(kItem3Key, iter->first);
+  EXPECT_EQ(item5.value, iter->second.value);
+}
+
+// Make sure that the owning version release its pointers properly.
+TEST(MRUCacheTest, Owning) {
+  typedef base::OwningMRUCache<int, CachedItem*> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  int initial_count = cached_item_live_count;
+
+  // First insert and item and then overwrite it.
+  static const int kItem1Key = 1;
+  cache.Put(kItem1Key, new CachedItem(20));
+  cache.Put(kItem1Key, new CachedItem(22));
+
+  // There should still be one item, and one extra live item.
+  Cache::iterator iter = cache.Get(kItem1Key);
+  EXPECT_EQ(1U, cache.size());
+  EXPECT_TRUE(iter != cache.end());
+  EXPECT_EQ(initial_count + 1, cached_item_live_count);
+
+  // Now remove it.
+  cache.Erase(cache.begin());
+  EXPECT_EQ(initial_count, cached_item_live_count);
+
+  // Now try another cache that goes out of scope to make sure its pointers
+  // go away.
+  {
+    Cache cache2(Cache::NO_AUTO_EVICT);
+    cache2.Put(1, new CachedItem(20));
+    cache2.Put(2, new CachedItem(20));
+  }
+
+  // There should be no objects leaked.
+  EXPECT_EQ(initial_count, cached_item_live_count);
+
+  // Check that Clear() also frees things correctly.
+  {
+    Cache cache2(Cache::NO_AUTO_EVICT);
+    cache2.Put(1, new CachedItem(20));
+    cache2.Put(2, new CachedItem(20));
+    EXPECT_EQ(initial_count + 2, cached_item_live_count);
+    cache2.Clear();
+    EXPECT_EQ(initial_count, cached_item_live_count);
+  }
+}
+
+TEST(MRUCacheTest, AutoEvict) {
+  typedef base::OwningMRUCache<int, CachedItem*> Cache;
+  static const Cache::size_type kMaxSize = 3;
+
+  int initial_count = cached_item_live_count;
+
+  {
+    Cache cache(kMaxSize);
+
+    static const int kItem1Key = 1, kItem2Key = 2, kItem3Key = 3, kItem4Key = 4;
+    cache.Put(kItem1Key, new CachedItem(20));
+    cache.Put(kItem2Key, new CachedItem(21));
+    cache.Put(kItem3Key, new CachedItem(22));
+    cache.Put(kItem4Key, new CachedItem(23));
+
+    // The cache should only have kMaxSize items in it even though we inserted
+    // more.
+    EXPECT_EQ(kMaxSize, cache.size());
+  }
+
+  // There should be no objects leaked.
+  EXPECT_EQ(initial_count, cached_item_live_count);
+}
+
+TEST(MRUCacheTest, HashingMRUCache) {
+  // Very simple test to make sure that the hashing cache works correctly.
+  typedef base::HashingMRUCache<std::string, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  CachedItem one(1);
+  cache.Put("First", one);
+
+  CachedItem two(2);
+  cache.Put("Second", two);
+
+  EXPECT_EQ(one.value, cache.Get("First")->second.value);
+  EXPECT_EQ(two.value, cache.Get("Second")->second.value);
+  cache.ShrinkToSize(1);
+  EXPECT_EQ(two.value, cache.Get("Second")->second.value);
+  EXPECT_TRUE(cache.Get("First") == cache.end());
+}
diff --git a/base/memory/raw_scoped_refptr_mismatch_checker.h b/base/memory/raw_scoped_refptr_mismatch_checker.h
new file mode 100644
index 0000000..7974f30
--- /dev/null
+++ b/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+#define BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/template_util.h"
+#include "base/tuple.h"
+#include "build/build_config.h"
+
+// It is dangerous to post a task with a T* argument where T is a subtype of
+// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the
+// object may already have been deleted since it was not held with a
+// scoped_refptr. Example: http://crbug.com/27191
+// The following set of traits are designed to generate a compile error
+// whenever this antipattern is attempted.
+
+namespace base {
+
+// This is a base internal implementation file used by task.h and callback.h.
+// Not for public consumption, so we wrap it in namespace internal.
+namespace internal {
+
+template <typename T>
+struct NeedsScopedRefptrButGetsRawPtr {
+#if defined(OS_WIN)
+  enum {
+    value = base::false_type::value
+  };
+#else
+  enum {
+    // Human readable translation: you needed to be a scoped_refptr if you are a
+    // raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase)
+    // type.
+    value = (is_pointer<T>::value &&
+             (is_convertible<T, subtle::RefCountedBase*>::value ||
+              is_convertible<T, subtle::RefCountedThreadSafeBase*>::value))
+  };
+#endif
+};
+
+template <typename Params>
+struct ParamsUseScopedRefptrCorrectly {
+  enum { value = 0 };
+};
+
+template <>
+struct ParamsUseScopedRefptrCorrectly<Tuple0> {
+  enum { value = 1 };
+};
+
+template <typename A>
+struct ParamsUseScopedRefptrCorrectly<Tuple1<A> > {
+  enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value };
+};
+
+template <typename A, typename B>
+struct ParamsUseScopedRefptrCorrectly<Tuple2<A, B> > {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value) };
+};
+
+template <typename A, typename B, typename C>
+struct ParamsUseScopedRefptrCorrectly<Tuple3<A, B, C> > {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value) };
+};
+
+template <typename A, typename B, typename C, typename D>
+struct ParamsUseScopedRefptrCorrectly<Tuple4<A, B, C, D> > {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E>
+struct ParamsUseScopedRefptrCorrectly<Tuple5<A, B, C, D, E> > {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E,
+          typename F>
+struct ParamsUseScopedRefptrCorrectly<Tuple6<A, B, C, D, E, F> > {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<F>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E,
+          typename F, typename G>
+struct ParamsUseScopedRefptrCorrectly<Tuple7<A, B, C, D, E, F, G> > {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<F>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<G>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E,
+          typename F, typename G, typename H>
+struct ParamsUseScopedRefptrCorrectly<Tuple8<A, B, C, D, E, F, G, H> > {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<F>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<G>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<H>::value) };
+};
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
diff --git a/base/memory/ref_counted.cc b/base/memory/ref_counted.cc
new file mode 100644
index 0000000..31ad509
--- /dev/null
+++ b/base/memory/ref_counted.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2011 The Chromium Authors. All 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/logging.h"
+#include "base/threading/thread_collision_warner.h"
+
+namespace base {
+
+namespace subtle {
+
+RefCountedBase::RefCountedBase()
+    : ref_count_(0)
+#ifndef NDEBUG
+    , in_dtor_(false)
+#endif
+    {
+}
+
+RefCountedBase::~RefCountedBase() {
+#ifndef NDEBUG
+  DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
+#endif
+}
+
+void RefCountedBase::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_;
+}
+
+bool RefCountedBase::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;
+}
+
+bool RefCountedThreadSafeBase::HasOneRef() const {
+  return AtomicRefCountIsOne(
+      &const_cast<RefCountedThreadSafeBase*>(this)->ref_count_);
+}
+
+RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) {
+#ifndef NDEBUG
+  in_dtor_ = false;
+#endif
+}
+
+RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
+#ifndef NDEBUG
+  DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
+                      "calling Release()";
+#endif
+}
+
+void RefCountedThreadSafeBase::AddRef() const {
+#ifndef NDEBUG
+  DCHECK(!in_dtor_);
+#endif
+  AtomicRefCountInc(&ref_count_);
+}
+
+bool RefCountedThreadSafeBase::Release() const {
+#ifndef NDEBUG
+  DCHECK(!in_dtor_);
+  DCHECK(!AtomicRefCountIsZero(&ref_count_));
+#endif
+  if (!AtomicRefCountDec(&ref_count_)) {
+#ifndef NDEBUG
+    in_dtor_ = true;
+#endif
+    return true;
+  }
+  return false;
+}
+
+}  // namespace subtle
+
+}  // namespace base
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
new file mode 100644
index 0000000..ba7e657
--- /dev/null
+++ b/base/memory/ref_counted.h
@@ -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.
+
+#ifndef BASE_MEMORY_REF_COUNTED_H_
+#define BASE_MEMORY_REF_COUNTED_H_
+
+#include <cassert>
+
+#include "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/threading/thread_collision_warner.h"
+
+namespace base {
+
+namespace subtle {
+
+class BASE_EXPORT RefCountedBase {
+ public:
+  bool HasOneRef() const { return ref_count_ == 1; }
+
+ protected:
+  RefCountedBase();
+  ~RefCountedBase();
+
+  void AddRef() const;
+
+  // Returns true if the object should self-delete.
+  bool Release() const;
+
+ private:
+  mutable int ref_count_;
+#ifndef NDEBUG
+  mutable bool in_dtor_;
+#endif
+
+  DFAKE_MUTEX(add_release_);
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
+};
+
+class BASE_EXPORT RefCountedThreadSafeBase {
+ public:
+  bool HasOneRef() const;
+
+ protected:
+  RefCountedThreadSafeBase();
+  ~RefCountedThreadSafeBase();
+
+  void AddRef() const;
+
+  // Returns true if the object should self-delete.
+  bool Release() const;
+
+ private:
+  mutable AtomicRefCount ref_count_;
+#ifndef NDEBUG
+  mutable bool in_dtor_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
+};
+
+}  // namespace subtle
+
+//
+// A base class for reference counted classes.  Otherwise, known as a cheap
+// knock-off of WebKit's RefCounted<T> class.  To use this guy just extend your
+// class from it like so:
+//
+//   class MyFoo : public base::RefCounted<MyFoo> {
+//    ...
+//    private:
+//     friend class base::RefCounted<MyFoo>;
+//     ~MyFoo();
+//   };
+//
+// You should always make your destructor private, to avoid any code deleting
+// the object accidently while there are references to it.
+template <class T>
+class RefCounted : public subtle::RefCountedBase {
+ public:
+  RefCounted() {}
+
+  void AddRef() const {
+    subtle::RefCountedBase::AddRef();
+  }
+
+  void Release() const {
+    if (subtle::RefCountedBase::Release()) {
+      delete static_cast<const T*>(this);
+    }
+  }
+
+ protected:
+  ~RefCounted() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
+};
+
+// Forward declaration.
+template <class T, typename Traits> class RefCountedThreadSafe;
+
+// Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
+// count reaches 0.  Overload to delete it on a different thread etc.
+template<typename T>
+struct DefaultRefCountedThreadSafeTraits {
+  static void Destruct(const T* x) {
+    // Delete through RefCountedThreadSafe to make child classes only need to be
+    // friend with RefCountedThreadSafe instead of this struct, which is an
+    // implementation detail.
+    RefCountedThreadSafe<T,
+                         DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
+  }
+};
+
+//
+// A thread-safe variant of RefCounted<T>
+//
+//   class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
+//    ...
+//   };
+//
+// If you're using the default trait, then you should add compile time
+// asserts that no one else is deleting your object.  i.e.
+//    private:
+//     friend class base::RefCountedThreadSafe<MyFoo>;
+//     ~MyFoo();
+template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
+class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
+ public:
+  RefCountedThreadSafe() {}
+
+  void AddRef() const {
+    subtle::RefCountedThreadSafeBase::AddRef();
+  }
+
+  void Release() const {
+    if (subtle::RefCountedThreadSafeBase::Release()) {
+      Traits::Destruct(static_cast<const T*>(this));
+    }
+  }
+
+ protected:
+  ~RefCountedThreadSafe() {}
+
+ private:
+  friend struct DefaultRefCountedThreadSafeTraits<T>;
+  static void DeleteInternal(const T* x) { delete x; }
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
+};
+
+//
+// A wrapper for some piece of data so we can place other things in
+// scoped_refptrs<>.
+//
+template<typename T>
+class RefCountedData : public base::RefCounted< base::RefCountedData<T> > {
+ public:
+  RefCountedData() : data() {}
+  RefCountedData(const T& in_value) : data(in_value) {}
+
+  T data;
+
+ private:
+  friend class base::RefCounted<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_)
+      ptr_->AddRef();
+  }
+
+  scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
+    if (ptr_)
+      ptr_->AddRef();
+  }
+
+  template <typename U>
+  scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
+    if (ptr_)
+      ptr_->AddRef();
+  }
+
+  ~scoped_refptr() {
+    if (ptr_)
+      ptr_->Release();
+  }
+
+  T* get() const { return ptr_; }
+  operator T*() const { return ptr_; }
+  T* operator->() const {
+    assert(ptr_ != NULL);
+    return ptr_;
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  T* release() WARN_UNUSED_RESULT {
+    T* retVal = ptr_;
+    ptr_ = NULL;
+    return retVal;
+  }
+
+  scoped_refptr<T>& operator=(T* p) {
+    // AddRef first so that self assignment should work
+    if (p)
+      p->AddRef();
+    T* old_ptr = ptr_;
+    ptr_ = p;
+    if (old_ptr)
+      old_ptr->Release();
+    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();
+  }
+
+  void swap(T** pp) {
+    T* p = ptr_;
+    ptr_ = *pp;
+    *pp = p;
+  }
+
+  void swap(scoped_refptr<T>& r) {
+    swap(&r.ptr_);
+  }
+
+ protected:
+  T* ptr_;
+};
+
+// 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);
+}
+
+#endif  // BASE_MEMORY_REF_COUNTED_H_
diff --git a/base/memory/ref_counted_memory.cc b/base/memory/ref_counted_memory.cc
new file mode 100644
index 0000000..9bcde32
--- /dev/null
+++ b/base/memory/ref_counted_memory.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 "base/memory/ref_counted_memory.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+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::TakeVector(
+    std::vector<unsigned char>* to_destroy) {
+  RefCountedBytes* bytes = new RefCountedBytes;
+  bytes->data_.swap(*to_destroy);
+  return bytes;
+}
+
+const unsigned char* RefCountedBytes::front() const {
+  // STL will assert if we do front() on an empty vector, but calling code
+  // expects a NULL.
+  return size() ? &data_.front() : NULL;
+}
+
+size_t RefCountedBytes::size() const {
+  return data_.size();
+}
+
+RefCountedBytes::~RefCountedBytes() {}
+
+RefCountedString::RefCountedString() {}
+
+RefCountedString::~RefCountedString() {}
+
+// static
+RefCountedString* RefCountedString::TakeString(std::string* to_destroy) {
+  RefCountedString* self = new RefCountedString;
+  to_destroy->swap(self->data_);
+  return self;
+}
+
+const unsigned char* RefCountedString::front() const {
+  return data_.empty() ? NULL :
+         reinterpret_cast<const unsigned char*>(data_.data());
+}
+
+size_t RefCountedString::size() const {
+  return data_.size();
+}
+
+}  //  namespace base
diff --git a/base/memory/ref_counted_memory.h b/base/memory/ref_counted_memory.h
new file mode 100644
index 0000000..9edcd6f
--- /dev/null
+++ b/base/memory/ref_counted_memory.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 BASE_MEMORY_REF_COUNTED_MEMORY_H_
+#define BASE_MEMORY_REF_COUNTED_MEMORY_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+// A generic interface to memory. This object is reference counted because one
+// of its two subclasses own the data they carry, and we need to have
+// heterogeneous containers of these two types of memory.
+class BASE_EXPORT RefCountedMemory
+    : public base::RefCountedThreadSafe<RefCountedMemory> {
+ public:
+  // Retrieves a pointer to the beginning of the data we point to. If the data
+  // is empty, this will return NULL.
+  virtual const unsigned char* front() const = 0;
+
+  // Size of the memory pointed to.
+  virtual size_t size() const = 0;
+
+ 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 unsigned char* data, size_t length)
+      : data_(length ? data : NULL), length_(length) {}
+
+  // Overridden from RefCountedMemory:
+  virtual const unsigned char* front() const OVERRIDE;
+  virtual size_t size() const OVERRIDE;
+
+ private:
+  virtual ~RefCountedStaticMemory();
+
+  const unsigned char* data_;
+  size_t length_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedStaticMemory);
+};
+
+// An implementation of RefCountedMemory, where we own our the data in a
+// vector.
+class BASE_EXPORT RefCountedBytes : public RefCountedMemory {
+ public:
+  RefCountedBytes();
+
+  // Constructs a RefCountedBytes object by _copying_ from |initializer|.
+  RefCountedBytes(const std::vector<unsigned char>& initializer);
+
+  // Constructs a RefCountedBytes object by performing a swap. (To non
+  // destructively build a RefCountedBytes, use the constructor that takes a
+  // vector.)
+  static RefCountedBytes* TakeVector(std::vector<unsigned char>* to_destroy);
+
+  // Overridden from RefCountedMemory:
+  virtual const unsigned char* front() const OVERRIDE;
+  virtual size_t size() const OVERRIDE;
+
+  const std::vector<unsigned char>& data() const { return data_; }
+  std::vector<unsigned char>& data() { return data_; }
+
+ private:
+  virtual ~RefCountedBytes();
+
+  std::vector<unsigned char> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedBytes);
+};
+
+// An implementation of RefCountedMemory, where the bytes are stored in an STL
+// string. Use this if your data naturally arrives in that format.
+class BASE_EXPORT RefCountedString : public RefCountedMemory {
+ public:
+  RefCountedString();
+
+  // Constructs a RefCountedString object by performing a swap. (To non
+  // destructively build a RefCountedString, use the default constructor and
+  // copy into object->data()).
+  static RefCountedString* TakeString(std::string* to_destroy);
+
+  // Overridden from RefCountedMemory:
+  virtual const unsigned char* front() const OVERRIDE;
+  virtual size_t size() const OVERRIDE;
+
+  const std::string& data() const { return data_; }
+  std::string& data() { return data_; }
+
+ private:
+  virtual ~RefCountedString();
+
+  std::string data_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedString);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_REF_COUNTED_MEMORY_H_
diff --git a/base/memory/ref_counted_memory_unittest.cc b/base/memory/ref_counted_memory_unittest.cc
new file mode 100644
index 0000000..1936040
--- /dev/null
+++ b/base/memory/ref_counted_memory_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/memory/ref_counted_memory.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(RefCountedMemoryUnitTest, RefCountedStaticMemory) {
+  scoped_refptr<RefCountedMemory> mem = new RefCountedStaticMemory(
+      reinterpret_cast<const uint8*>("static mem00"), 10);
+
+  EXPECT_EQ(10U, mem->size());
+  EXPECT_EQ("static mem",
+            std::string(reinterpret_cast<const char*>(mem->front()),
+                        mem->size()));
+}
+
+TEST(RefCountedMemoryUnitTest, RefCountedBytes) {
+  std::vector<uint8> data;
+  data.push_back(45);
+  data.push_back(99);
+  scoped_refptr<RefCountedMemory> mem = RefCountedBytes::TakeVector(&data);
+
+  EXPECT_EQ(0U, data.size());
+
+  EXPECT_EQ(2U, mem->size());
+  EXPECT_EQ(45U, mem->front()[0]);
+  EXPECT_EQ(99U, mem->front()[1]);
+}
+
+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]);
+}
+
+}  //  namespace base
diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc
new file mode 100644
index 0000000..8ddd5be
--- /dev/null
+++ b/base/memory/ref_counted_unittest.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class SelfAssign : public base::RefCounted<SelfAssign> {
+  friend class base::RefCounted<SelfAssign>;
+
+  ~SelfAssign() {}
+};
+
+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()
+      : ALLOW_THIS_IN_INITIALIZER_LIST(self_ptr_(this)) {
+  }
+
+  static bool was_destroyed() { return was_destroyed_; }
+
+  void SelfDestruct() { self_ptr_ = NULL; }
+
+ private:
+  friend class base::RefCounted<ScopedRefPtrToSelf>;
+  ~ScopedRefPtrToSelf() { was_destroyed_ = true; }
+
+  static bool was_destroyed_;
+
+  scoped_refptr<ScopedRefPtrToSelf> self_ptr_;
+};
+
+bool ScopedRefPtrToSelf::was_destroyed_ = false;
+
+}  // 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, ScopedRefPtrToSelf) {
+  ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
+  EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
+  check->SelfDestruct();
+  EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
+}
diff --git a/base/memory/scoped_generic_obj.h b/base/memory/scoped_generic_obj.h
new file mode 100644
index 0000000..4b3cb86
--- /dev/null
+++ b/base/memory/scoped_generic_obj.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_MEMORY_SCOPED_GENERIC_OBJ_H_
+#define BASE_MEMORY_SCOPED_GENERIC_OBJ_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+// ScopedGenericObj<> is patterned after scoped_ptr_malloc<>, except
+// that it assumes the template argument is typedef'ed to a pointer
+// type. It does not support retain/release semantics. It takes as its
+// second template argument a functor which frees the object.
+//
+// Example (Mac-specific):
+//
+// class ScopedDestroyRendererInfo {
+//  public:
+//   void operator()(CGLRendererInfoObj x) const {
+//     CGLDestroyRendererInfo(x);
+//   }
+// };
+//
+// ...
+//
+//   CGLRendererInfoObj renderer_info = NULL;
+//   ...
+//   ScopedGenericObj<CGLRendererInfoObj, ScopedDestroyRendererInfo>
+//       scoper(renderer_info);
+
+template<class C, class FreeProc>
+class ScopedGenericObj {
+ public:
+
+  // The element type
+  typedef C element_type;
+
+  // Constructor.  Defaults to initializing with NULL.
+  // There is no way to create an uninitialized ScopedGenericObj.
+  // The input parameter must be allocated with an allocator that matches the
+  // Free functor.
+  explicit ScopedGenericObj(C p = C()): obj_(p) {}
+
+  // Destructor.  If there is a C object, call the Free functor.
+  ~ScopedGenericObj() {
+    reset();
+  }
+
+  // Reset.  Calls the Free functor on the current owned object, if any.
+  // Then takes ownership of a new object, if given.
+  // this->reset(this->get()) works.
+  void reset(C p = C()) {
+    if (obj_ != p) {
+      FreeProc free_proc;
+      free_proc(obj_);
+      obj_ = p;
+    }
+  }
+
+  operator C() const {
+    return obj_;
+  }
+
+  C get() const {
+    return obj_;
+  }
+
+  // Comparison operators.
+  // These return whether a ScopedGenericObj and a plain pointer refer
+  // to the same object, not just to two different but equal objects.
+  // For compatibility with the boost-derived implementation, these
+  // take non-const arguments.
+  bool operator==(C p) const {
+    return obj_ == p;
+  }
+
+  bool operator!=(C p) const {
+    return obj_ != p;
+  }
+
+  // Swap two ScopedGenericObjs.
+  void swap(ScopedGenericObj& b) {
+    C tmp = b.obj_;
+    b.obj_ = obj_;
+    obj_ = tmp;
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  C release() WARN_UNUSED_RESULT {
+    C tmp = obj_;
+    obj_ = NULL;
+    return tmp;
+  }
+
+ private:
+  C obj_;
+
+  // no reason to use these: each ScopedGenericObj should have its own object.
+  template <class C2, class GP>
+  bool operator==(ScopedGenericObj<C2, GP> const& p) const;
+  template <class C2, class GP>
+  bool operator!=(ScopedGenericObj<C2, GP> const& p) const;
+
+  // Disallow evil constructors.
+  ScopedGenericObj(const ScopedGenericObj&);
+  void operator=(const ScopedGenericObj&);
+};
+
+template<class C, class FP> inline
+void swap(ScopedGenericObj<C, FP>& a, ScopedGenericObj<C, FP>& b) {
+  a.swap(b);
+}
+
+template<class C, class FP> inline
+bool operator==(C* p, const ScopedGenericObj<C, FP>& b) {
+  return p == b.get();
+}
+
+template<class C, class FP> inline
+bool operator!=(C* p, const ScopedGenericObj<C, FP>& b) {
+  return p != b.get();
+}
+
+#endif  // BASE_MEMORY_SCOPED_GENERIC_OBJ_H_
diff --git a/base/memory/scoped_handle.h b/base/memory/scoped_handle.h
new file mode 100644
index 0000000..b95559d
--- /dev/null
+++ b/base/memory/scoped_handle.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SCOPED_HANDLE_H_
+#define BASE_MEMORY_SCOPED_HANDLE_H_
+
+#include <stdio.h>
+
+#include "base/basictypes.h"
+
+class ScopedStdioHandle {
+ public:
+  ScopedStdioHandle()
+      : handle_(NULL) { }
+
+  explicit ScopedStdioHandle(FILE* handle)
+      : handle_(handle) { }
+
+  ~ScopedStdioHandle() {
+    Close();
+  }
+
+  void Close() {
+    if (handle_) {
+      fclose(handle_);
+      handle_ = NULL;
+    }
+  }
+
+  FILE* get() const { return handle_; }
+
+  FILE* Take() {
+    FILE* temp = handle_;
+    handle_ = NULL;
+    return temp;
+  }
+
+  void Set(FILE* newhandle) {
+    Close();
+    handle_ = newhandle;
+  }
+
+ private:
+  FILE* handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedStdioHandle);
+};
+
+#endif  // BASE_MEMORY_SCOPED_HANDLE_H_
diff --git a/base/memory/scoped_nsobject.h b/base/memory/scoped_nsobject.h
new file mode 100644
index 0000000..5d98e3f
--- /dev/null
+++ b/base/memory/scoped_nsobject.h
@@ -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.
+
+#ifndef BASE_MEMORY_SCOPED_NSOBJECT_H_
+#define BASE_MEMORY_SCOPED_NSOBJECT_H_
+
+#import <Foundation/Foundation.h>
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_policy.h"
+
+// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership
+// of an NSObject subclass object.  Style deviations here are solely for
+// compatibility with scoped_ptr<>'s interface, with which everyone is already
+// familiar.
+//
+// By default, 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. This behavior is parametrized by the |OwnershipPolicy| enum.
+// If the value |RETAIN| is passed (in the constructor or in reset()), then
+// scoped_nsobject<> will call -retain on the object, and the initial
+// ownership is not changed.
+//
+// scoped_nsprotocol<> has the same behavior as scoped_nsobject, but can be used
+// with protocols.
+//
+// scoped_nsobject<> is not to be used for NSAutoreleasePools. For
+// NSAutoreleasePools use ScopedNSAutoreleasePool from
+// scoped_nsautorelease_pool.h instead.
+// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile
+// time with a template specialization (see below).
+
+template<typename NST>
+class scoped_nsprotocol {
+ public:
+  explicit scoped_nsprotocol(
+      NST object = nil,
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : object_(object) {
+    if (policy == base::scoped_policy::RETAIN)
+      [object retain];
+  }
+
+  scoped_nsprotocol(const scoped_nsprotocol<NST>& that)
+      : object_([that.object_ retain]) {
+  }
+
+  ~scoped_nsprotocol() {
+    [object_ release];
+  }
+
+  scoped_nsprotocol& operator=(const scoped_nsprotocol<NST>& that) {
+    reset(that.get(), base::scoped_policy::RETAIN);
+    return *this;
+  }
+
+  void reset(NST object = nil,
+             base::scoped_policy::OwnershipPolicy policy =
+                base::scoped_policy::ASSUME) {
+    if (policy == base::scoped_policy::RETAIN)
+      [object retain];
+    // We intentionally do not check that object != object_ as the caller must
+    // either already have an ownership claim over whatever it passes to this
+    // method, or call it with the |RETAIN| policy which will have ensured that
+    // the object is retained once more when reaching this point.
+    [object_ release];
+    object_ = object;
+  }
+
+  bool operator==(NST that) const { return object_ == that; }
+  bool operator!=(NST that) const { return object_ != that; }
+
+  operator NST() const {
+    return object_;
+  }
+
+  NST get() const {
+    return object_;
+  }
+
+  void swap(scoped_nsprotocol& that) {
+    NST temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  // scoped_nsprotocol<>::release() is like scoped_ptr<>::release.  It is NOT a
+  // wrapper for [object_ release].  To force a scoped_nsprotocol<> to call
+  // [object_ release], use scoped_nsprotocol<>::reset().
+  NST release() WARN_UNUSED_RESULT {
+    NST temp = object_;
+    object_ = nil;
+    return temp;
+  }
+
+  // Shift reference to the autorelease pool to be released later.
+  NST autorelease() {
+    return [release() autorelease];
+  }
+
+ private:
+  NST object_;
+};
+
+// Free functions
+template <class C>
+void swap(scoped_nsprotocol<C>& p1, scoped_nsprotocol<C>& p2) {
+  p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C p1, const scoped_nsprotocol<C>& p2) {
+  return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C p1, const scoped_nsprotocol<C>& p2) {
+  return p1 != p2.get();
+}
+
+template<typename NST>
+class scoped_nsobject : public scoped_nsprotocol<NST*> {
+ public:
+  explicit scoped_nsobject(
+      NST* object = nil,
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : scoped_nsprotocol<NST*>(object, policy) {
+  }
+
+  scoped_nsobject(const scoped_nsobject<NST>& that)
+      : scoped_nsprotocol<NST*>(that) {
+  }
+
+  scoped_nsobject& operator=(const scoped_nsobject<NST>& that) {
+    scoped_nsprotocol<NST*>::operator=(that);
+    return *this;
+  }
+};
+
+// Specialization to make scoped_nsobject<id> work.
+template<>
+class scoped_nsobject<id> : public scoped_nsprotocol<id> {
+ public:
+  explicit scoped_nsobject(
+      id object = nil,
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : scoped_nsprotocol<id>(object, policy) {
+  }
+
+  scoped_nsobject(const scoped_nsobject<id>& that)
+      : scoped_nsprotocol<id>(that) {
+  }
+
+  scoped_nsobject& operator=(const scoped_nsobject<id>& that) {
+    scoped_nsprotocol<id>::operator=(that);
+    return *this;
+  }
+};
+
+// Do not use scoped_nsobject for NSAutoreleasePools, use
+// ScopedNSAutoreleasePool instead. This is a compile time check. See details
+// at top of header.
+template<>
+class scoped_nsobject<NSAutoreleasePool> {
+ private:
+  explicit scoped_nsobject(NSAutoreleasePool* object = nil,
+                           base::scoped_policy::OwnershipPolicy policy =
+                               base::scoped_policy::ASSUME);
+  DISALLOW_COPY_AND_ASSIGN(scoped_nsobject);
+};
+#endif  // BASE_MEMORY_SCOPED_NSOBJECT_H_
diff --git a/base/memory/scoped_nsobject_unittest.mm b/base/memory/scoped_nsobject_unittest.mm
new file mode 100644
index 0000000..377a3de
--- /dev/null
+++ b/base/memory/scoped_nsobject_unittest.mm
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/memory/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(ScopedNSObjectTest, ScopedNSObject) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  ASSERT_TRUE(p1.get());
+  ASSERT_EQ(1u, [p1 retainCount]);
+  scoped_nsobject<NSObject> p2(p1);
+  ASSERT_EQ(p1.get(), p2.get());
+  ASSERT_EQ(2u, [p1 retainCount]);
+  p2.reset();
+  ASSERT_EQ(nil, p2.get());
+  ASSERT_EQ(1u, [p1 retainCount]);
+  {
+    scoped_nsobject<NSObject> p3 = p1;
+    ASSERT_EQ(p1.get(), p3.get());
+    ASSERT_EQ(2u, [p1 retainCount]);
+    p3 = p1;
+    ASSERT_EQ(p1.get(), p3.get());
+    ASSERT_EQ(2u, [p1 retainCount]);
+  }
+  ASSERT_EQ(1u, [p1 retainCount]);
+  scoped_nsobject<NSObject> p4(p1.get(), base::scoped_policy::RETAIN);
+  ASSERT_EQ(2u, [p1 retainCount]);
+  ASSERT_TRUE(p1 == p1.get());
+  ASSERT_TRUE(p1 == p1);
+  ASSERT_FALSE(p1 != p1);
+  ASSERT_FALSE(p1 != p1.get());
+  scoped_nsobject<NSObject> p5([[NSObject alloc] init]);
+  ASSERT_TRUE(p1 != p5);
+  ASSERT_TRUE(p1 != p5.get());
+  ASSERT_FALSE(p1 == p5);
+  ASSERT_FALSE(p1 == p5.get());
+
+  scoped_nsobject<NSObject> p6 = p1;
+  ASSERT_EQ(3u, [p6 retainCount]);
+  {
+    base::mac::ScopedNSAutoreleasePool pool;
+    p6.autorelease();
+    ASSERT_EQ(nil, p6.get());
+    ASSERT_EQ(3u, [p1 retainCount]);
+  }
+  ASSERT_EQ(2u, [p1 retainCount]);
+}
+
+TEST(ScopedNSObjectTest, ScopedNSObjectInContainer) {
+  scoped_nsobject<id> p([[NSObject alloc] init]);
+  ASSERT_TRUE(p.get());
+  ASSERT_EQ(1u, [p retainCount]);
+  {
+    std::vector<scoped_nsobject<id> > objects;
+    objects.push_back(p);
+    ASSERT_EQ(2u, [p retainCount]);
+    ASSERT_EQ(p.get(), objects[0].get());
+    objects.push_back(scoped_nsobject<id>([[NSObject alloc] init]));
+    ASSERT_TRUE(objects[1].get());
+    ASSERT_EQ(1u, [objects[1] retainCount]);
+  }
+  ASSERT_EQ(1u, [p retainCount]);
+}
+
+TEST(ScopedNSObjectTest, ScopedNSObjectFreeFunctions) {
+  scoped_nsobject<id> p1([[NSObject alloc] init]);
+  id o1 = p1.get();
+  ASSERT_TRUE(o1 == p1);
+  ASSERT_FALSE(o1 != p1);
+  scoped_nsobject<id> p2([[NSObject alloc] init]);
+  ASSERT_TRUE(o1 != p2);
+  ASSERT_FALSE(o1 == p2);
+  id o2 = p2.get();
+  swap(p1, p2);
+  ASSERT_EQ(o2, p1.get());
+  ASSERT_EQ(o1, p2.get());
+}
+
+}  // namespace
diff --git a/base/memory/scoped_open_process.h b/base/memory/scoped_open_process.h
new file mode 100644
index 0000000..93ba387
--- /dev/null
+++ b/base/memory/scoped_open_process.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_MEMORY_SCOPED_OPEN_PROCESS_H_
+#define BASE_MEMORY_SCOPED_OPEN_PROCESS_H_
+
+#include "base/process.h"
+#include "base/process_util.h"
+
+namespace base {
+
+// A class that opens a process from its process id and closes it when the
+// instance goes out of scope.
+class ScopedOpenProcess {
+ public:
+  ScopedOpenProcess() : handle_(kNullProcessHandle) {
+  }
+
+  // Automatically close the process.
+  ~ScopedOpenProcess() {
+    Close();
+  }
+
+  // Open a new process by pid. Closes any previously opened process (even if
+  // opening the new one fails).
+  bool Open(ProcessId pid) {
+    Close();
+    return OpenProcessHandle(pid, &handle_);
+  }
+
+  // Close the previously opened process.
+  void Close() {
+    if (handle_ == kNullProcessHandle)
+      return;
+
+    CloseProcessHandle(handle_);
+    handle_ = kNullProcessHandle;
+  }
+
+  ProcessHandle handle() const { return handle_; }
+
+ private:
+  ProcessHandle handle_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedOpenProcess);
+};
+}  // namespace base
+
+#endif  // BASE_MEMORY_SCOPED_OPEN_PROCESS_H_
diff --git a/base/memory/scoped_policy.h b/base/memory/scoped_policy.h
new file mode 100644
index 0000000..5dbf204
--- /dev/null
+++ b/base/memory/scoped_policy.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SCOPED_POLICY_H_
+#define BASE_MEMORY_SCOPED_POLICY_H_
+
+namespace base {
+namespace scoped_policy {
+
+// Defines the ownership policy for a scoped object.
+enum OwnershipPolicy {
+  // The scoped object takes ownership of an object by taking over an existing
+  // ownership claim.
+  ASSUME,
+
+  // The scoped object will retain the the object and any initial ownership is
+  // not changed.
+  RETAIN
+};
+
+}  // namespace scoped_policy
+}  // namespace base
+
+#endif  // BASE_MEMORY_SCOPED_POLICY_H_
diff --git a/base/memory/scoped_ptr.h b/base/memory/scoped_ptr.h
new file mode 100644
index 0000000..3547b7a
--- /dev/null
+++ b/base/memory/scoped_ptr.h
@@ -0,0 +1,524 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Scopers help you manage ownership of a pointer, helping you easily manage the
+// a pointer within a scope, and automatically destroying the pointer at the
+// end of a scope.  There are two main classes you will use, which correspond
+// to the operators new/delete and new[]/delete[].
+//
+// Example usage (scoped_ptr):
+//   {
+//     scoped_ptr<Foo> foo(new Foo("wee"));
+//   }  // foo goes out of scope, releasing the pointer with it.
+//
+//   {
+//     scoped_ptr<Foo> foo;          // No pointer managed.
+//     foo.reset(new Foo("wee"));    // Now a pointer is managed.
+//     foo.reset(new Foo("wee2"));   // Foo("wee") was destroyed.
+//     foo.reset(new Foo("wee3"));   // Foo("wee2") was destroyed.
+//     foo->Method();                // Foo::Method() called.
+//     foo.get()->Method();          // Foo::Method() called.
+//     SomeFunc(foo.release());      // SomeFunc takes ownership, foo no longer
+//                                   // manages a pointer.
+//     foo.reset(new Foo("wee4"));   // foo manages a pointer again.
+//     foo.reset();                  // Foo("wee4") destroyed, foo no longer
+//                                   // manages a pointer.
+//   }  // foo wasn't managing a pointer, so nothing was destroyed.
+//
+// Example usage (scoped_array):
+//   {
+//     scoped_array<Foo> foo(new Foo[100]);
+//     foo.get()->Method();  // Foo::Method on the 0th element.
+//     foo[10].Method();     // Foo::Method on the 10th element.
+//   }
+//
+// These scopers also implement part of the functionality of C++11 unique_ptr
+// in that they are "movable but not copyable."  You can use the scopers in
+// the parameter and return types of functions to signify ownership transfer
+// in to and out of a function.  When calling a function that has a scoper
+// as the argument type, it must be called with the result of an analogous
+// scoper's Pass() function or another function that generates a temporary;
+// passing by copy will NOT work.  Here is an example using scoped_ptr:
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) {
+//     // Do something with arg
+//   }
+//   scoped_ptr<Foo> CreateFoo() {
+//     // No need for calling Pass() because we are constructing a temporary
+//     // for the return value.
+//     return scoped_ptr<Foo>(new Foo("new"));
+//   }
+//   scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
+//     return arg.Pass();
+//   }
+//
+//   {
+//     scoped_ptr<Foo> ptr(new Foo("yay"));  // ptr manages Foo("yay").
+//     TakesOwnership(ptr.Pass());           // ptr no longer owns Foo("yay").
+//     scoped_ptr<Foo> ptr2 = CreateFoo();   // ptr2 owns the return Foo.
+//     scoped_ptr<Foo> ptr3 =                // ptr3 now owns what was in ptr2.
+//         PassThru(ptr2.Pass());            // ptr2 is correspondingly NULL.
+//   }
+//
+// Notice that if you do not call Pass() when returning from PassThru(), or
+// when invoking TakesOwnership(), the code will not compile because scopers
+// are not copyable; they only implement move semantics which require calling
+// the Pass() function to signify a destructive transfer of state. CreateFoo()
+// is different though because we are constructing a temporary on the return
+// line and thus can avoid needing to call Pass().
+//
+// Pass() properly handles upcast in assignment, i.e. you can assign
+// scoped_ptr<Child> to scoped_ptr<Parent>:
+//
+//   scoped_ptr<Foo> foo(new Foo());
+//   scoped_ptr<FooParent> parent = foo.Pass();
+//
+// PassAs<>() should be used to upcast return value in return statement:
+//
+//   scoped_ptr<Foo> CreateFoo() {
+//     scoped_ptr<FooChild> result(new FooChild());
+//     return result.PassAs<Foo>();
+//   }
+//
+// Note that PassAs<>() is implemented only for scoped_ptr, but not for
+// scoped_array. This is because casting array pointers may not be safe.
+
+#ifndef BASE_MEMORY_SCOPED_PTR_H_
+#define BASE_MEMORY_SCOPED_PTR_H_
+
+// This is an implementation designed to match the anticipated future TR2
+// implementation of the scoped_ptr class, and its closely-related brethren,
+// scoped_array, scoped_ptr_malloc.
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/move.h"
+#include "base/template_util.h"
+
+namespace base {
+
+namespace subtle {
+class RefCountedBase;
+class RefCountedThreadSafeBase;
+}  // namespace subtle
+
+namespace internal {
+
+template <typename T> struct IsNotRefCounted {
+  enum {
+    value = !base::is_convertible<T*, base::subtle::RefCountedBase*>::value &&
+        !base::is_convertible<T*, base::subtle::RefCountedThreadSafeBase*>::
+            value
+  };
+};
+
+}  // namespace internal
+}  // namespace base
+
+// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
+// automatically deletes the pointer it holds (if any).
+// That is, scoped_ptr<T> owns the T object that it points to.
+// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
+// Also like T*, scoped_ptr<T> is thread-compatible, and once you
+// dereference it, you get the thread safety guarantees of T.
+//
+// The size of a scoped_ptr is small:
+// sizeof(scoped_ptr<C>) == sizeof(C*)
+template <class C>
+class scoped_ptr {
+  MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+
+  COMPILE_ASSERT(base::internal::IsNotRefCounted<C>::value,
+                 C_is_refcounted_type_and_needs_scoped_refptr);
+
+ public:
+
+  // The element type
+  typedef C element_type;
+
+  // Constructor.  Defaults to initializing with NULL.
+  // There is no way to create an uninitialized scoped_ptr.
+  // The input parameter must be allocated with new.
+  explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
+
+  // Constructor.  Allows construction from a scoped_ptr rvalue for a
+  // convertible type.
+  template <typename U>
+  scoped_ptr(scoped_ptr<U> other) : ptr_(other.release()) { }
+
+  // Constructor.  Move constructor for C++03 move emulation of this type.
+  scoped_ptr(RValue rvalue)
+      : ptr_(rvalue.object->release()) {
+  }
+
+  // Destructor.  If there is a C object, delete it.
+  // We don't need to test ptr_ == NULL because C++ does that for us.
+  ~scoped_ptr() {
+    enum { type_must_be_complete = sizeof(C) };
+    delete ptr_;
+  }
+
+  // operator=.  Allows assignment from a scoped_ptr rvalue for a convertible
+  // type.
+  template <typename U>
+  scoped_ptr& operator=(scoped_ptr<U> rhs) {
+    reset(rhs.release());
+    return *this;
+  }
+
+  // operator=.  Move operator= for C++03 move emulation of this type.
+  scoped_ptr& operator=(RValue rhs) {
+    swap(*rhs->object);
+    return *this;
+  }
+
+  // Reset.  Deletes the current owned object, if any.
+  // Then takes ownership of a new object, if given.
+  // this->reset(this->get()) works.
+  void reset(C* p = NULL) {
+    if (p != ptr_) {
+      enum { type_must_be_complete = sizeof(C) };
+      delete ptr_;
+      ptr_ = p;
+    }
+  }
+
+  // Accessors to get the owned object.
+  // operator* and operator-> will assert() if there is no current object.
+  C& operator*() const {
+    assert(ptr_ != NULL);
+    return *ptr_;
+  }
+  C* operator->() const  {
+    assert(ptr_ != NULL);
+    return ptr_;
+  }
+  C* get() const { return ptr_; }
+
+  // Allow scoped_ptr<C> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+  typedef C* scoped_ptr::*Testable;
+  operator Testable() const { return ptr_ ? &scoped_ptr::ptr_ : NULL; }
+
+  // Comparison operators.
+  // These return whether two scoped_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(C* p) const { return ptr_ == p; }
+  bool operator!=(C* p) const { return ptr_ != p; }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr& p2) {
+    C* tmp = ptr_;
+    ptr_ = p2.ptr_;
+    p2.ptr_ = tmp;
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  C* release() WARN_UNUSED_RESULT {
+    C* retVal = ptr_;
+    ptr_ = NULL;
+    return retVal;
+  }
+
+  template <typename PassAsType>
+  scoped_ptr<PassAsType> PassAs() {
+    return scoped_ptr<PassAsType>(release());
+  }
+
+ private:
+  C* ptr_;
+
+  // Forbid comparison of scoped_ptr types.  If C2 != C, it totally doesn't
+  // make sense, and if C2 == C, it still doesn't make sense because you should
+  // never have the same object owned by two different scoped_ptrs.
+  template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
+  template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
+
+};
+
+// Free functions
+template <class C>
+void swap(scoped_ptr<C>& p1, scoped_ptr<C>& p2) {
+  p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C* p1, const scoped_ptr<C>& p2) {
+  return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C* p1, const scoped_ptr<C>& p2) {
+  return p1 != p2.get();
+}
+
+// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
+// with new [] and the destructor deletes objects with delete [].
+//
+// As with scoped_ptr<C>, a scoped_array<C> either points to an object
+// or is NULL.  A scoped_array<C> owns the object that it points to.
+// scoped_array<T> is thread-compatible, and once you index into it,
+// the returned objects have only the thread safety guarantees of T.
+//
+// Size: sizeof(scoped_array<C>) == sizeof(C*)
+template <class C>
+class scoped_array {
+  MOVE_ONLY_TYPE_FOR_CPP_03(scoped_array, RValue)
+
+ public:
+
+  // The element type
+  typedef C element_type;
+
+  // Constructor.  Defaults to initializing with NULL.
+  // There is no way to create an uninitialized scoped_array.
+  // The input parameter must be allocated with new [].
+  explicit scoped_array(C* p = NULL) : array_(p) { }
+
+  // Constructor.  Move constructor for C++03 move emulation of this type.
+  scoped_array(RValue rvalue)
+      : array_(rvalue.object->release()) {
+  }
+
+  // Destructor.  If there is a C object, delete it.
+  // We don't need to test ptr_ == NULL because C++ does that for us.
+  ~scoped_array() {
+    enum { type_must_be_complete = sizeof(C) };
+    delete[] array_;
+  }
+
+  // operator=.  Move operator= for C++03 move emulation of this type.
+  scoped_array& operator=(RValue rhs) {
+    swap(*rhs.object);
+    return *this;
+  }
+
+  // Reset.  Deletes the current owned object, if any.
+  // Then takes ownership of a new object, if given.
+  // this->reset(this->get()) works.
+  void reset(C* p = NULL) {
+    if (p != array_) {
+      enum { type_must_be_complete = sizeof(C) };
+      delete[] array_;
+      array_ = p;
+    }
+  }
+
+  // Get one element of the current object.
+  // Will assert() if there is no current object, or index i is negative.
+  C& operator[](ptrdiff_t i) const {
+    assert(i >= 0);
+    assert(array_ != NULL);
+    return array_[i];
+  }
+
+  // Get a pointer to the zeroth element of the current object.
+  // If there is no current object, return NULL.
+  C* get() const {
+    return array_;
+  }
+
+  // Allow scoped_array<C> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+  typedef C* scoped_array::*Testable;
+  operator Testable() const { return array_ ? &scoped_array::array_ : NULL; }
+
+  // Comparison operators.
+  // These return whether two scoped_array refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(C* p) const { return array_ == p; }
+  bool operator!=(C* p) const { return array_ != p; }
+
+  // Swap two scoped arrays.
+  void swap(scoped_array& p2) {
+    C* tmp = array_;
+    array_ = p2.array_;
+    p2.array_ = tmp;
+  }
+
+  // Release an array.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  C* release() WARN_UNUSED_RESULT {
+    C* retVal = array_;
+    array_ = NULL;
+    return retVal;
+  }
+
+ private:
+  C* array_;
+
+  // Forbid comparison of different scoped_array types.
+  template <class C2> bool operator==(scoped_array<C2> const& p2) const;
+  template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
+};
+
+// Free functions
+template <class C>
+void swap(scoped_array<C>& p1, scoped_array<C>& p2) {
+  p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C* p1, const scoped_array<C>& p2) {
+  return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C* p1, const scoped_array<C>& p2) {
+  return p1 != p2.get();
+}
+
+// This class wraps the c library function free() in a class that can be
+// passed as a template argument to scoped_ptr_malloc below.
+class ScopedPtrMallocFree {
+ public:
+  inline void operator()(void* x) const {
+    free(x);
+  }
+};
+
+// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
+// second template argument, the functor used to free the object.
+
+template<class C, class FreeProc = ScopedPtrMallocFree>
+class scoped_ptr_malloc {
+  MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr_malloc, RValue)
+
+ public:
+
+  // The element type
+  typedef C element_type;
+
+  // Constructor.  Defaults to initializing with NULL.
+  // There is no way to create an uninitialized scoped_ptr.
+  // The input parameter must be allocated with an allocator that matches the
+  // Free functor.  For the default Free functor, this is malloc, calloc, or
+  // realloc.
+  explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {}
+
+  // Constructor.  Move constructor for C++03 move emulation of this type.
+  scoped_ptr_malloc(RValue rvalue)
+      : ptr_(rvalue.object->release()) {
+  }
+
+  // Destructor.  If there is a C object, call the Free functor.
+  ~scoped_ptr_malloc() {
+    reset();
+  }
+
+  // operator=.  Move operator= for C++03 move emulation of this type.
+  scoped_ptr_malloc& operator=(RValue rhs) {
+    swap(*rhs.object);
+    return *this;
+  }
+
+  // Reset.  Calls the Free functor on the current owned object, if any.
+  // Then takes ownership of a new object, if given.
+  // this->reset(this->get()) works.
+  void reset(C* p = NULL) {
+    if (ptr_ != p) {
+      FreeProc free_proc;
+      free_proc(ptr_);
+      ptr_ = p;
+    }
+  }
+
+  // Get the current object.
+  // operator* and operator-> will cause an assert() failure if there is
+  // no current object.
+  C& operator*() const {
+    assert(ptr_ != NULL);
+    return *ptr_;
+  }
+
+  C* operator->() const {
+    assert(ptr_ != NULL);
+    return ptr_;
+  }
+
+  C* get() const {
+    return ptr_;
+  }
+
+  // Allow scoped_ptr_malloc<C> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+  typedef C* scoped_ptr_malloc::*Testable;
+  operator Testable() const { return ptr_ ? &scoped_ptr_malloc::ptr_ : NULL; }
+
+  // Comparison operators.
+  // These return whether a scoped_ptr_malloc and a plain pointer refer
+  // to the same object, not just to two different but equal objects.
+  // For compatibility with the boost-derived implementation, these
+  // take non-const arguments.
+  bool operator==(C* p) const {
+    return ptr_ == p;
+  }
+
+  bool operator!=(C* p) const {
+    return ptr_ != p;
+  }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr_malloc & b) {
+    C* tmp = b.ptr_;
+    b.ptr_ = ptr_;
+    ptr_ = tmp;
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  C* release() WARN_UNUSED_RESULT {
+    C* tmp = ptr_;
+    ptr_ = NULL;
+    return tmp;
+  }
+
+ private:
+  C* ptr_;
+
+  // no reason to use these: each scoped_ptr_malloc should have its own object
+  template <class C2, class GP>
+  bool operator==(scoped_ptr_malloc<C2, GP> const& p) const;
+  template <class C2, class GP>
+  bool operator!=(scoped_ptr_malloc<C2, GP> const& p) const;
+};
+
+template<class C, class FP> inline
+void swap(scoped_ptr_malloc<C, FP>& a, scoped_ptr_malloc<C, FP>& b) {
+  a.swap(b);
+}
+
+template<class C, class FP> inline
+bool operator==(C* p, const scoped_ptr_malloc<C, FP>& b) {
+  return p == b.get();
+}
+
+template<class C, class FP> inline
+bool operator!=(C* p, const scoped_ptr_malloc<C, FP>& b) {
+  return p != b.get();
+}
+
+// A function to convert T* into scoped_ptr<T>
+// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+scoped_ptr<T> make_scoped_ptr(T* ptr) {
+  return scoped_ptr<T>(ptr);
+}
+
+#endif  // BASE_MEMORY_SCOPED_PTR_H_
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
new file mode 100644
index 0000000..3da6f15
--- /dev/null
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -0,0 +1,359 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Used to test depth subtyping.
+class ConDecLoggerParent {
+ public:
+  virtual ~ConDecLoggerParent() {}
+
+  virtual void SetPtr(int* ptr) = 0;
+
+  virtual int SomeMeth(int x) const = 0;
+};
+
+class ConDecLogger : public ConDecLoggerParent {
+ public:
+  ConDecLogger() : ptr_(NULL) { }
+  explicit ConDecLogger(int* ptr) { SetPtr(ptr); }
+  virtual ~ConDecLogger() { --*ptr_; }
+
+  virtual void SetPtr(int* ptr) OVERRIDE { ptr_ = ptr; ++*ptr_; }
+
+  virtual int SomeMeth(int x) const OVERRIDE { return x; }
+
+ private:
+  int* ptr_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConDecLogger);
+};
+
+scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
+  return logger.Pass();
+}
+
+void GrabAndDrop(scoped_ptr<ConDecLogger> logger) {
+}
+
+// Do not delete this function!  It's existence is to test that you can
+// return a temporarily constructed version of the scoper.
+scoped_ptr<ConDecLogger> TestReturnOfType(int* constructed) {
+  return scoped_ptr<ConDecLogger>(new ConDecLogger(constructed));
+}
+
+scoped_ptr<ConDecLoggerParent> UpcastUsingPassAs(
+    scoped_ptr<ConDecLogger> object) {
+  return object.PassAs<ConDecLoggerParent>();
+}
+
+}  // namespace
+
+TEST(ScopedPtrTest, ScopedPtr) {
+  int constructed = 0;
+
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    EXPECT_EQ(10, scoper->SomeMeth(10));
+    EXPECT_EQ(10, scoper.get()->SomeMeth(10));
+    EXPECT_EQ(10, (*scoper).SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test reset() and release()
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoper.reset(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoper.reset();
+    EXPECT_EQ(0, constructed);
+    EXPECT_FALSE(scoper.get());
+
+    scoper.reset(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    ConDecLogger* take = scoper.release();
+    EXPECT_EQ(1, constructed);
+    EXPECT_FALSE(scoper.get());
+    delete take;
+    EXPECT_EQ(0, constructed);
+
+    scoper.reset(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test swap(), == and !=
+  {
+    scoped_ptr<ConDecLogger> scoper1;
+    scoped_ptr<ConDecLogger> scoper2;
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoper1.reset(logger);
+    EXPECT_EQ(logger, scoper1.get());
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(logger, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
+  int constructed = 0;
+
+  // Test construction from a scoped_ptr to a derived class.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<ConDecLoggerParent> scoper_parent(scoper.Pass());
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_parent.get());
+    EXPECT_FALSE(scoper.get());
+
+    EXPECT_EQ(10, scoper_parent->SomeMeth(10));
+    EXPECT_EQ(10, scoper_parent.get()->SomeMeth(10));
+    EXPECT_EQ(10, (*scoper_parent).SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test assignment from a scoped_ptr to a derived class.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<ConDecLoggerParent> scoper_parent;
+    scoper_parent = scoper.Pass();
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_parent.get());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test construction of a scoped_ptr with an additional const annotation.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<const ConDecLogger> scoper_const(scoper.Pass());
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_const.get());
+    EXPECT_FALSE(scoper.get());
+
+    EXPECT_EQ(10, scoper_const->SomeMeth(10));
+    EXPECT_EQ(10, scoper_const.get()->SomeMeth(10));
+    EXPECT_EQ(10, (*scoper_const).SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test assignment to a scoped_ptr with an additional const annotation.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<const ConDecLogger> scoper_const;
+    scoper_const = scoper.Pass();
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_const.get());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, ScopedArray) {
+  static const int kNumLoggers = 12;
+
+  int constructed = 0;
+
+  {
+    scoped_array<ConDecLogger> scoper(new ConDecLogger[kNumLoggers]);
+    EXPECT_TRUE(scoper.get());
+    EXPECT_EQ(&scoper[0], scoper.get());
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+
+    EXPECT_EQ(10, scoper.get()->SomeMeth(10));
+    EXPECT_EQ(10, scoper[2].SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test reset() and release()
+  {
+    scoped_array<ConDecLogger> scoper;
+    EXPECT_FALSE(scoper.get());
+    EXPECT_FALSE(scoper.release());
+    EXPECT_FALSE(scoper.get());
+    scoper.reset();
+    EXPECT_FALSE(scoper.get());
+
+    scoper.reset(new ConDecLogger[kNumLoggers]);
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+    scoper.reset();
+    EXPECT_EQ(0, constructed);
+
+    scoper.reset(new ConDecLogger[kNumLoggers]);
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+    ConDecLogger* ptr = scoper.release();
+    EXPECT_EQ(12, constructed);
+    delete[] ptr;
+    EXPECT_EQ(0, constructed);
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test swap(), == and !=
+  {
+    scoped_array<ConDecLogger> scoper1;
+    scoped_array<ConDecLogger> scoper2;
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
+    for (int i = 0; i < kNumLoggers; ++i) {
+      loggers[i].SetPtr(&constructed);
+    }
+    scoper1.reset(loggers);
+    EXPECT_EQ(loggers, scoper1.get());
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(loggers, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, PassBehavior) {
+  int constructed = 0;
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Test Pass() with constructor;
+    scoped_ptr<ConDecLogger> scoper2(scoper.Pass());
+    EXPECT_EQ(1, constructed);
+
+    // Test Pass() with assignment;
+    scoped_ptr<ConDecLogger> scoper3;
+    scoper3 = scoper2.Pass();
+    EXPECT_EQ(1, constructed);
+    EXPECT_FALSE(scoper.get());
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_TRUE(scoper3.get());
+  }
+
+  // Test uncaught Pass() does not leak.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Should auto-destruct logger by end of scope.
+    scoper.Pass();
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test that passing to function which does nothing does not leak.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Should auto-destruct logger by end of scope.
+    GrabAndDrop(scoper.Pass());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, ReturnTypeBehavior) {
+  int constructed = 0;
+
+  // Test that we can return a scoped_ptr.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    PassThru(scoper.Pass());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test uncaught return type not leak.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Should auto-destruct logger by end of scope.
+    PassThru(scoper.Pass());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Call TestReturnOfType() so the compiler doesn't warn for an unused
+  // function.
+  {
+    TestReturnOfType(&constructed);
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, PassAs) {
+  int constructed = 0;
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<ConDecLoggerParent> scoper_parent;
+    scoper_parent = UpcastUsingPassAs(scoper.Pass());
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_parent.get());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+// TODO scoped_ptr_malloc
diff --git a/base/memory/scoped_ptr_unittest.nc b/base/memory/scoped_ptr_unittest.nc
new file mode 100644
index 0000000..30a332e
--- /dev/null
+++ b/base/memory/scoped_ptr_unittest.nc
@@ -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.
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/ref_counted.h"
+
+namespace {
+
+class Parent {
+};
+
+class Child : public Parent {
+};
+
+class RefCountedClass : public base::RefCountedThreadSafe<RefCountedClass> {
+};
+
+}  // namespace
+
+#if defined(NCTEST_NO_PASSAS_DOWNCAST)  // [r"invalid conversion from"]
+
+scoped_ptr<Child> DowncastUsingPassAs(scoped_ptr<Parent> object) {
+  return object.PassAs<Child>();
+}
+
+#elif defined(NCTEST_NO_REF_COUNTED_SCOPED_PTR)  // [r"creating array with negative size"]
+
+// scoped_ptr<> should not work for ref-counted objects.
+void WontCompile() {
+  scoped_ptr<RefCountedClass> x;
+}
+
+#endif
diff --git a/base/memory/scoped_vector.h b/base/memory/scoped_vector.h
new file mode 100644
index 0000000..feb0321
--- /dev/null
+++ b/base/memory/scoped_vector.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SCOPED_VECTOR_H_
+#define BASE_MEMORY_SCOPED_VECTOR_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/move.h"
+#include "base/stl_util.h"
+
+// ScopedVector wraps a vector deleting the elements from its
+// destructor.
+template <class T>
+class ScopedVector {
+  MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue)
+
+ public:
+  typedef typename std::vector<T*>::allocator_type allocator_type;
+  typedef typename std::vector<T*>::size_type size_type;
+  typedef typename std::vector<T*>::difference_type difference_type;
+  typedef typename std::vector<T*>::pointer pointer;
+  typedef typename std::vector<T*>::const_pointer const_pointer;
+  typedef typename std::vector<T*>::reference reference;
+  typedef typename std::vector<T*>::const_reference const_reference;
+  typedef typename std::vector<T*>::value_type value_type;
+  typedef typename std::vector<T*>::iterator iterator;
+  typedef typename std::vector<T*>::const_iterator const_iterator;
+  typedef typename std::vector<T*>::reverse_iterator reverse_iterator;
+  typedef typename std::vector<T*>::const_reverse_iterator
+      const_reverse_iterator;
+
+  ScopedVector() {}
+  ~ScopedVector() { clear(); }
+  ScopedVector(RValue other) { swap(*other.object); }
+
+  ScopedVector& operator=(RValue rhs) {
+    swap(*rhs.object);
+    return *this;
+  }
+
+  T*& operator[](size_t index) { return v_[index]; }
+  const T* 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); }
+
+  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); }
+  void resize(size_t new_size) { v_.resize(new_size); }
+
+  template<typename InputIterator>
+  void assign(InputIterator begin, InputIterator end) {
+    v_.assign(begin, end);
+  }
+
+  void clear() { STLDeleteElements(&v_); }
+
+  // Like |clear()|, but doesn't delete any elements.
+  void weak_clear() { v_.clear(); }
+
+  // Lets the ScopedVector take ownership of |x|.
+  iterator insert(iterator position, T* x) {
+    return v_.insert(position, x);
+  }
+
+  // Lets the ScopedVector take ownership of elements in [first,last).
+  template<typename InputIterator>
+  void insert(iterator position, InputIterator first, InputIterator last) {
+    v_.insert(position, first, last);
+  }
+
+  iterator erase(iterator position) {
+    delete *position;
+    return v_.erase(position);
+  }
+
+  iterator erase(iterator first, iterator last) {
+    STLDeleteContainerPointers(first, last);
+    return v_.erase(first, last);
+  }
+
+  // Like |erase()|, but doesn't delete the element at |position|.
+  iterator weak_erase(iterator position) {
+    return v_.erase(position);
+  }
+
+  // Like |erase()|, but doesn't delete the elements in [first, last).
+  iterator weak_erase(iterator first, iterator last) {
+    return v_.erase(first, last);
+  }
+
+ private:
+  std::vector<T*> v_;
+};
+
+#endif  // BASE_MEMORY_SCOPED_VECTOR_H_
diff --git a/base/memory/scoped_vector_unittest.cc b/base/memory/scoped_vector_unittest.cc
new file mode 100644
index 0000000..03774c5
--- /dev/null
+++ b/base/memory/scoped_vector_unittest.cc
@@ -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.
+
+#include "base/memory/scoped_vector.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// The LifeCycleObject notifies its Observer upon construction & destruction.
+class LifeCycleObject {
+ public:
+  class Observer {
+   public:
+    virtual void OnLifeCycleConstruct(LifeCycleObject* o) = 0;
+    virtual void OnLifeCycleDestroy(LifeCycleObject* o) = 0;
+
+   protected:
+    virtual ~Observer() {}
+  };
+
+  explicit LifeCycleObject(Observer* observer)
+      : observer_(observer) {
+    observer_->OnLifeCycleConstruct(this);
+  }
+
+  ~LifeCycleObject() {
+    observer_->OnLifeCycleDestroy(this);
+  }
+
+ private:
+  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),
+        constructed_life_cycle_object_(NULL) {}
+  virtual ~LifeCycleWatcher() {}
+
+  // Assert INITIAL -> CONSTRUCTED and no LifeCycleObject associated with this
+  // LifeCycleWatcher.
+  virtual 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.
+  virtual 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);
+  }
+
+ private:
+  LifeCycleState life_cycle_state_;
+  scoped_ptr<LifeCycleObject> constructed_life_cycle_object_;
+
+  DISALLOW_COPY_AND_ASSIGN(LifeCycleWatcher);
+};
+
+TEST(ScopedVectorTest, LifeCycleWatcher) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  LifeCycleObject* object = watcher.NewLifeCycleObject();
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  delete object;
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+TEST(ScopedVectorTest, 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());
+  scoped_vector.clear();
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+  EXPECT_EQ(static_cast<size_t>(0), scoped_vector.size());
+}
+
+TEST(ScopedVectorTest, WeakClear) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+  scoped_ptr<LifeCycleObject> object(watcher.NewLifeCycleObject());
+  scoped_vector.push_back(object.get());
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  scoped_vector.weak_clear();
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_EQ(static_cast<size_t>(0), scoped_vector.size());
+}
+
+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_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());
+
+    ScopedVector<LifeCycleObject> scoped_vector_copy(scoped_vector.Pass());
+    EXPECT_TRUE(scoped_vector.empty());
+    EXPECT_FALSE(scoped_vector_copy.empty());
+
+    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());
+
+    scoped_vector_assign = scoped_vector.Pass();
+    EXPECT_TRUE(scoped_vector.empty());
+    EXPECT_FALSE(scoped_vector_assign.empty());
+
+    EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  }
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+class DeleteCounter {
+ public:
+  explicit DeleteCounter(int* deletes)
+      : deletes_(deletes) {
+  }
+
+  ~DeleteCounter() {
+    (*deletes_)++;
+  }
+
+  void VoidMethod0() {}
+
+ private:
+  int* const deletes_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteCounter);
+};
+
+template <typename T>
+ScopedVector<T> PassThru(ScopedVector<T> scoper) {
+  return scoper.Pass();
+}
+
+TEST(ScopedVectorTest, Passed) {
+  int deletes = 0;
+  ScopedVector<DeleteCounter> deleter_vector;
+  deleter_vector.push_back(new DeleteCounter(&deletes));
+  EXPECT_EQ(0, deletes);
+  base::Callback<ScopedVector<DeleteCounter>(void)> callback =
+      base::Bind(&PassThru<DeleteCounter>, base::Passed(&deleter_vector));
+  EXPECT_EQ(0, deletes);
+  ScopedVector<DeleteCounter> result = callback.Run();
+  EXPECT_EQ(0, deletes);
+  result.clear();
+  EXPECT_EQ(1, deletes);
+};
+
+TEST(ScopedVectorTest, InsertRange) {
+  LifeCycleWatcher watchers[5];
+
+  std::vector<LifeCycleObject*> vec;
+  for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers);
+      ++it) {
+    EXPECT_EQ(LC_INITIAL, it->life_cycle_state());
+    vec.push_back(it->NewLifeCycleObject());
+    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+  }
+  // Start scope for ScopedVector.
+  {
+    ScopedVector<LifeCycleObject> scoped_vector;
+    scoped_vector.insert(scoped_vector.end(), vec.begin() + 1, vec.begin() + 3);
+    for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers);
+        ++it)
+      EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+  }
+  for(LifeCycleWatcher* it = watchers; it != watchers + 1; ++it)
+    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+  for(LifeCycleWatcher* it = watchers + 1; it != watchers + 3; ++it)
+    EXPECT_EQ(LC_DESTROYED, it->life_cycle_state());
+  for(LifeCycleWatcher* it = watchers + 3; it != watchers + arraysize(watchers);
+      ++it)
+    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+}
+
+}  // namespace
diff --git a/base/memory/singleton.cc b/base/memory/singleton.cc
new file mode 100644
index 0000000..ee5e58d
--- /dev/null
+++ b/base/memory/singleton.cc
@@ -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.
+
+#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) {
+    value = subtle::NoBarrier_Load(instance);
+    if (value != kBeingCreatedMarker)
+      break;
+    PlatformThread::YieldCurrentThread();
+  }
+  return value;
+}
+
+}  // namespace internal
+}  // namespace base
+
diff --git a/base/memory/singleton.h b/base/memory/singleton.h
new file mode 100644
index 0000000..0d4fc89
--- /dev/null
+++ b/base/memory/singleton.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.
+
+// PLEASE READ: Do you really need a singleton?
+//
+// Singletons make it hard to determine the lifetime of an object, which can
+// lead to buggy code and spurious crashes.
+//
+// Instead of adding another singleton into the mix, try to identify either:
+//   a) An existing singleton that can manage your object's lifetime
+//   b) Locations where you can deterministically create the object and pass
+//      into other objects
+//
+// If you absolutely need a singleton, please keep them as trivial as possible
+// and ideally a leaf dependency. Singletons get problematic when they attempt
+// to do too much in their destructor or have circular dependencies.
+
+#ifndef BASE_MEMORY_SINGLETON_H_
+#define BASE_MEMORY_SINGLETON_H_
+
+#include "base/at_exit.h"
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/memory/aligned_memory.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+namespace internal {
+
+// Our AtomicWord doubles as a spinlock, where a value of
+// kBeingCreatedMarker means the spinlock is being held for creation.
+static const subtle::AtomicWord kBeingCreatedMarker = 1;
+
+// We pull out some of the functionality into a non-templated function, so that
+// we can implement the more complicated pieces out of line in the .cc file.
+BASE_EXPORT subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance);
+
+}  // namespace internal
+}  // namespace base
+
+// TODO(joth): Move more of this file into namespace base
+
+// Default traits for Singleton<Type>. Calls operator new and operator delete on
+// the object. Registers automatic deletion at process exit.
+// Overload if you need arguments or another memory allocation function.
+template<typename Type>
+struct DefaultSingletonTraits {
+  // Allocates the object.
+  static Type* New() {
+    // The parenthesis is very important here; it forces POD type
+    // initialization.
+    return new Type();
+  }
+
+  // Destroys the object.
+  static void Delete(Type* x) {
+    delete x;
+  }
+
+  // Set to true to automatically register deletion of the object on process
+  // exit. See below for the required call that makes this happen.
+  static const bool kRegisterAtExit = true;
+
+  // 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;
+};
+
+
+// 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;
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+};
+
+
+// Alternate traits for use with the Singleton<Type>.  Allocates memory
+// for the singleton instance from a static buffer.  The singleton will
+// be cleaned up at exit, but can't be revived after destruction unless
+// the Resurrect() method is called.
+//
+// This is useful for a certain category of things, notably logging and
+// tracing, where the singleton instance is of a type carefully constructed to
+// be safe to access post-destruction.
+// In logging and tracing you'll typically get stray calls at odd times, like
+// during static destruction, thread teardown and the like, and there's a
+// termination race on the heap-based singleton - e.g. if one thread calls
+// get(), but then another thread initiates AtExit processing, the first thread
+// may call into an object residing in unallocated memory. If the instance is
+// allocated from the data segment, then this is survivable.
+//
+// The destructor is to deallocate system resources, in this case to unregister
+// a callback the system will invoke when logging levels change. Note that
+// this is also used in e.g. Chrome Frame, where you have to allow for the
+// possibility of loading briefly into someone else's process space, and
+// so leaking is not an option, as that would sabotage the state of your host
+// process once you've unloaded.
+template <typename Type>
+struct StaticMemorySingletonTraits {
+  // WARNING: User has to deal with get() in the singleton class
+  // this is traits for returning NULL.
+  static Type* New() {
+    // Only constructs once and returns pointer; otherwise returns NULL.
+    if (base::subtle::NoBarrier_AtomicExchange(&dead_, 1))
+      return NULL;
+
+    return new(buffer_.void_data()) Type();
+  }
+
+  static void Delete(Type* p) {
+    if (p != NULL)
+      p->Type::~Type();
+  }
+
+  static const bool kRegisterAtExit = true;
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+
+  // Exposed for unittesting.
+  static void Resurrect() {
+    base::subtle::NoBarrier_Store(&dead_, 0);
+  }
+
+ private:
+  static base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
+  // Signal the object was already deleted, so it is not revived.
+  static base::subtle::Atomic32 dead_;
+};
+
+template <typename Type> base::AlignedMemory<sizeof(Type), ALIGNOF(Type)>
+    StaticMemorySingletonTraits<Type>::buffer_;
+template <typename Type> base::subtle::Atomic32
+    StaticMemorySingletonTraits<Type>::dead_ = 0;
+
+// The Singleton<Type, Traits, DifferentiatingType> class manages a single
+// instance of Type which will be created on first use and will be destroyed at
+// normal process exit). The Trait::Delete function will not be called on
+// abnormal process exit.
+//
+// DifferentiatingType is used as a key to differentiate two different
+// singletons having the same memory allocation functions but serving a
+// different purpose. This is mainly used for Locks serving different purposes.
+//
+// Example usage:
+//
+// In your header:
+//   template <typename T> struct DefaultSingletonTraits;
+//   class FooClass {
+//    public:
+//     static FooClass* GetInstance();  <-- See comment below on this.
+//     void Bar() { ... }
+//    private:
+//     FooClass() { ... }
+//     friend struct DefaultSingletonTraits<FooClass>;
+//
+//     DISALLOW_COPY_AND_ASSIGN(FooClass);
+//   };
+//
+// In your source file:
+//  #include "base/memory/singleton.h"
+//  FooClass* FooClass::GetInstance() {
+//    return Singleton<FooClass>::get();
+//  }
+//
+// And to call methods on FooClass:
+//   FooClass::GetInstance()->Bar();
+//
+// NOTE: The method accessing Singleton<T>::get() has to be named as GetInstance
+// and it is important that FooClass::GetInstance() is not inlined in the
+// header. This makes sure that when source files from multiple targets include
+// this header they don't end up with different copies of the inlined code
+// creating multiple copies of the singleton.
+//
+// Singleton<> has no non-static members and doesn't need to actually be
+// instantiated.
+//
+// This class is itself thread-safe. The underlying Type must of course be
+// thread-safe if you want to use it concurrently. Two parameters may be tuned
+// depending on the user's requirements.
+//
+// Glossary:
+//   RAE = kRegisterAtExit
+//
+// On every platform, if Traits::RAE is true, the singleton will be destroyed at
+// process exit. More precisely it uses base::AtExitManager which requires an
+// object of this type to be instantiated. AtExitManager mimics the semantics
+// of atexit() such as LIFO order but under Windows is safer to call. For more
+// information see at_exit.h.
+//
+// If Traits::RAE is false, the singleton will not be freed at process exit,
+// thus the singleton will be leaked if it is ever accessed. Traits::RAE
+// shouldn't be false unless absolutely necessary. Remember that the heap where
+// the object is allocated may be destroyed by the CRT anyway.
+//
+// Caveats:
+// (a) Every call to get(), operator->() and operator*() incurs some overhead
+//     (16ns on my P4/2.8GHz) to check whether the object has already been
+//     initialized.  You may wish to cache the result of get(); it will not
+//     change.
+//
+// (b) Your factory function must never throw an exception. This class is not
+//     exception-safe.
+//
+template <typename Type,
+          typename Traits = DefaultSingletonTraits<Type>,
+          typename DifferentiatingType = Type>
+class Singleton {
+ private:
+  // Classes using the Singleton<T> pattern should declare a GetInstance()
+  // method and call Singleton::get() from within that.
+  friend Type* Type::GetInstance();
+
+  // Allow TraceLog tests to test tracing after OnExit.
+  friend class DeleteTraceLogForTesting;
+
+  // This class is safe to be constructed and copy-constructed since it has no
+  // member.
+
+  // Return a pointer to the one true instance of the class.
+  static Type* get() {
+#ifndef NDEBUG
+    // Avoid making TLS lookup on release builds.
+    if (!Traits::kAllowedToAccessOnNonjoinableThread)
+      base::ThreadRestrictions::AssertSingletonAllowed();
+#endif
+
+    base::subtle::AtomicWord value = base::subtle::NoBarrier_Load(&instance_);
+    if (value != 0 && value != base::internal::kBeingCreatedMarker) {
+      // See the corresponding HAPPENS_BEFORE below.
+      ANNOTATE_HAPPENS_AFTER(&instance_);
+      return reinterpret_cast<Type*>(value);
+    }
+
+    // Object isn't created yet, maybe we will get to create it, let's try...
+    if (base::subtle::Acquire_CompareAndSwap(
+          &instance_, 0, base::internal::kBeingCreatedMarker) == 0) {
+      // instance_ was NULL and is now kBeingCreatedMarker.  Only one thread
+      // will ever get here.  Threads might be spinning on us, and they will
+      // stop right after we do this store.
+      Type* newval = Traits::New();
+
+      // This annotation helps race detectors recognize correct lock-less
+      // synchronization between different threads calling get().
+      // See the corresponding HAPPENS_AFTER below and above.
+      ANNOTATE_HAPPENS_BEFORE(&instance_);
+      base::subtle::Release_Store(
+          &instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
+
+      if (newval != NULL && Traits::kRegisterAtExit)
+        base::AtExitManager::RegisterCallback(OnExit, NULL);
+
+      return newval;
+    }
+
+    // We hit a race. Wait for the other thread to complete it.
+    value = base::internal::WaitForInstance(&instance_);
+
+    // See the corresponding HAPPENS_BEFORE above.
+    ANNOTATE_HAPPENS_AFTER(&instance_);
+    return reinterpret_cast<Type*>(value);
+  }
+
+  // Adapter function for use with AtExit().  This should be called single
+  // threaded, so don't use atomic operations.
+  // Calling OnExit while singleton is in use by other threads is a mistake.
+  static void OnExit(void* /*unused*/) {
+    // AtExit should only ever be register after the singleton instance was
+    // created.  We should only ever get here with a valid instance_ pointer.
+    Traits::Delete(
+        reinterpret_cast<Type*>(base::subtle::NoBarrier_Load(&instance_)));
+    instance_ = 0;
+  }
+  static base::subtle::AtomicWord instance_;
+};
+
+template <typename Type, typename Traits, typename DifferentiatingType>
+base::subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::
+    instance_ = 0;
+
+#endif  // BASE_MEMORY_SINGLETON_H_
diff --git a/base/memory/singleton_objc.h b/base/memory/singleton_objc.h
new file mode 100644
index 0000000..6df3f77
--- /dev/null
+++ b/base/memory/singleton_objc.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Support for using the Singleton<T> pattern with Objective-C objects.  A
+// SingletonObjC is the same as a Singleton, except the default traits are
+// appropriate for Objective-C objects.  A typical Objective-C object of type
+// NSExampleType can be maintained as a singleton and accessed with:
+//
+//   NSExampleType* exampleSingleton = SingletonObjC<NSExampleType>::get();
+//
+// The first time this is used, it will create exampleSingleton as the result
+// of [[NSExampleType alloc] init].  Subsequent calls will return the same
+// NSExampleType* object.  The object will be released by calling
+// -[NSExampleType release] when Singleton's atexit routines run
+// (see singleton.h).
+//
+// For Objective-C objects initialized through means other than the
+// no-parameter -init selector, DefaultSingletonObjCTraits may be extended
+// as needed:
+//
+//   struct FooSingletonTraits : public DefaultSingletonObjCTraits<Foo> {
+//     static Foo* New() {
+//       return [[Foo alloc] initWithName:@"selecty"];
+//     }
+//   };
+//   ...
+//   Foo* widgetSingleton = SingletonObjC<Foo, FooSingletonTraits>::get();
+
+#ifndef BASE_MEMORY_SINGLETON_OBJC_H_
+#define BASE_MEMORY_SINGLETON_OBJC_H_
+
+#import <Foundation/Foundation.h>
+#include "base/memory/singleton.h"
+
+// Singleton traits usable to manage traditional Objective-C objects, which
+// are instantiated by sending |alloc| and |init| messages, and are deallocated
+// in a memory-managed environment when their retain counts drop to 0 by
+// sending |release| messages.
+template<typename Type>
+struct DefaultSingletonObjCTraits : public DefaultSingletonTraits<Type> {
+  static Type* New() {
+    return [[Type alloc] init];
+  }
+
+  static void Delete(Type* object) {
+    [object release];
+  }
+};
+
+// Exactly like Singleton, but without the DefaultSingletonObjCTraits as the
+// default trait class.  This makes it straightforward for Objective-C++ code
+// to hold Objective-C objects as singletons.
+template<typename Type,
+         typename Traits = DefaultSingletonObjCTraits<Type>,
+         typename DifferentiatingType = Type>
+class SingletonObjC : public Singleton<Type, Traits, DifferentiatingType> {
+};
+
+#endif  // BASE_MEMORY_SINGLETON_OBJC_H_
diff --git a/base/memory/singleton_unittest.cc b/base/memory/singleton_unittest.cc
new file mode 100644
index 0000000..d9892cb
--- /dev/null
+++ b/base/memory/singleton_unittest.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/at_exit.h"
+#include "base/file_util.h"
+#include "base/memory/singleton.h"
+#include "base/path_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
+
+typedef void (*CallbackFunc)();
+
+class IntSingleton {
+ public:
+  static IntSingleton* GetInstance() {
+    return Singleton<IntSingleton>::get();
+  }
+
+  int value_;
+};
+
+class Init5Singleton {
+ public:
+  struct Trait;
+
+  static Init5Singleton* GetInstance() {
+    return Singleton<Init5Singleton, Trait>::get();
+  }
+
+  int value_;
+};
+
+struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
+  static Init5Singleton* New() {
+    Init5Singleton* instance = new Init5Singleton();
+    instance->value_ = 5;
+    return instance;
+  }
+};
+
+int* SingletonInt() {
+  return &IntSingleton::GetInstance()->value_;
+}
+
+int* SingletonInt5() {
+  return &Init5Singleton::GetInstance()->value_;
+}
+
+template <typename Type>
+struct CallbackTrait : public DefaultSingletonTraits<Type> {
+  static void Delete(Type* instance) {
+    if (instance->callback_)
+      (instance->callback_)();
+    DefaultSingletonTraits<Type>::Delete(instance);
+  }
+};
+
+class CallbackSingleton {
+ public:
+  CallbackSingleton() : callback_(NULL) { }
+  CallbackFunc callback_;
+};
+
+class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
+ public:
+  struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
+
+  CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
+
+  static CallbackSingletonWithNoLeakTrait* GetInstance() {
+    return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
+  }
+};
+
+class CallbackSingletonWithLeakTrait : public CallbackSingleton {
+ public:
+  struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
+    static const bool kRegisterAtExit = false;
+  };
+
+  CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
+
+  static CallbackSingletonWithLeakTrait* GetInstance() {
+    return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
+  }
+};
+
+class CallbackSingletonWithStaticTrait : public CallbackSingleton {
+ public:
+  struct Trait;
+
+  CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
+
+  static CallbackSingletonWithStaticTrait* GetInstance() {
+    return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
+  }
+};
+
+struct CallbackSingletonWithStaticTrait::Trait
+    : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
+  static void Delete(CallbackSingletonWithStaticTrait* instance) {
+    if (instance->callback_)
+      (instance->callback_)();
+    StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
+        instance);
+  }
+};
+
+template <class Type>
+class AlignedTestSingleton {
+ public:
+  AlignedTestSingleton() {}
+  ~AlignedTestSingleton() {}
+  static AlignedTestSingleton* GetInstance() {
+    return Singleton<AlignedTestSingleton,
+        StaticMemorySingletonTraits<AlignedTestSingleton> >::get();
+  }
+
+  Type type_;
+};
+
+
+void SingletonNoLeak(CallbackFunc CallOnQuit) {
+  CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
+}
+
+void SingletonLeak(CallbackFunc CallOnQuit) {
+  CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
+}
+
+CallbackFunc* GetLeakySingleton() {
+  return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
+}
+
+void DeleteLeakySingleton() {
+  DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
+      CallbackSingletonWithLeakTrait::GetInstance());
+}
+
+void SingletonStatic(CallbackFunc CallOnQuit) {
+  CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
+}
+
+CallbackFunc* GetStaticSingleton() {
+  return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
+}
+
+}  // namespace
+
+class SingletonTest : public testing::Test {
+ public:
+  SingletonTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    non_leak_called_ = false;
+    leaky_called_ = false;
+    static_called_ = false;
+  }
+
+ protected:
+  void VerifiesCallbacks() {
+    EXPECT_TRUE(non_leak_called_);
+    EXPECT_FALSE(leaky_called_);
+    EXPECT_TRUE(static_called_);
+    non_leak_called_ = false;
+    leaky_called_ = false;
+    static_called_ = false;
+  }
+
+  void VerifiesCallbacksNotCalled() {
+    EXPECT_FALSE(non_leak_called_);
+    EXPECT_FALSE(leaky_called_);
+    EXPECT_FALSE(static_called_);
+    non_leak_called_ = false;
+    leaky_called_ = false;
+    static_called_ = false;
+  }
+
+  static void CallbackNoLeak() {
+    non_leak_called_ = true;
+  }
+
+  static void CallbackLeak() {
+    leaky_called_ = true;
+  }
+
+  static void CallbackStatic() {
+    static_called_ = true;
+  }
+
+ private:
+  static bool non_leak_called_;
+  static bool leaky_called_;
+  static bool static_called_;
+};
+
+bool SingletonTest::non_leak_called_ = false;
+bool SingletonTest::leaky_called_ = false;
+bool SingletonTest::static_called_ = false;
+
+TEST_F(SingletonTest, Basic) {
+  int* singleton_int;
+  int* singleton_int_5;
+  CallbackFunc* leaky_singleton;
+  CallbackFunc* static_singleton;
+
+  {
+    base::ShadowingAtExitManager sem;
+    {
+      singleton_int = SingletonInt();
+    }
+    // Ensure POD type initialization.
+    EXPECT_EQ(*singleton_int, 0);
+    *singleton_int = 1;
+
+    EXPECT_EQ(singleton_int, SingletonInt());
+    EXPECT_EQ(*singleton_int, 1);
+
+    {
+      singleton_int_5 = SingletonInt5();
+    }
+    // Is default initialized to 5.
+    EXPECT_EQ(*singleton_int_5, 5);
+
+    SingletonNoLeak(&CallbackNoLeak);
+    SingletonLeak(&CallbackLeak);
+    SingletonStatic(&CallbackStatic);
+    static_singleton = GetStaticSingleton();
+    leaky_singleton = GetLeakySingleton();
+    EXPECT_TRUE(leaky_singleton);
+  }
+
+  // Verify that only the expected callback has been called.
+  VerifiesCallbacks();
+  // Delete the leaky singleton.
+  DeleteLeakySingleton();
+
+  // The static singleton can't be acquired post-atexit.
+  EXPECT_EQ(NULL, GetStaticSingleton());
+
+  {
+    base::ShadowingAtExitManager sem;
+    // Verifiy that the variables were reset.
+    {
+      singleton_int = SingletonInt();
+      EXPECT_EQ(*singleton_int, 0);
+    }
+    {
+      singleton_int_5 = SingletonInt5();
+      EXPECT_EQ(*singleton_int_5, 5);
+    }
+    {
+      // Resurrect the static singleton, and assert that it
+      // still points to the same (static) memory.
+      CallbackSingletonWithStaticTrait::Trait::Resurrect();
+      EXPECT_EQ(GetStaticSingleton(), static_singleton);
+    }
+  }
+  // The leaky singleton shouldn't leak since SingletonLeak has not been called.
+  VerifiesCallbacksNotCalled();
+}
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST_F(SingletonTest, Alignment) {
+  using base::AlignedMemory;
+
+  // Create some static singletons with increasing sizes and alignment
+  // requirements. By ordering this way, the linker will need to do some work to
+  // ensure proper alignment of the static data.
+  AlignedTestSingleton<int32>* align4 =
+      AlignedTestSingleton<int32>::GetInstance();
+  AlignedTestSingleton<AlignedMemory<32, 32> >* align32 =
+      AlignedTestSingleton<AlignedMemory<32, 32> >::GetInstance();
+  AlignedTestSingleton<AlignedMemory<128, 128> >* align128 =
+      AlignedTestSingleton<AlignedMemory<128, 128> >::GetInstance();
+  AlignedTestSingleton<AlignedMemory<4096, 4096> >* align4096 =
+      AlignedTestSingleton<AlignedMemory<4096, 4096> >::GetInstance();
+
+  EXPECT_ALIGNED(align4, 4);
+  EXPECT_ALIGNED(align32, 32);
+  EXPECT_ALIGNED(align128, 128);
+  EXPECT_ALIGNED(align4096, 4096);
+}
diff --git a/base/memory/weak_ptr.cc b/base/memory/weak_ptr.cc
new file mode 100644
index 0000000..9dec8fd
--- /dev/null
+++ b/base/memory/weak_ptr.cc
@@ -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.
+
+#include "base/memory/weak_ptr.h"
+
+namespace base {
+namespace internal {
+
+WeakReference::Flag::Flag() : is_valid_(true) {
+}
+
+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(thread_checker_.CalledOnValidThread() || HasOneRef());
+  is_valid_ = false;
+}
+
+bool WeakReference::Flag::IsValid() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return is_valid_;
+}
+
+WeakReference::Flag::~Flag() {
+}
+
+WeakReference::WeakReference() {
+}
+
+WeakReference::WeakReference(const Flag* flag) : flag_(flag) {
+}
+
+WeakReference::~WeakReference() {
+}
+
+bool WeakReference::is_valid() const {
+  return flag_ && flag_->IsValid();
+}
+
+WeakReferenceOwner::WeakReferenceOwner() {
+}
+
+WeakReferenceOwner::~WeakReferenceOwner() {
+  Invalidate();
+}
+
+WeakReference WeakReferenceOwner::GetRef() const {
+  // We also want to reattach to the current thread if all previous references
+  // have gone away.
+  if (!HasRefs())
+    flag_ = new WeakReference::Flag();
+  return WeakReference(flag_);
+}
+
+void WeakReferenceOwner::Invalidate() {
+  if (flag_) {
+    flag_->Invalidate();
+    flag_ = NULL;
+  }
+}
+
+WeakPtrBase::WeakPtrBase() {
+}
+
+WeakPtrBase::~WeakPtrBase() {
+}
+
+WeakPtrBase::WeakPtrBase(const WeakReference& ref) : ref_(ref) {
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h
new file mode 100644
index 0000000..7006fb6
--- /dev/null
+++ b/base/memory/weak_ptr.h
@@ -0,0 +1,343 @@
+// Copyright (c) 2012 The Chromium 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 help in cases where you have many objects referring back to a
+// shared object and you wish for the lifetime of the shared object to not be
+// bound to the lifetime of the referrers.  In other words, this is useful when
+// reference counting is not a good fit.
+//
+// A common alternative to weak pointers is to have the shared object hold a
+// list of all referrers, and then when the shared object is destroyed, it
+// calls a method on the referrers to tell them to drop their references.  This
+// approach also requires the referrers to tell the shared object when they get
+// destroyed so that the shared object can remove the referrer from its list of
+// referrers.  Such a solution works, but it is a bit complex.
+//
+// EXAMPLE:
+//
+//  class Controller : public SupportsWeakPtr<Controller> {
+//   public:
+//    void SpawnWorker() { Worker::StartNew(AsWeakPtr()); }
+//    void WorkComplete(const Result& result) { ... }
+//  };
+//
+//  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_;
+//  };
+//
+// Given the above classes, a consumer may allocate a Controller object, call
+// SpawnWorker several times, and then destroy the Controller object before all
+// of the workers have completed.  Because the Worker class only holds a weak
+// pointer to the Controller, we don't have to worry about the Worker
+// dereferencing the Controller back pointer after the Controller has been
+// destroyed.
+//
+// ------------------------ Thread-safety notes ------------------------
+// When you get a WeakPtr (from a WeakPtrFactory or SupportsWeakPtr), if it's
+// the only one pointing to the object, the object become bound to the
+// current thread, as well as this WeakPtr and all later ones get created.
+//
+// You may only dereference the WeakPtr on the thread it binds to. However, it
+// is safe to destroy the WeakPtr object on another thread. Because of this,
+// querying WeakPtrFactory's HasWeakPtrs() method can be racy.
+//
+// On the other hand, the object that supports WeakPtr (extends SupportsWeakPtr)
+// can only be deleted from the thread it binds to, until all WeakPtrs are
+// deleted.
+//
+// Calling SupportsWeakPtr::DetachFromThread() can work around the limitations
+// above and cancel the thread binding of the object and all WeakPtrs pointing
+// to it, but it's not recommended and unsafe.
+//
+// WeakPtrs may be copy-constructed or assigned on threads other than the thread
+// they are bound to. This does not change the thread binding. So these WeakPtrs
+// may only be dereferenced on the thread that the original WeakPtr was bound
+// to.
+
+#ifndef BASE_MEMORY_WEAK_PTR_H_
+#define BASE_MEMORY_WEAK_PTR_H_
+
+#include "base/basictypes.h"
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/template_util.h"
+#include "base/threading/thread_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:
+  // While Flag is bound to a specific thread, it may be deleted from another
+  // via base::WeakPtr::~WeakPtr().
+  class Flag : public RefCountedThreadSafe<Flag> {
+   public:
+    Flag();
+
+    void Invalidate();
+    bool IsValid() const;
+
+    void DetachFromThread() { thread_checker_.DetachFromThread(); }
+
+   private:
+    friend class base::RefCountedThreadSafe<Flag>;
+
+    ~Flag();
+
+    ThreadChecker thread_checker_;
+    bool is_valid_;
+  };
+
+  WeakReference();
+  explicit WeakReference(const Flag* flag);
+  ~WeakReference();
+
+  bool is_valid() const;
+
+ private:
+  scoped_refptr<const Flag> flag_;
+};
+
+class BASE_EXPORT WeakReferenceOwner {
+ public:
+  WeakReferenceOwner();
+  ~WeakReferenceOwner();
+
+  WeakReference GetRef() const;
+
+  bool HasRefs() const {
+    return flag_.get() && !flag_->HasOneRef();
+  }
+
+  void Invalidate();
+
+  // Indicates that this object will be used on another thread from now on.
+  void DetachFromThread() {
+    if (flag_) flag_->DetachFromThread();
+  }
+
+ private:
+  mutable scoped_refptr<WeakReference::Flag> flag_;
+};
+
+// This class simplifies the implementation of WeakPtr's type conversion
+// constructor by avoiding the need for a public accessor for ref_.  A
+// WeakPtr<T> cannot access the private members of WeakPtr<U>, so this
+// base class gives us a way to access ref_ in a protected fashion.
+class BASE_EXPORT WeakPtrBase {
+ public:
+  WeakPtrBase();
+  ~WeakPtrBase();
+
+ protected:
+  explicit WeakPtrBase(const WeakReference& ref);
+
+  WeakReference ref_;
+};
+
+// This class provides a common implementation of common functions that would
+// otherwise get instantiated separately for each distinct instantiation of
+// SupportsWeakPtr<>.
+class SupportsWeakPtrBase {
+ public:
+  // A safe static downcast of a WeakPtr<Base> to WeakPtr<Derived>. This
+  // conversion will only compile if there is exists a Base which inherits
+  // from SupportsWeakPtr<Base>. See base::AsWeakPtr() below for a helper
+  // function that makes calling this easier.
+  template<typename Derived>
+  static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
+    typedef
+        is_convertible<Derived, internal::SupportsWeakPtrBase&> convertible;
+    COMPILE_ASSERT(convertible::value,
+                   AsWeakPtr_argument_inherits_from_SupportsWeakPtr);
+    return AsWeakPtrImpl<Derived>(t, *t);
+  }
+
+ private:
+  // This template function uses type inference to find a Base of Derived
+  // which is an instance of SupportsWeakPtr<Base>. We can then safely
+  // static_cast the Base* to a Derived*.
+  template <typename Derived, typename Base>
+  static WeakPtr<Derived> AsWeakPtrImpl(
+      Derived* t, const SupportsWeakPtr<Base>&) {
+    WeakPtr<Base> ptr = t->Base::AsWeakPtr();
+    return WeakPtr<Derived>(ptr.ref_, static_cast<Derived*>(ptr.ptr_));
+  }
+};
+
+}  // namespace internal
+
+template <typename T> class WeakPtrFactory;
+
+// The WeakPtr class holds a weak reference to |T*|.
+//
+// This class is designed to be used like a normal pointer.  You should always
+// null-test an object of this class before using it or invoking a method that
+// may result in the underlying object being destroyed.
+//
+// EXAMPLE:
+//
+//   class Foo { ... };
+//   WeakPtr<Foo> foo;
+//   if (foo)
+//     foo->method();
+//
+template <typename T>
+class WeakPtr : public internal::WeakPtrBase {
+ public:
+  WeakPtr() : ptr_(NULL) {
+  }
+
+  // Allow conversion from U to T provided U "is a" T.
+  template <typename U>
+  WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.get()) {
+  }
+
+  T* get() const { return ref_.is_valid() ? ptr_ : NULL; }
+  operator T*() const { return get(); }
+
+  T& operator*() const {
+    DCHECK(get() != NULL);
+    return *get();
+  }
+  T* operator->() const {
+    DCHECK(get() != NULL);
+    return get();
+  }
+
+  void reset() {
+    ref_ = internal::WeakReference();
+    ptr_ = NULL;
+  }
+
+ private:
+  friend class internal::SupportsWeakPtrBase;
+  friend class SupportsWeakPtr<T>;
+  friend class WeakPtrFactory<T>;
+
+  WeakPtr(const internal::WeakReference& ref, T* ptr)
+      : WeakPtrBase(ref),
+        ptr_(ptr) {
+  }
+
+  // This pointer is only valid when ref_.is_valid() is true.  Otherwise, its
+  // value is undefined (as opposed to NULL).
+  T* ptr_;
+};
+
+// A class may extend from SupportsWeakPtr to expose weak pointers to itself.
+// This is useful in cases where you want others to be able to get a weak
+// pointer to your class.  It also has the property that you don't need to
+// initialize it from your constructor.
+template <class T>
+class SupportsWeakPtr : public internal::SupportsWeakPtrBase {
+ public:
+  SupportsWeakPtr() {}
+
+  WeakPtr<T> AsWeakPtr() {
+    return WeakPtr<T>(weak_reference_owner_.GetRef(), static_cast<T*>(this));
+  }
+
+  // Indicates that this object will be used on another thread from now on.
+  void DetachFromThread() {
+    weak_reference_owner_.DetachFromThread();
+  }
+
+ 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);
+}
+
+// A class may alternatively be composed of a WeakPtrFactory and thereby
+// control how it exposes weak pointers to itself.  This is helpful if you only
+// need weak pointers within the implementation of a class.  This class is also
+// useful when working with primitive types.  For example, you could have a
+// WeakPtrFactory<bool> that is used to pass around a weak reference to a bool.
+template <class T>
+class WeakPtrFactory {
+ public:
+  explicit WeakPtrFactory(T* ptr) : ptr_(ptr) {
+  }
+
+  ~WeakPtrFactory() {
+    ptr_ = NULL;
+  }
+
+  WeakPtr<T> GetWeakPtr() {
+    DCHECK(ptr_);
+    return WeakPtr<T>(weak_reference_owner_.GetRef(), ptr_);
+  }
+
+  // Call this method to invalidate all existing weak pointers.
+  void InvalidateWeakPtrs() {
+    DCHECK(ptr_);
+    weak_reference_owner_.Invalidate();
+  }
+
+  // Call this method to determine if any weak pointers exist.
+  bool HasWeakPtrs() const {
+    DCHECK(ptr_);
+    return weak_reference_owner_.HasRefs();
+  }
+
+  // Indicates that this object will be used on another thread from now on.
+  void DetachFromThread() {
+    DCHECK(ptr_);
+    weak_reference_owner_.DetachFromThread();
+  }
+
+ private:
+  internal::WeakReferenceOwner weak_reference_owner_;
+  T* ptr_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(WeakPtrFactory);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_WEAK_PTR_H_
diff --git a/base/memory/weak_ptr_unittest.cc b/base/memory/weak_ptr_unittest.cc
new file mode 100644
index 0000000..d5f8057
--- /dev/null
+++ b/base/memory/weak_ptr_unittest.cc
@@ -0,0 +1,477 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/weak_ptr.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+template <class T>
+class OffThreadObjectCreator {
+ public:
+  static T* NewObject() {
+    T* result;
+    {
+      Thread creator_thread("creator_thread");
+      creator_thread.Start();
+      creator_thread.message_loop()->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 : Base {};
+
+struct Target : SupportsWeakPtr<Target> {};
+struct DerivedTarget : Target {};
+struct Arrow {
+  WeakPtr<Target> target;
+};
+
+// 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") {}
+
+  virtual ~BackgroundThread() {
+    Stop();
+  }
+
+  void CreateArrowFromTarget(Arrow** arrow, Target* target) {
+    WaitableEvent completion(true, false);
+    message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(&BackgroundThread::DoCreateArrowFromTarget,
+                   arrow, target, &completion));
+    completion.Wait();
+  }
+
+  void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
+    WaitableEvent completion(true, false);
+    message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(&BackgroundThread::DoCreateArrowFromArrow,
+                   arrow, other, &completion));
+    completion.Wait();
+  }
+
+  void DeleteTarget(Target* object) {
+    WaitableEvent completion(true, false);
+    message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
+    completion.Wait();
+  }
+
+  void DeleteArrow(Arrow* object) {
+    WaitableEvent completion(true, false);
+    message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
+    completion.Wait();
+  }
+
+  Target* DeRef(const Arrow* arrow) {
+    WaitableEvent completion(true, false);
+    Target* result = NULL;
+    message_loop()->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 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, ptr2);
+}
+
+TEST(WeakPtrFactoryTest, OutOfScope) {
+  WeakPtr<int> ptr;
+  EXPECT_EQ(NULL, ptr.get());
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    ptr = factory.GetWeakPtr();
+  }
+  EXPECT_EQ(NULL, ptr.get());
+}
+
+TEST(WeakPtrFactoryTest, Multiple) {
+  WeakPtr<int> a, b;
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    a = factory.GetWeakPtr();
+    b = factory.GetWeakPtr();
+    EXPECT_EQ(&data, a.get());
+    EXPECT_EQ(&data, b.get());
+  }
+  EXPECT_EQ(NULL, a.get());
+  EXPECT_EQ(NULL, b.get());
+}
+
+TEST(WeakPtrFactoryTest, MultipleStaged) {
+  WeakPtr<int> a;
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    a = factory.GetWeakPtr();
+    {
+      WeakPtr<int> b = factory.GetWeakPtr();
+    }
+    EXPECT_TRUE(NULL != a.get());
+  }
+  EXPECT_EQ(NULL, a.get());
+}
+
+TEST(WeakPtrFactoryTest, Dereference) {
+  Base data;
+  data.member = "123456";
+  WeakPtrFactory<Base> factory(&data);
+  WeakPtr<Base> ptr = factory.GetWeakPtr();
+  EXPECT_EQ(&data, ptr.get());
+  EXPECT_EQ(data.member, (*ptr).member);
+  EXPECT_EQ(data.member, ptr->member);
+}
+
+TEST(WeakPtrFactoryTest, UpCast) {
+  Derived data;
+  WeakPtrFactory<Derived> factory(&data);
+  WeakPtr<Base> ptr = factory.GetWeakPtr();
+  ptr = factory.GetWeakPtr();
+  EXPECT_EQ(ptr.get(), &data);
+}
+
+TEST(WeakPtrTest, SupportsWeakPtr) {
+  Target target;
+  WeakPtr<Target> ptr = target.AsWeakPtr();
+  EXPECT_EQ(&target, ptr.get());
+}
+
+TEST(WeakPtrTest, DerivedTarget) {
+  DerivedTarget target;
+  WeakPtr<DerivedTarget> ptr = AsWeakPtr(&target);
+  EXPECT_EQ(&target, ptr.get());
+}
+
+TEST(WeakPtrTest, InvalidateWeakPtrs) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  WeakPtr<int> ptr = factory.GetWeakPtr();
+  EXPECT_EQ(&data, ptr.get());
+  EXPECT_TRUE(factory.HasWeakPtrs());
+  factory.InvalidateWeakPtrs();
+  EXPECT_EQ(NULL, ptr.get());
+  EXPECT_FALSE(factory.HasWeakPtrs());
+}
+
+TEST(WeakPtrTest, HasWeakPtrs) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  {
+    WeakPtr<int> ptr = factory.GetWeakPtr();
+    EXPECT_TRUE(factory.HasWeakPtrs());
+  }
+  EXPECT_FALSE(factory.HasWeakPtrs());
+}
+
+TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) {
+  // Test that it is OK to create an object that supports WeakPtr on one thread,
+  // but use it on another.  This tests that we do not trip runtime checks that
+  // ensure that a WeakPtr is not used by multiple threads.
+  scoped_ptr<Target> target(OffThreadObjectCreator<Target>::NewObject());
+  WeakPtr<Target> weak_ptr = target->AsWeakPtr();
+  EXPECT_EQ(target.get(), weak_ptr.get());
+}
+
+TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) {
+  // Test that it is OK to create an object that has a WeakPtr member on one
+  // thread, but use it on another.  This tests that we do not trip runtime
+  // checks that ensure that a WeakPtr is not used by multiple threads.
+  scoped_ptr<Arrow> arrow(OffThreadObjectCreator<Arrow>::NewObject());
+  Target target;
+  arrow->target = target.AsWeakPtr();
+  EXPECT_EQ(&target, arrow->target.get());
+}
+
+TEST(WeakPtrTest, MoveOwnershipImplicitly) {
+  // Move object ownership to another thread by releasing all weak pointers
+  // on the original thread first, and then establish WeakPtr on a different
+  // thread.
+  BackgroundThread background;
+  background.Start();
+
+  Target* target = new Target();
+  {
+    WeakPtr<Target> weak_ptr = target->AsWeakPtr();
+    // Main thread deletes the WeakPtr, then the thread ownership of the
+    // object can be implicitly moved.
+  }
+  Arrow* arrow;
+
+  // Background thread creates WeakPtr(and implicitly owns the object).
+  background.CreateArrowFromTarget(&arrow, target);
+  EXPECT_EQ(background.DeRef(arrow), target);
+
+  {
+    // Main thread creates another WeakPtr, but this does not trigger implicitly
+    // thread ownership move.
+    Arrow arrow;
+    arrow.target = target->AsWeakPtr();
+
+    // The new WeakPtr is owned by background thread.
+    EXPECT_EQ(target, background.DeRef(&arrow));
+  }
+
+  // Target can only be deleted on background thread.
+  background.DeleteTarget(target);
+  background.DeleteArrow(arrow);
+}
+
+TEST(WeakPtrTest, MoveOwnershipExplicitlyObjectNotReferenced) {
+  // Case 1: The target is not bound to any thread yet. So calling
+  // DetachFromThread() is a no-op.
+  Target target;
+  target.DetachFromThread();
+
+  // Case 2: The target is bound to main thread but no WeakPtr is pointing to
+  // it. In this case, it will be re-bound to any thread trying to get a
+  // WeakPtr pointing to it. So detach function call is again no-op.
+  {
+    WeakPtr<Target> weak_ptr = target.AsWeakPtr();
+  }
+  target.DetachFromThread();
+}
+
+TEST(WeakPtrTest, MoveOwnershipExplicitly) {
+  BackgroundThread background;
+  background.Start();
+
+  Arrow* arrow;
+  {
+    Target target;
+    // Background thread creates WeakPtr(and implicitly owns the object).
+    background.CreateArrowFromTarget(&arrow, &target);
+    EXPECT_EQ(&target, background.DeRef(arrow));
+
+    // Detach from background thread.
+    target.DetachFromThread();
+
+    // Re-bind to main thread.
+    EXPECT_EQ(&target, arrow->target.get());
+
+    // Main thread can now delete the target.
+  }
+
+  // WeakPtr can be deleted on non-owner thread.
+  background.DeleteArrow(arrow);
+}
+
+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, &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, &target);
+  background.DeleteArrow(arrow_copy);
+}
+
+TEST(WeakPtrTest, OwnerThreadDeletesObject) {
+  // Originating thread invalidates WeakPtrs while its held by other thread.
+  // - Main thread creates WeakPtr and passes Copy to background thread
+  // - Object gets destroyed on main thread
+  //   (invalidates WeakPtr on background thread)
+  // - WeakPtr gets destroyed on Thread B
+  BackgroundThread background;
+  background.Start();
+  Arrow* arrow_copy;
+  {
+    Target target;
+    Arrow arrow;
+    arrow.target = target.AsWeakPtr();
+    background.CreateArrowFromArrow(&arrow_copy, &arrow);
+  }
+  EXPECT_EQ(NULL, arrow_copy->target.get());
+  background.DeleteArrow(arrow_copy);
+}
+
+TEST(WeakPtrTest, 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, NonOwnerThreadDereferencesWeakPtr) {
+  // 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();
+
+  // Background thread tries to deref target, which violates thread ownership.
+  BackgroundThread background;
+  background.Start();
+  ASSERT_DEATH(background.DeRef(&arrow), "");
+}
+
+TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObject) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  scoped_ptr<Target> target(new Target());
+  // Main thread creates an arrow referencing the Target (so target's thread
+  // ownership can not be implicitly moved).
+  Arrow arrow;
+  arrow.target = target->AsWeakPtr();
+
+  // Background thread tries to delete target, which violates thread ownership.
+  BackgroundThread background;
+  background.Start();
+  ASSERT_DEATH(background.DeleteTarget(target.release()), "");
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/memory/weak_ptr_unittest.nc b/base/memory/weak_ptr_unittest.nc
new file mode 100644
index 0000000..afc8060
--- /dev/null
+++ b/base/memory/weak_ptr_unittest.nc
@@ -0,0 +1,138 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/weak_ptr.h"
+
+namespace base {
+
+struct Producer : SupportsWeakPtr<Producer> {};
+struct DerivedProducer : Producer {};
+struct OtherDerivedProducer : Producer {};
+struct MultiplyDerivedProducer : Producer,
+                                 SupportsWeakPtr<MultiplyDerivedProducer> {};
+struct Unrelated {};
+struct DerivedUnrelated : Unrelated {};
+
+#if defined(NCTEST_AUTO_DOWNCAST)  // [r"invalid conversion from"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<Producer> ptr = f.AsWeakPtr();
+  WeakPtr<DerivedProducer> derived_ptr = ptr;
+}
+
+#elif defined(NCTEST_STATIC_DOWNCAST)  // [r"invalid conversion from"]
+
+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"invalid initialization of reference"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<Producer> ptr = f.AsWeakPtr();
+  WeakPtr<DerivedProducer>& derived_ptr = ptr;
+}
+
+#elif defined(NCTEST_STATIC_REF_DOWNCAST)  // [r"invalid static_cast"]
+
+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"invalid conversion from"]
+
+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"invalid conversion from"]
+
+void WontCompile() {
+  Producer f; 
+  WeakPtr<DerivedProducer> ptr = AsWeakPtr<Producer>(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_HELPER_CAST)  // [r"cannot convert"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_INSTANTIATED_HELPER_SIDECAST)  // [r"no matching function"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr<OtherDerivedProducer>(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_WRONG_INSTANTIATED_HELPER_SIDECAST)  // [r"cannot convert"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr<DerivedProducer>(&f);
+}
+
+#elif defined(NCTEST_UNRELATED_HELPER)  // [r"cannot convert"]
+
+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"array with negative size"]
+
+void WontCompile() {
+  Unrelated f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_DERIVED_COMPLETELY_UNRELATED_HELPER)  // [r"array with negative size"]
+
+void WontCompile() {
+  DerivedUnrelated f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_AMBIGUOUS_ANCESTORS)  // [r"ambiguous base"]
+
+void WontCompile() {
+  MultiplyDerivedProducer f;
+  WeakPtr<MultiplyDerivedProducer> ptr = AsWeakPtr(&f);
+}
+
+#endif
+
+}
diff --git a/base/message_loop.cc b/base/message_loop.cc
new file mode 100644
index 0000000..f427993
--- /dev/null
+++ b/base/message_loop.cc
@@ -0,0 +1,794 @@
+// Copyright (c) 2012 The Chromium Authors. All 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.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/debug/alias.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop_proxy_impl.h"
+#include "base/message_pump_default.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/run_loop.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_local.h"
+#include "base/time.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_MACOSX)
+#include "base/message_pump_mac.h"
+#endif
+#if defined(OS_POSIX)
+#include "base/message_pump_libevent.h"
+#endif
+#if defined(OS_ANDROID)
+#include "base/message_pump_android.h"
+#endif
+
+#if defined(TOOLKIT_GTK)
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#endif
+
+using base::PendingTask;
+using base::TimeDelta;
+using base::TimeTicks;
+
+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.
+base::LazyInstance<base::ThreadLocalPointer<MessageLoop> > 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;
+const int kTimerEvent = 0x2;
+
+// Provide range of message IDs for use in histogramming and debug display.
+const int kLeastNonZeroMessageId = 1;
+const int kMaxMessageId = 1099;
+const int kNumberOfDistinctMessagesDisplayed = 1100;
+
+// Provide a macro that takes an expression (such as a constant, or macro
+// constant) and creates a pair to initalize an array of pairs.  In this case,
+// our pair consists of the expressions value, and the "stringized" version
+// of the expression (i.e., the exrpression put in quotes).  For example, if
+// we have:
+//    #define FOO 2
+//    #define BAR 5
+// then the following:
+//    VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
+// will expand to:
+//   {7, "FOO + BAR"}
+// We use the resulting array as an argument to our histogram, which reads the
+// number as a bucket identifier, and proceeds to use the corresponding name
+// in the pair (i.e., the quoted string) when printing out a histogram.
+#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
+
+const base::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.
+};
+
+bool enable_histogrammer_ = false;
+
+MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL;
+
+// Create a process-wide unique ID to represent this task in trace events. This
+// will be mangled with a Process ID hash to reduce the likelyhood of colliding
+// with MessageLoop pointers on other processes.
+uint64 GetTaskTraceID(const PendingTask& task, MessageLoop* loop) {
+  return (static_cast<uint64>(task.sequence_num) << 32) |
+         static_cast<uint64>(reinterpret_cast<intptr_t>(loop));
+}
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+
+#if defined(OS_WIN)
+
+// Upon a SEH exception in this thread, it restores the original unhandled
+// exception filter.
+static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
+  ::SetUnhandledExceptionFilter(old_filter);
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+
+// Retrieves a pointer to the current unhandled exception filter. There
+// is no standalone getter method.
+static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
+  LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL;
+  top_filter = ::SetUnhandledExceptionFilter(0);
+  ::SetUnhandledExceptionFilter(top_filter);
+  return top_filter;
+}
+
+#endif  // defined(OS_WIN)
+
+//------------------------------------------------------------------------------
+
+MessageLoop::TaskObserver::TaskObserver() {
+}
+
+MessageLoop::TaskObserver::~TaskObserver() {
+}
+
+MessageLoop::DestructionObserver::~DestructionObserver() {
+}
+
+//------------------------------------------------------------------------------
+
+MessageLoop::MessageLoop(Type type)
+    : type_(type),
+      nestable_tasks_allowed_(true),
+      exception_restoration_(false),
+      message_histogram_(NULL),
+      run_loop_(NULL),
+#ifdef OS_WIN
+      os_modal_loop_(false),
+#endif  // OS_WIN
+      next_sequence_num_(0) {
+  DCHECK(!current()) << "should only have one message loop per thread";
+  lazy_tls_ptr.Pointer()->Set(this);
+
+  message_loop_proxy_ = new base::MessageLoopProxyImpl();
+  thread_task_runner_handle_.reset(
+      new base::ThreadTaskRunnerHandle(message_loop_proxy_));
+
+// TODO(rvargas): Get rid of the OS guards.
+#if defined(OS_WIN)
+#define MESSAGE_PUMP_UI new base::MessagePumpForUI()
+#define MESSAGE_PUMP_IO new base::MessagePumpForIO()
+#elif defined(OS_MACOSX)
+#define MESSAGE_PUMP_UI base::MessagePumpMac::Create()
+#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
+#elif defined(OS_NACL)
+// Currently NaCl doesn't have a UI MessageLoop.
+// TODO(abarth): Figure out if we need this.
+#define MESSAGE_PUMP_UI NULL
+// ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and
+// doesn't require extra support for watching file descriptors.
+#define MESSAGE_PUMP_IO new base::MessagePumpDefault();
+#elif defined(OS_POSIX)  // POSIX but not MACOSX.
+#define MESSAGE_PUMP_UI new base::MessagePumpForUI()
+#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
+#else
+#error Not implemented
+#endif
+
+  if (type_ == TYPE_UI) {
+    if (message_pump_for_ui_factory_)
+      pump_ = message_pump_for_ui_factory_();
+    else
+      pump_ = MESSAGE_PUMP_UI;
+  } else if (type_ == TYPE_IO) {
+    pump_ = MESSAGE_PUMP_IO;
+  } else {
+    DCHECK_EQ(TYPE_DEFAULT, type_);
+    pump_ = new base::MessagePumpDefault();
+  }
+}
+
+MessageLoop::~MessageLoop() {
+  DCHECK_EQ(this, current());
+
+  DCHECK(!run_loop_);
+
+  // 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 message_loop_proxy that we are dying.
+  static_cast<base::MessageLoopProxyImpl*>(message_loop_proxy_.get())->
+      WillDestroyCurrentMessageLoop();
+  message_loop_proxy_ = NULL;
+
+  // OK, now make it so that no one can find us.
+  lazy_tls_ptr.Pointer()->Set(NULL);
+
+#if defined(OS_WIN)
+  // If we left the high-resolution timer activated, deactivate it now.
+  // Doing this is not-critical, it is mainly to make sure we track
+  // the high resolution timer activations properly in our unit tests.
+  if (!high_resolution_timer_expiration_.is_null()) {
+    base::Time::ActivateHighResolutionTimer(false);
+    high_resolution_timer_expiration_ = base::TimeTicks();
+  }
+#endif
+}
+
+// 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
+void MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) {
+  DCHECK(!message_pump_for_ui_factory_);
+  message_pump_for_ui_factory_ = factory;
+}
+
+void MessageLoop::AddDestructionObserver(
+    DestructionObserver* destruction_observer) {
+  DCHECK_EQ(this, current());
+  destruction_observers_.AddObserver(destruction_observer);
+}
+
+void MessageLoop::RemoveDestructionObserver(
+    DestructionObserver* destruction_observer) {
+  DCHECK_EQ(this, current());
+  destruction_observers_.RemoveObserver(destruction_observer);
+}
+
+void MessageLoop::PostTask(
+    const tracked_objects::Location& from_here, const base::Closure& task) {
+  DCHECK(!task.is_null()) << from_here.ToString();
+  PendingTask pending_task(
+      from_here, task, CalculateDelayedRuntime(TimeDelta()), true);
+  AddToIncomingQueue(&pending_task);
+}
+
+void MessageLoop::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    TimeDelta delay) {
+  DCHECK(!task.is_null()) << from_here.ToString();
+  PendingTask pending_task(
+      from_here, task, CalculateDelayedRuntime(delay), true);
+  AddToIncomingQueue(&pending_task);
+}
+
+void MessageLoop::PostNonNestableTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task) {
+  DCHECK(!task.is_null()) << from_here.ToString();
+  PendingTask pending_task(
+      from_here, task, CalculateDelayedRuntime(TimeDelta()), false);
+  AddToIncomingQueue(&pending_task);
+}
+
+void MessageLoop::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    TimeDelta delay) {
+  DCHECK(!task.is_null()) << from_here.ToString();
+  PendingTask pending_task(
+      from_here, task, CalculateDelayedRuntime(delay), false);
+  AddToIncomingQueue(&pending_task);
+}
+
+void MessageLoop::Run() {
+  base::RunLoop run_loop;
+  run_loop.Run();
+}
+
+void MessageLoop::RunUntilIdle() {
+  base::RunLoop run_loop;
+  run_loop.RunUntilIdle();
+}
+
+void MessageLoop::QuitWhenIdle() {
+  DCHECK_EQ(this, current());
+  if (run_loop_) {
+    run_loop_->quit_when_idle_received_ = true;
+  } else {
+    NOTREACHED() << "Must be inside Run to call Quit";
+  }
+}
+
+void MessageLoop::QuitNow() {
+  DCHECK_EQ(this, current());
+  if (run_loop_) {
+    pump_->Quit();
+  } else {
+    NOTREACHED() << "Must be inside Run to call Quit";
+  }
+}
+
+bool MessageLoop::IsType(Type type) const {
+  return type_ == type;
+}
+
+static void QuitCurrentWhenIdle() {
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+// static
+base::Closure MessageLoop::QuitWhenIdleClosure() {
+  return base::Bind(&QuitCurrentWhenIdle);
+}
+
+void MessageLoop::SetNestableTasksAllowed(bool allowed) {
+  if (nestable_tasks_allowed_ != allowed) {
+    nestable_tasks_allowed_ = allowed;
+    if (!nestable_tasks_allowed_)
+      return;
+    // Start the native pump if we are not already pumping.
+    pump_->ScheduleWork();
+  }
+}
+
+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);
+}
+
+void MessageLoop::AssertIdle() const {
+  // We only check |incoming_queue_|, since we don't want to lock |work_queue_|.
+  base::AutoLock lock(incoming_queue_lock_);
+  DCHECK(incoming_queue_.empty());
+}
+
+bool MessageLoop::is_running() const {
+  DCHECK_EQ(this, current());
+  return run_loop_ != NULL;
+}
+
+//------------------------------------------------------------------------------
+
+// Runs the loop in two different SEH modes:
+// enable_SEH_restoration_ = false : any unhandled exception goes to the last
+// one that calls SetUnhandledExceptionFilter().
+// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
+// that was existed before the loop was run.
+void MessageLoop::RunHandler() {
+#if defined(OS_WIN)
+  if (exception_restoration_) {
+    RunInternalInSEHFrame();
+    return;
+  }
+#endif
+
+  RunInternal();
+}
+
+#if defined(OS_WIN)
+__declspec(noinline) void MessageLoop::RunInternalInSEHFrame() {
+  LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
+  __try {
+    RunInternal();
+  } __except(SEHFilter(current_filter)) {
+  }
+  return;
+}
+#endif
+
+void MessageLoop::RunInternal() {
+  DCHECK_EQ(this, current());
+
+  StartHistogrammer();
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+  if (run_loop_->dispatcher_ && type() == TYPE_UI) {
+    static_cast<base::MessagePumpForUI*>(pump_.get())->
+        RunWithDispatcher(this, run_loop_->dispatcher_);
+    return;
+  }
+#endif
+
+  pump_->Run(this);
+}
+
+bool MessageLoop::ProcessNextDelayedNonNestableTask() {
+  if (run_loop_->run_depth_ != 1)
+    return false;
+
+  if (deferred_non_nestable_work_queue_.empty())
+    return false;
+
+  PendingTask pending_task = deferred_non_nestable_work_queue_.front();
+  deferred_non_nestable_work_queue_.pop();
+
+  RunTask(pending_task);
+  return true;
+}
+
+void MessageLoop::RunTask(const PendingTask& pending_task) {
+  TRACE_EVENT_FLOW_END0("task", "MessageLoop::PostTask",
+      TRACE_ID_MANGLE(GetTaskTraceID(pending_task, this)));
+  TRACE_EVENT2("task", "MessageLoop::RunTask",
+               "src_file", pending_task.posted_from.file_name(),
+               "src_func", pending_task.posted_from.function_name());
+  DCHECK(nestable_tasks_allowed_);
+  // Execute the task and assume the worst: It is probably not reentrant.
+  nestable_tasks_allowed_ = false;
+
+  // 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();
+  base::debug::Alias(&program_counter);
+
+  HistogramEvent(kTaskRunEvent);
+
+  tracked_objects::TrackedTime start_time =
+      tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally);
+
+  FOR_EACH_OBSERVER(TaskObserver, task_observers_,
+                    WillProcessTask(pending_task.time_posted));
+  pending_task.task.Run();
+  FOR_EACH_OBSERVER(TaskObserver, task_observers_,
+                    DidProcessTask(pending_task.time_posted));
+
+  tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(pending_task,
+      start_time, tracked_objects::ThreadData::NowForEndOfRun());
+
+  nestable_tasks_allowed_ = true;
+}
+
+bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
+  if (pending_task.nestable || run_loop_->run_depth_ == 1) {
+    RunTask(pending_task);
+    // Show that we ran a task (Note: a new one might arrive as a
+    // consequence!).
+    return true;
+  }
+
+  // We couldn't run the task now because we're in a nested message loop
+  // and the task isn't nestable.
+  deferred_non_nestable_work_queue_.push(pending_task);
+  return false;
+}
+
+void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
+  // Move to the delayed work queue.
+  delayed_work_queue_.push(pending_task);
+}
+
+void MessageLoop::ReloadWorkQueue() {
+  // We can improve performance of our loading tasks from 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())
+    return;  // Wait till we *really* need to lock and load.
+
+  // Acquire all we can from the inter-thread queue with one lock acquisition.
+  {
+    base::AutoLock lock(incoming_queue_lock_);
+    if (incoming_queue_.empty())
+      return;
+    incoming_queue_.Swap(&work_queue_);  // Constant time
+    DCHECK(incoming_queue_.empty());
+  }
+}
+
+bool MessageLoop::DeletePendingTasks() {
+  bool did_work = !work_queue_.empty();
+  while (!work_queue_.empty()) {
+    PendingTask pending_task = work_queue_.front();
+    work_queue_.pop();
+    if (!pending_task.delayed_run_time.is_null()) {
+      // We want to delete delayed tasks in the same order in which they would
+      // normally be deleted in case of any funny dependencies between delayed
+      // tasks.
+      AddToDelayedWorkQueue(pending_task);
+    }
+  }
+  did_work |= !deferred_non_nestable_work_queue_.empty();
+  while (!deferred_non_nestable_work_queue_.empty()) {
+    deferred_non_nestable_work_queue_.pop();
+  }
+  did_work |= !delayed_work_queue_.empty();
+
+  // Historically, we always delete the task regardless of valgrind status. It's
+  // not completely clear why we want to leak them in the loops above.  This
+  // code is replicating legacy behavior, and should not be considered
+  // absolutely "correct" behavior.  See TODO above about deleting all tasks
+  // when it's safe.
+  while (!delayed_work_queue_.empty()) {
+    delayed_work_queue_.pop();
+  }
+  return did_work;
+}
+
+TimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) {
+  TimeTicks delayed_run_time;
+  if (delay > TimeDelta()) {
+    delayed_run_time = TimeTicks::Now() + delay;
+
+#if defined(OS_WIN)
+    if (high_resolution_timer_expiration_.is_null()) {
+      // Windows timers are granular to 15.6ms.  If we only set high-res
+      // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms,
+      // which as a percentage is pretty inaccurate.  So enable high
+      // res timers for any timer which is within 2x of the granularity.
+      // This is a tradeoff between accuracy and power management.
+      bool needs_high_res_timers = delay.InMilliseconds() <
+          (2 * base::Time::kMinLowResolutionThresholdMs);
+      if (needs_high_res_timers) {
+        if (base::Time::ActivateHighResolutionTimer(true)) {
+          high_resolution_timer_expiration_ = TimeTicks::Now() +
+              TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs);
+        }
+      }
+    }
+#endif
+  } else {
+    DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative";
+  }
+
+#if defined(OS_WIN)
+  if (!high_resolution_timer_expiration_.is_null()) {
+    if (TimeTicks::Now() > high_resolution_timer_expiration_) {
+      base::Time::ActivateHighResolutionTimer(false);
+      high_resolution_timer_expiration_ = TimeTicks();
+    }
+  }
+#endif
+
+  return delayed_run_time;
+}
+
+// Possibly called on a background thread!
+void MessageLoop::AddToIncomingQueue(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.
+
+  scoped_refptr<base::MessagePump> pump;
+  {
+    base::AutoLock locked(incoming_queue_lock_);
+
+    // Initialize the sequence number. The sequence number is used for delayed
+    // tasks (to faciliate FIFO sorting when two tasks have the same
+    // delayed_run_time value) and for identifying the task in about:tracing.
+    pending_task->sequence_num = next_sequence_num_++;
+
+    TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask",
+        TRACE_ID_MANGLE(GetTaskTraceID(*pending_task, this)));
+
+    bool was_empty = incoming_queue_.empty();
+    incoming_queue_.push(*pending_task);
+    pending_task->task.Reset();
+    if (!was_empty)
+      return;  // Someone else should have started the sub-pump.
+
+    pump = pump_;
+  }
+  // Since the incoming_queue_ may contain a task that destroys this message
+  // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
+  // We use a stack-based reference to the message pump so that we can call
+  // ScheduleWork outside of incoming_queue_lock_.
+
+  pump->ScheduleWork();
+}
+
+//------------------------------------------------------------------------------
+// Method and data for histogramming events and actions taken by each instance
+// on each thread.
+
+void MessageLoop::StartHistogrammer() {
+#if !defined(OS_NACL)  // NaCl build has no metrics code.
+  if (enable_histogrammer_ && !message_histogram_
+      && base::StatisticsRecorder::IsActive()) {
+    DCHECK(!thread_name_.empty());
+    message_histogram_ = base::LinearHistogram::FactoryGetWithRangeDescription(
+        "MsgLoop:" + thread_name_,
+        kLeastNonZeroMessageId, kMaxMessageId,
+        kNumberOfDistinctMessagesDisplayed,
+        message_histogram_->kHexRangePrintingFlag,
+        event_descriptions_);
+  }
+#endif
+}
+
+void MessageLoop::HistogramEvent(int event) {
+#if !defined(OS_NACL)
+  if (message_histogram_)
+    message_histogram_->Add(event);
+#endif
+}
+
+bool MessageLoop::DoWork() {
+  if (!nestable_tasks_allowed_) {
+    // Task can't be executed right now.
+    return false;
+  }
+
+  for (;;) {
+    ReloadWorkQueue();
+    if (work_queue_.empty())
+      break;
+
+    // Execute oldest task.
+    do {
+      PendingTask pending_task = work_queue_.front();
+      work_queue_.pop();
+      if (!pending_task.delayed_run_time.is_null()) {
+        AddToDelayedWorkQueue(pending_task);
+        // If we changed the topmost task, then it is time to reschedule.
+        if (delayed_work_queue_.top().task.Equals(pending_task.task))
+          pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
+      } else {
+        if (DeferOrRunPendingTask(pending_task))
+          return true;
+      }
+    } while (!work_queue_.empty());
+  }
+
+  // Nothing happened.
+  return false;
+}
+
+bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
+  if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
+    recent_time_ = *next_delayed_work_time = TimeTicks();
+    return false;
+  }
+
+  // When we "fall behind," there will be a lot of tasks in the delayed work
+  // queue that are ready to run.  To increase efficiency when we fall behind,
+  // we will only call Time::Now() intermittently, and then process all tasks
+  // that are ready to run before calling it again.  As a result, the more we
+  // fall behind (and have a lot of ready-to-run delayed tasks), the more
+  // efficient we'll be at handling the tasks.
+
+  TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time;
+  if (next_run_time > recent_time_) {
+    recent_time_ = TimeTicks::Now();  // Get a better view of Now();
+    if (next_run_time > recent_time_) {
+      *next_delayed_work_time = next_run_time;
+      return false;
+    }
+  }
+
+  PendingTask pending_task = delayed_work_queue_.top();
+  delayed_work_queue_.pop();
+
+  if (!delayed_work_queue_.empty())
+    *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
+
+  return DeferOrRunPendingTask(pending_task);
+}
+
+bool MessageLoop::DoIdleWork() {
+  if (ProcessNextDelayedNonNestableTask())
+    return true;
+
+  if (run_loop_->quit_when_idle_received_)
+    pump_->Quit();
+
+  return false;
+}
+
+void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here,
+                                     void(*deleter)(const void*),
+                                     const void* object) {
+  PostNonNestableTask(from_here, base::Bind(deleter, object));
+}
+
+void MessageLoop::ReleaseSoonInternal(
+    const tracked_objects::Location& from_here,
+    void(*releaser)(const void*),
+    const void* object) {
+  PostNonNestableTask(from_here, base::Bind(releaser, object));
+}
+
+//------------------------------------------------------------------------------
+// MessageLoopForUI
+
+#if defined(OS_WIN)
+void MessageLoopForUI::DidProcessMessage(const MSG& message) {
+  pump_win()->DidProcessMessage(message);
+}
+#endif  // defined(OS_WIN)
+
+#if defined(OS_ANDROID)
+void MessageLoopForUI::Start() {
+  // No Histogram support for UI message loop as it is managed by Java side
+  static_cast<base::MessagePumpForUI*>(pump_.get())->Start(this);
+}
+#endif
+
+#if defined(OS_IOS)
+void MessageLoopForUI::Attach() {
+  static_cast<base::MessagePumpUIApplication*>(pump_.get())->Attach(this);
+}
+#endif
+
+#if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
+void MessageLoopForUI::AddObserver(Observer* observer) {
+  pump_ui()->AddObserver(observer);
+}
+
+void MessageLoopForUI::RemoveObserver(Observer* observer) {
+  pump_ui()->RemoveObserver(observer);
+}
+
+#endif  //  !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
+
+//------------------------------------------------------------------------------
+// MessageLoopForIO
+
+#if defined(OS_WIN)
+
+void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) {
+  pump_io()->RegisterIOHandler(file, handler);
+}
+
+bool MessageLoopForIO::RegisterJobObject(HANDLE job, IOHandler* handler) {
+  return pump_io()->RegisterJobObject(job, handler);
+}
+
+bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
+  return pump_io()->WaitForIOCompletion(timeout, filter);
+}
+
+#elif defined(OS_POSIX) && !defined(OS_NACL)
+
+bool MessageLoopForIO::WatchFileDescriptor(int fd,
+                                           bool persistent,
+                                           Mode mode,
+                                           FileDescriptorWatcher *controller,
+                                           Watcher *delegate) {
+  return pump_libevent()->WatchFileDescriptor(
+      fd,
+      persistent,
+      static_cast<base::MessagePumpLibevent::Mode>(mode),
+      controller,
+      delegate);
+}
+
+#endif
diff --git a/base/message_loop.h b/base/message_loop.h
new file mode 100644
index 0000000..74dfe65
--- /dev/null
+++ b/base/message_loop.h
@@ -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.
+
+#ifndef BASE_MESSAGE_LOOP_H_
+#define BASE_MESSAGE_LOOP_H_
+
+#include <queue>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop_proxy.h"
+#include "base/message_pump.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/tracking_info.h"
+#include "base/time.h"
+
+#if defined(OS_WIN)
+// We need this to declare base::MessagePumpWin::Dispatcher, which we should
+// really just eliminate.
+#include "base/message_pump_win.h"
+#elif defined(OS_POSIX)
+#include "base/message_pump_libevent.h"
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+
+#if defined(USE_AURA) && defined(USE_X11) && !defined(OS_NACL)
+#include "base/message_pump_aurax11.h"
+#else
+#include "base/message_pump_gtk.h"
+#endif
+
+#endif
+#endif
+
+namespace base {
+class Histogram;
+class RunLoop;
+class ThreadTaskRunnerHandle;
+#if defined(OS_ANDROID)
+class MessagePumpForUI;
+#endif
+}  // namespace base
+
+// 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 or those
+// managed by TimerManager.  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 base::MessagePump::Delegate {
+ public:
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+  typedef base::MessagePumpDispatcher Dispatcher;
+  typedef base::MessagePumpObserver Observer;
+#endif
+
+  // 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.
+  //
+  enum Type {
+    TYPE_DEFAULT,
+    TYPE_UI,
+    TYPE_IO
+  };
+
+  // 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);
+  virtual ~MessageLoop();
+
+  // Returns the MessageLoop object for the current thread, or null if none.
+  static MessageLoop* current();
+
+  static void EnableHistogrammer(bool enable_histogrammer);
+
+  typedef base::MessagePump* (MessagePumpFactory)();
+  // Using the given base::MessagePumpForUIFactory to override the default
+  // MessagePump implementation for 'TYPE_UI'.
+  static void InitMessagePumpForUIFactory(MessagePumpFactory* factory);
+
+  // 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);
+
+  // 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().
+  //
+  // 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 base::Closure& task);
+
+  void PostDelayedTask(
+      const tracked_objects::Location& from_here,
+      const base::Closure& task,
+      base::TimeDelta delay);
+
+  void PostNonNestableTask(
+      const tracked_objects::Location& from_here,
+      const base::Closure& task);
+
+  void PostNonNestableDelayedTask(
+      const tracked_objects::Location& from_here,
+      const base::Closure& task,
+      base::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().  If this is not the same
+  // as the thread that calls PostDelayedTask(FROM_HERE, ), then T MUST inherit
+  // from RefCountedThreadSafe<T>!
+  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.
+  //
+  // 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
+  // PostDelayedTask(FROM_HERE, ), then T MUST inherit from
+  // RefCountedThreadSafe<T>!
+  template <class T>
+  void ReleaseSoon(const tracked_objects::Location& from_here,
+                   const T* object) {
+    base::subtle::ReleaseHelperInternal<T, void>::ReleaseViaSequencedTaskRunner(
+        this, from_here, object);
+  }
+
+  // Deprecated: use RunLoop instead.
+  // Run the message loop.
+  void Run();
+
+  // Deprecated: use RunLoop instead.
+  // Process all pending tasks, windows messages, etc., but don't wait/sleep.
+  // Return as soon as all items that can be run are taken care of.
+  void RunUntilIdle();
+
+  // TODO(jbates) remove this. crbug.com/131220. See RunUntilIdle().
+  void RunAllPending() { RunUntilIdle(); }
+
+  // TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdle().
+  void Quit() { QuitWhenIdle(); }
+
+  // Deprecated: use RunLoop instead.
+  //
+  // Signals the Run method to return when it becomes idle. It will continue to
+  // process pending messages and future messages as long as they are enqueued.
+  // Warning: if the MessageLoop remains busy, it may never quit. Only use this
+  // Quit method when looping procedures (such as web pages) have been shut
+  // down.
+  //
+  // This method may only be called on the same thread that called Run, and Run
+  // must still be on the call stack.
+  //
+  // Use QuitClosure variants if you need to Quit another thread's MessageLoop,
+  // but note that doing so is fairly dangerous if the target thread makes
+  // nested calls to MessageLoop::Run.  The problem being that you won't know
+  // which nested run loop you are quitting, so be careful!
+  void QuitWhenIdle();
+
+  // Deprecated: use RunLoop instead.
+  //
+  // This method is a variant of Quit, that does not wait for pending messages
+  // to be processed before returning from Run.
+  void QuitNow();
+
+  // TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdleClosure().
+  static base::Closure QuitClosure() { return QuitWhenIdleClosure(); }
+
+  // Deprecated: use RunLoop instead.
+  // Construct a Closure that will call QuitWhenIdle(). Useful to schedule an
+  // arbitrary MessageLoop to QuitWhenIdle.
+  static base::Closure QuitWhenIdleClosure();
+
+  // Returns true if this loop is |type|. This allows subclasses (especially
+  // those in tests) to specialize how they are identified.
+  virtual bool IsType(Type type) const;
+
+  // Returns the type passed to the constructor.
+  Type type() const { return type_; }
+
+  // Optional call to connect the thread name with this loop.
+  void set_thread_name(const std::string& thread_name) {
+    DCHECK(thread_name_.empty()) << "Should not rename this thread!";
+    thread_name_ = thread_name;
+  }
+  const std::string& thread_name() const { return thread_name_; }
+
+  // Gets the message loop proxy associated with this message loop.
+  scoped_refptr<base::MessageLoopProxy> message_loop_proxy() {
+    return message_loop_proxy_.get();
+  }
+
+  // Enables or disables the recursive task processing. This happens in the case
+  // of recursive message loops. Some unwanted message loop may occurs when
+  // using common controls or printer functions. By default, recursive task
+  // processing is disabled.
+  //
+  // Please utilize |ScopedNestableTaskAllower| instead of calling these methods
+  // directly.  In general nestable message loops are to be avoided.  They are
+  // dangerous and difficult to get right, so please use with extreme caution.
+  //
+  // The specific case where tasks get queued is:
+  // - The thread is running a message loop.
+  // - It receives a task #1 and execute it.
+  // - The task #1 implicitly start a message loop, like a MessageBox in the
+  //   unit test. This can also be StartDoc or GetSaveFileName.
+  // - The thread receives a task #2 before or while in this second message
+  //   loop.
+  // - With NestableTasksAllowed set to true, the task #2 will run right away.
+  //   Otherwise, it will get executed right after task #1 completes at "thread
+  //   message loop level".
+  void SetNestableTasksAllowed(bool allowed);
+  bool NestableTasksAllowed() const;
+
+  // Enables nestable tasks on |loop| while in scope.
+  class ScopedNestableTaskAllower {
+   public:
+    explicit ScopedNestableTaskAllower(MessageLoop* loop)
+        : loop_(loop),
+          old_state_(loop_->NestableTasksAllowed()) {
+      loop_->SetNestableTasksAllowed(true);
+    }
+    ~ScopedNestableTaskAllower() {
+      loop_->SetNestableTasksAllowed(old_state_);
+    }
+
+   private:
+    MessageLoop* loop_;
+    bool old_state_;
+  };
+
+  // Enables or disables the restoration during an exception of the unhandled
+  // exception filter that was active when Run() was called. This can happen
+  // if some third party code call SetUnhandledExceptionFilter() and never
+  // restores the previous filter.
+  void set_exception_restoration(bool restore) {
+    exception_restoration_ = restore;
+  }
+
+  // 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(base::TimeTicks time_posted) = 0;
+
+    // This method is called after processing a task.
+    virtual void DidProcessTask(base::TimeTicks time_posted) = 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);
+
+  // Returns true if the message loop has high resolution timers enabled.
+  // Provided for testing.
+  bool high_resolution_timers_enabled() {
+#if defined(OS_WIN)
+    return !high_resolution_timer_expiration_.is_null();
+#else
+    return true;
+#endif
+  }
+
+  // When we go into high resolution timer mode, we will stay in hi-res mode
+  // for at least 1s.
+  static const int kHighResolutionTimerModeLeaseTimeMs = 1000;
+
+  // Asserts that the MessageLoop is "idle".
+  void AssertIdle() const;
+
+#if defined(OS_WIN)
+  void set_os_modal_loop(bool os_modal_loop) {
+    os_modal_loop_ = os_modal_loop;
+  }
+
+  bool os_modal_loop() const {
+    return os_modal_loop_;
+  }
+#endif  // OS_WIN
+
+  // Can only be called from the thread that owns the MessageLoop.
+  bool is_running() const;
+
+  //----------------------------------------------------------------------------
+ protected:
+  friend class base::RunLoop;
+
+#if defined(OS_WIN)
+  base::MessagePumpWin* pump_win() {
+    return static_cast<base::MessagePumpWin*>(pump_.get());
+  }
+#elif defined(OS_POSIX)
+  base::MessagePumpLibevent* pump_libevent() {
+    return static_cast<base::MessagePumpLibevent*>(pump_.get());
+  }
+#endif
+
+  // A function to encapsulate all the exception handling capability in the
+  // stacks around the running of a main message loop.  It will run the message
+  // loop in a SEH try block or not depending on the set_SEH_restoration()
+  // flag invoking respectively RunInternalInSEHFrame() or RunInternal().
+  void RunHandler();
+
+#if defined(OS_WIN)
+  __declspec(noinline) void RunInternalInSEHFrame();
+#endif
+
+  // A surrounding stack frame around the running of the message loop that
+  // supports all saving and restoring of state, as is needed for any/all (ugly)
+  // recursive calls.
+  void RunInternal();
+
+  // Called to process any delayed non-nestable tasks.
+  bool ProcessNextDelayedNonNestableTask();
+
+  // Runs the specified PendingTask.
+  void RunTask(const base::PendingTask& pending_task);
+
+  // Calls RunTask or queues the pending_task on the deferred task list if it
+  // cannot be run right now.  Returns true if the task was run.
+  bool DeferOrRunPendingTask(const base::PendingTask& pending_task);
+
+  // Adds the pending task to delayed_work_queue_.
+  void AddToDelayedWorkQueue(const base::PendingTask& pending_task);
+
+  // Adds the pending task to our incoming_queue_.
+  //
+  // 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.
+  void AddToIncomingQueue(base::PendingTask* pending_task);
+
+  // Load tasks from the incoming_queue_ into work_queue_ if the latter is
+  // empty.  The former requires a lock to access, while the latter is directly
+  // accessible on this thread.
+  void ReloadWorkQueue();
+
+  // 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();
+
+  // Calculates the time at which a PendingTask should run.
+  base::TimeTicks CalculateDelayedRuntime(base::TimeDelta delay);
+
+  // 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);
+
+  // base::MessagePump::Delegate methods:
+  virtual bool DoWork() OVERRIDE;
+  virtual bool DoDelayedWork(base::TimeTicks* next_delayed_work_time) OVERRIDE;
+  virtual bool DoIdleWork() OVERRIDE;
+
+  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.
+  base::TaskQueue work_queue_;
+
+  // Contains delayed tasks, sorted by their 'delayed_run_time' property.
+  base::DelayedTaskQueue delayed_work_queue_;
+
+  // A recent snapshot of Time::Now(), used to check delayed_work_queue_.
+  base::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.
+  base::TaskQueue deferred_non_nestable_work_queue_;
+
+  scoped_refptr<base::MessagePump> pump_;
+
+  ObserverList<DestructionObserver> destruction_observers_;
+
+  // A recursion block that prevents accidentally running additional tasks when
+  // insider a (accidentally induced?) nested message pump.
+  bool nestable_tasks_allowed_;
+
+  bool exception_restoration_;
+
+  std::string thread_name_;
+  // A profiling histogram showing the counts of various messages and events.
+  base::Histogram* message_histogram_;
+
+  // A null terminated list which creates an incoming_queue of tasks that are
+  // acquired under a mutex for processing on this instance's thread. These
+  // tasks have not yet been sorted out into items for our work_queue_ vs items
+  // that will be handled by the TimerManager.
+  base::TaskQueue incoming_queue_;
+  // Protect access to incoming_queue_.
+  mutable base::Lock incoming_queue_lock_;
+
+  base::RunLoop* run_loop_;
+
+#if defined(OS_WIN)
+  base::TimeTicks high_resolution_timer_expiration_;
+  // Should be set to true before calling Windows APIs like TrackPopupMenu, etc
+  // which enter a modal message loop.
+  bool os_modal_loop_;
+#endif
+
+  // The next sequence number to use for delayed tasks. Updating this counter is
+  // protected by incoming_queue_lock_.
+  int next_sequence_num_;
+
+  ObserverList<TaskObserver> task_observers_;
+
+  // The message loop proxy associated with this message loop, if one exists.
+  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+  scoped_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
+
+ private:
+  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);
+};
+
+//-----------------------------------------------------------------------------
+// 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:
+#if defined(OS_WIN)
+  typedef base::MessagePumpForUI::MessageFilter MessageFilter;
+#endif
+
+  MessageLoopForUI() : MessageLoop(TYPE_UI) {
+  }
+
+  // Returns the MessageLoopForUI of the current thread.
+  static MessageLoopForUI* current() {
+    MessageLoop* loop = MessageLoop::current();
+    DCHECK(loop);
+    DCHECK_EQ(MessageLoop::TYPE_UI, loop->type());
+    return static_cast<MessageLoopForUI*>(loop);
+  }
+
+#if defined(OS_WIN)
+  void DidProcessMessage(const MSG& message);
+#endif  // defined(OS_WIN)
+
+#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();
+#elif !defined(OS_MACOSX)
+  // Please see message_pump_win/message_pump_glib for definitions of these
+  // methods.
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+#if defined(OS_WIN)
+  // Plese see MessagePumpForUI for definitions of this method.
+  void SetMessageFilter(scoped_ptr<MessageFilter> message_filter) {
+    pump_ui()->SetMessageFilter(message_filter.Pass());
+  }
+#endif
+
+ protected:
+#if defined(USE_AURA) && defined(USE_X11) && !defined(OS_NACL)
+  friend class base::MessagePumpAuraX11;
+#endif
+
+  // TODO(rvargas): Make this platform independent.
+  base::MessagePumpForUI* pump_ui() {
+    return static_cast<base::MessagePumpForUI*>(pump_.get());
+  }
+#endif  // !defined(OS_MACOSX)
+};
+
+// Do not add any member variables to MessageLoopForUI!  This is important b/c
+// MessageLoopForUI is often allocated via MessageLoop(TYPE_UI).  Any extra
+// data that you need should be stored on the MessageLoop's pump_ instance.
+COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
+               MessageLoopForUI_should_not_have_extra_member_variables);
+
+//-----------------------------------------------------------------------------
+// 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:
+#if defined(OS_WIN)
+  typedef base::MessagePumpForIO::IOHandler IOHandler;
+  typedef base::MessagePumpForIO::IOContext IOContext;
+  typedef base::MessagePumpForIO::IOObserver IOObserver;
+#elif defined(OS_POSIX)
+  typedef base::MessagePumpLibevent::Watcher Watcher;
+  typedef base::MessagePumpLibevent::FileDescriptorWatcher
+      FileDescriptorWatcher;
+  typedef base::MessagePumpLibevent::IOObserver IOObserver;
+
+  enum Mode {
+    WATCH_READ = base::MessagePumpLibevent::WATCH_READ,
+    WATCH_WRITE = base::MessagePumpLibevent::WATCH_WRITE,
+    WATCH_READ_WRITE = base::MessagePumpLibevent::WATCH_READ_WRITE
+  };
+
+#endif
+
+  MessageLoopForIO() : MessageLoop(TYPE_IO) {
+  }
+
+  // Returns the MessageLoopForIO of the current thread.
+  static MessageLoopForIO* current() {
+    MessageLoop* loop = MessageLoop::current();
+    DCHECK_EQ(MessageLoop::TYPE_IO, loop->type());
+    return static_cast<MessageLoopForIO*>(loop);
+  }
+
+  void AddIOObserver(IOObserver* io_observer) {
+    pump_io()->AddIOObserver(io_observer);
+  }
+
+  void RemoveIOObserver(IOObserver* io_observer) {
+    pump_io()->RemoveIOObserver(io_observer);
+  }
+
+#if defined(OS_WIN)
+  // Please see MessagePumpWin for definitions of these methods.
+  void RegisterIOHandler(HANDLE file, IOHandler* handler);
+  bool RegisterJobObject(HANDLE job, IOHandler* handler);
+  bool WaitForIOCompletion(DWORD timeout, IOHandler* filter);
+
+ protected:
+  // TODO(rvargas): Make this platform independent.
+  base::MessagePumpForIO* pump_io() {
+    return static_cast<base::MessagePumpForIO*>(pump_.get());
+  }
+
+#elif defined(OS_POSIX)
+  // Please see MessagePumpLibevent for definition.
+  bool WatchFileDescriptor(int fd,
+                           bool persistent,
+                           Mode mode,
+                           FileDescriptorWatcher* controller,
+                           Watcher* delegate);
+
+ private:
+  base::MessagePumpLibevent* pump_io() {
+    return static_cast<base::MessagePumpLibevent*>(pump_.get());
+  }
+#endif  // defined(OS_POSIX)
+};
+
+// Do not add any member variables to MessageLoopForIO!  This is important b/c
+// MessageLoopForIO is often allocated via MessageLoop(TYPE_IO).  Any extra
+// data that you need should be stored on the MessageLoop's pump_ instance.
+COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
+               MessageLoopForIO_should_not_have_extra_member_variables);
+
+#endif  // BASE_MESSAGE_LOOP_H_
diff --git a/base/message_loop_proxy.cc b/base/message_loop_proxy.cc
new file mode 100644
index 0000000..755564b
--- /dev/null
+++ b/base/message_loop_proxy.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop_proxy.h"
+
+#include "base/bind.h"
+
+namespace base {
+
+MessageLoopProxy::MessageLoopProxy() {
+}
+
+MessageLoopProxy::~MessageLoopProxy() {
+}
+
+}  // namespace base
diff --git a/base/message_loop_proxy.h b/base/message_loop_proxy.h
new file mode 100644
index 0000000..ce949dd
--- /dev/null
+++ b/base/message_loop_proxy.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_MESSAGE_LOOP_PROXY_H_
+#define BASE_MESSAGE_LOOP_PROXY_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// This class provides a thread-safe refcounted interface to the Post* methods
+// of a message loop. This class can outlive the target message loop.
+// MessageLoopProxy objects are constructed automatically for all MessageLoops.
+// So, to access them, you can use any of the following:
+//   Thread::message_loop_proxy()
+//   MessageLoop::current()->message_loop_proxy()
+//   MessageLoopProxy::current()
+//
+// TODO(akalin): Now that we have the *TaskRunner interfaces, we can
+// merge this with MessageLoopProxyImpl.
+class BASE_EXPORT MessageLoopProxy : public SingleThreadTaskRunner {
+ public:
+  // Gets the MessageLoopProxy for the current message loop, creating one if
+  // needed.
+  static scoped_refptr<MessageLoopProxy> current();
+
+ protected:
+  MessageLoopProxy();
+  virtual ~MessageLoopProxy();
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_PROXY_H_
diff --git a/base/message_loop_proxy_impl.cc b/base/message_loop_proxy_impl.cc
new file mode 100644
index 0000000..b4ca210
--- /dev/null
+++ b/base/message_loop_proxy_impl.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop_proxy_impl.h"
+
+#include "base/location.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+MessageLoopProxyImpl::~MessageLoopProxyImpl() {
+}
+
+bool MessageLoopProxyImpl::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  return PostTaskHelper(from_here, task, delay, true);
+}
+
+bool MessageLoopProxyImpl::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  return PostTaskHelper(from_here, task, delay, false);
+}
+
+bool MessageLoopProxyImpl::RunsTasksOnCurrentThread() const {
+  // We shouldn't use MessageLoop::current() since it uses LazyInstance which
+  // may be deleted by ~AtExitManager when a WorkerPool thread calls this
+  // function.
+  // http://crbug.com/63678
+  base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
+  AutoLock lock(message_loop_lock_);
+  return (target_message_loop_ &&
+          (MessageLoop::current() == target_message_loop_));
+}
+
+// MessageLoop::DestructionObserver implementation
+void MessageLoopProxyImpl::WillDestroyCurrentMessageLoop() {
+  AutoLock lock(message_loop_lock_);
+  target_message_loop_ = NULL;
+}
+
+void MessageLoopProxyImpl::OnDestruct() const {
+  // We shouldn't use MessageLoop::current() since it uses LazyInstance which
+  // may be deleted by ~AtExitManager when a WorkerPool thread calls this
+  // function.
+  // http://crbug.com/63678
+  base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
+  bool delete_later = false;
+  {
+    AutoLock lock(message_loop_lock_);
+    if (target_message_loop_ &&
+        (MessageLoop::current() != target_message_loop_)) {
+      target_message_loop_->DeleteSoon(FROM_HERE, this);
+      delete_later = true;
+    }
+  }
+  if (!delete_later)
+    delete this;
+}
+
+MessageLoopProxyImpl::MessageLoopProxyImpl()
+    : target_message_loop_(MessageLoop::current()) {
+}
+
+bool MessageLoopProxyImpl::PostTaskHelper(
+    const tracked_objects::Location& from_here, const base::Closure& task,
+    base::TimeDelta delay, bool nestable) {
+  AutoLock lock(message_loop_lock_);
+  if (target_message_loop_) {
+    if (nestable) {
+      target_message_loop_->PostDelayedTask(from_here, task, delay);
+    } else {
+      target_message_loop_->PostNonNestableDelayedTask(from_here, task, delay);
+    }
+    return true;
+  }
+  return false;
+}
+
+scoped_refptr<MessageLoopProxy>
+MessageLoopProxy::current() {
+  MessageLoop* cur_loop = MessageLoop::current();
+  if (!cur_loop)
+    return NULL;
+  return cur_loop->message_loop_proxy();
+}
+
+}  // namespace base
diff --git a/base/message_loop_proxy_impl.h b/base/message_loop_proxy_impl.h
new file mode 100644
index 0000000..2bcd8fd
--- /dev/null
+++ b/base/message_loop_proxy_impl.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_MESSAGE_LOOP_PROXY_IMPL_H_
+#define BASE_MESSAGE_LOOP_PROXY_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// A stock implementation of MessageLoopProxy that is created and managed by a
+// MessageLoop. For now a MessageLoopProxyImpl can only be created as part of a
+// MessageLoop.
+class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy {
+ public:
+  // MessageLoopProxy implementation
+  virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+                               const base::Closure& task,
+                               base::TimeDelta delay) OVERRIDE;
+  virtual bool PostNonNestableDelayedTask(
+      const tracked_objects::Location& from_here,
+      const base::Closure& task,
+      base::TimeDelta delay) OVERRIDE;
+  virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
+
+ protected:
+  virtual ~MessageLoopProxyImpl();
+
+  // Override OnDestruct so that we can delete the object on the target message
+  // loop if it still exists.
+  virtual void OnDestruct() const OVERRIDE;
+
+ private:
+  // Allow the MessageLoop to create a MessageLoopProxyImpl.
+  friend class ::MessageLoop;
+  friend class DeleteHelper<MessageLoopProxyImpl>;
+
+  MessageLoopProxyImpl();
+
+  // Called directly by MessageLoop::~MessageLoop.
+  virtual void WillDestroyCurrentMessageLoop();
+
+
+  bool PostTaskHelper(const tracked_objects::Location& from_here,
+                      const base::Closure& task,
+                      base::TimeDelta delay,
+                      bool nestable);
+
+  // The lock that protects access to target_message_loop_.
+  mutable base::Lock message_loop_lock_;
+  MessageLoop* target_message_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageLoopProxyImpl);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_PROXY_IMPL_H_
diff --git a/base/message_loop_proxy_impl_unittest.cc b/base/message_loop_proxy_impl_unittest.cc
new file mode 100644
index 0000000..e97d8f1
--- /dev/null
+++ b/base/message_loop_proxy_impl_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 "base/message_loop_proxy_impl.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+
+class MessageLoopProxyImplTest : public testing::Test {
+ public:
+  void Release() const {
+    AssertOnIOThread();
+    Quit();
+  }
+
+  void Quit() const {
+    loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure());
+  }
+
+  void AssertOnIOThread() const {
+    ASSERT_TRUE(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+    ASSERT_EQ(io_thread_->message_loop_proxy(),
+              base::MessageLoopProxy::current());
+  }
+
+  void AssertOnFileThread() const {
+    ASSERT_TRUE(file_thread_->message_loop_proxy()->BelongsToCurrentThread());
+    ASSERT_EQ(file_thread_->message_loop_proxy(),
+              base::MessageLoopProxy::current());
+  }
+
+ protected:
+  virtual void SetUp() OVERRIDE {
+    io_thread_.reset(new base::Thread("MessageLoopProxyImplTest_IO"));
+    file_thread_.reset(new base::Thread("MessageLoopProxyImplTest_File"));
+    io_thread_->Start();
+    file_thread_->Start();
+  }
+
+  virtual void TearDown() OVERRIDE {
+    io_thread_->Stop();
+    file_thread_->Stop();
+  }
+
+  static void BasicFunction(MessageLoopProxyImplTest* test) {
+    test->AssertOnFileThread();
+    test->Quit();
+  }
+
+  static void AssertNotRun() {
+    FAIL() << "Callback Should not get executed.";
+  }
+
+  class DeletedOnFile {
+   public:
+    explicit DeletedOnFile(MessageLoopProxyImplTest* test) : test_(test) {}
+
+    ~DeletedOnFile() {
+      test_->AssertOnFileThread();
+      test_->Quit();
+    }
+
+   private:
+    MessageLoopProxyImplTest* test_;
+  };
+
+  scoped_ptr<base::Thread> io_thread_;
+  scoped_ptr<base::Thread> file_thread_;
+
+ private:
+  mutable MessageLoop loop_;
+};
+
+TEST_F(MessageLoopProxyImplTest, Release) {
+  EXPECT_TRUE(io_thread_->message_loop_proxy()->ReleaseSoon(FROM_HERE, this));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopProxyImplTest, Delete) {
+  DeletedOnFile* deleted_on_file = new DeletedOnFile(this);
+  EXPECT_TRUE(file_thread_->message_loop_proxy()->DeleteSoon(
+      FROM_HERE, deleted_on_file));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopProxyImplTest, PostTask) {
+  EXPECT_TRUE(file_thread_->message_loop_proxy()->PostTask(
+      FROM_HERE, base::Bind(&MessageLoopProxyImplTest::BasicFunction,
+                            base::Unretained(this))));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopProxyImplTest, PostTaskAfterThreadExits) {
+  scoped_ptr<base::Thread> test_thread(
+      new base::Thread("MessageLoopProxyImplTest_Dummy"));
+  test_thread->Start();
+  scoped_refptr<base::MessageLoopProxy> message_loop_proxy =
+      test_thread->message_loop_proxy();
+  test_thread->Stop();
+
+  bool ret = message_loop_proxy->PostTask(
+      FROM_HERE,
+      base::Bind(&MessageLoopProxyImplTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+TEST_F(MessageLoopProxyImplTest, PostTaskAfterThreadIsDeleted) {
+  scoped_refptr<base::MessageLoopProxy> message_loop_proxy;
+  {
+    scoped_ptr<base::Thread> test_thread(
+        new base::Thread("MessageLoopProxyImplTest_Dummy"));
+    test_thread->Start();
+    message_loop_proxy = test_thread->message_loop_proxy();
+  }
+  bool ret = message_loop_proxy->PostTask(
+      FROM_HERE,
+      base::Bind(&MessageLoopProxyImplTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
diff --git a/base/message_loop_proxy_unittest.cc b/base/message_loop_proxy_unittest.cc
new file mode 100644
index 0000000..4776502
--- /dev/null
+++ b/base/message_loop_proxy_unittest.cc
@@ -0,0 +1,266 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop_proxy.h"
+
+#include "base/atomic_sequence_num.h"
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class MessageLoopProxyTest : public testing::Test {
+ public:
+  MessageLoopProxyTest()
+      : current_loop_(new MessageLoop()),
+        task_thread_("task_thread"),
+        thread_sync_(true, false) {
+  }
+
+  void DeleteCurrentMessageLoop() {
+    current_loop_.reset();
+  }
+
+ protected:
+  virtual void SetUp() OVERRIDE {
+    // Use SetUp() instead of the constructor to avoid posting a task to a
+    // partialy constructed object.
+    task_thread_.Start();
+
+    // Allow us to pause the |task_thread_|'s MessageLoop.
+    task_thread_.message_loop()->PostTask(
+        FROM_HERE,
+        Bind(&MessageLoopProxyTest::BlockTaskThreadHelper, Unretained(this)));
+  }
+
+  virtual void TearDown() OVERRIDE {
+    // Make sure the |task_thread_| is not blocked, and stop the thread
+    // fully before destuction because its tasks may still depend on the
+    // |thread_sync_| event.
+    thread_sync_.Signal();
+    task_thread_.Stop();
+    DeleteCurrentMessageLoop();
+  }
+
+  // Make LoopRecorder threadsafe so that there is defined behavior even if a
+  // threading mistake sneaks into the PostTaskAndReplyRelay implementation.
+  class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
+   public:
+    LoopRecorder(MessageLoop** run_on, MessageLoop** deleted_on,
+                 int* destruct_order)
+        : run_on_(run_on),
+          deleted_on_(deleted_on),
+          destruct_order_(destruct_order) {
+    }
+
+    void RecordRun() {
+      *run_on_ = MessageLoop::current();
+    }
+
+   private:
+    friend class RefCountedThreadSafe<LoopRecorder>;
+    ~LoopRecorder() {
+      *deleted_on_ = MessageLoop::current();
+      *destruct_order_ = g_order.GetNext();
+    }
+
+    MessageLoop** run_on_;
+    MessageLoop** deleted_on_;
+    int* destruct_order_;
+  };
+
+  static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
+    recorder->RecordRun();
+  }
+
+  static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
+    recorder->RecordRun();
+    MessageLoop::current()->Quit();
+  }
+
+  void UnblockTaskThread() {
+    thread_sync_.Signal();
+  }
+
+  void BlockTaskThreadHelper() {
+    thread_sync_.Wait();
+  }
+
+  static StaticAtomicSequenceNumber g_order;
+
+  scoped_ptr<MessageLoop> current_loop_;
+  Thread task_thread_;
+
+ private:
+  base::WaitableEvent thread_sync_;
+};
+
+StaticAtomicSequenceNumber MessageLoopProxyTest::g_order;
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  ASSERT_TRUE(task_thread_.message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  UnblockTaskThread();
+  current_loop_->Run();
+
+  EXPECT_EQ(task_thread_.message_loop(), task_run_on);
+  EXPECT_EQ(current_loop_.get(), task_deleted_on);
+  EXPECT_EQ(current_loop_.get(), reply_run_on);
+  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
+  EXPECT_LT(task_delete_order, reply_delete_order);
+}
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Grab a MessageLoopProxy to a dead MessageLoop.
+  scoped_refptr<MessageLoopProxy> task_loop_proxy =
+      task_thread_.message_loop_proxy();
+  UnblockTaskThread();
+  task_thread_.Stop();
+
+  ASSERT_FALSE(task_loop_proxy->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // The relay should have properly deleted its resources leaving us as the only
+  // reference.
+  EXPECT_EQ(task_delete_order, reply_delete_order);
+  ASSERT_TRUE(task_recoder->HasOneRef());
+  ASSERT_TRUE(reply_recoder->HasOneRef());
+
+  // Nothing should have run though.
+  EXPECT_FALSE(task_run_on);
+  EXPECT_FALSE(reply_run_on);
+}
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Enqueue the relay.
+  ASSERT_TRUE(current_loop_->message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  current_loop_->Run();
+
+  EXPECT_EQ(current_loop_.get(), task_run_on);
+  EXPECT_EQ(current_loop_.get(), task_deleted_on);
+  EXPECT_EQ(current_loop_.get(), reply_run_on);
+  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
+  EXPECT_LT(task_delete_order, reply_delete_order);
+}
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
+  // Annotate the scope as having memory leaks to suppress heapchecker reports.
+  ANNOTATE_SCOPED_MEMORY_LEAK;
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Enqueue the relay.
+  task_thread_.message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  UnblockTaskThread();
+
+  // Mercilessly whack the current loop before |reply| gets to run.
+  current_loop_.reset();
+
+  // This should ensure the relay has been run.  We need to record the
+  // MessageLoop pointer before stopping the thread because Thread::Stop() will
+  // NULL out its own pointer.
+  MessageLoop* task_loop = task_thread_.message_loop();
+  task_thread_.Stop();
+
+  EXPECT_EQ(task_loop, task_run_on);
+  ASSERT_FALSE(task_deleted_on);
+  EXPECT_FALSE(reply_run_on);
+  ASSERT_FALSE(reply_deleted_on);
+  EXPECT_EQ(task_delete_order, reply_delete_order);
+
+  // The PostTaskAndReplyRelay is leaked here.  Even if we had a reference to
+  // it, we cannot just delete it because PostTaskAndReplyRelay's destructor
+  // checks that MessageLoop::current() is the the same as when the
+  // PostTaskAndReplyRelay object was constructed.  However, this loop must have
+  // aleady been deleted in order to perform this test.  See
+  // http://crbug.com/86301.
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc
new file mode 100644
index 0000000..e8abb1a
--- /dev/null
+++ b/base/message_loop_unittest.cc
@@ -0,0 +1,2063 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop.h"
+#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "base/message_pump_win.h"
+#include "base/win/scoped_handle.h"
+#endif
+
+using base::PlatformThread;
+using base::Thread;
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+
+// TODO(darin): Platform-specific MessageLoop tests should be grouped together
+// to avoid chopping this file up with so many #ifdefs.
+
+namespace {
+
+class MessageLoopTest : public testing::Test {};
+
+class Foo : public base::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 base::RefCounted<Foo>;
+
+  ~Foo() {}
+
+  int test_count_;
+  std::string result_;
+};
+
+void RunTest_PostTask(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  // Add tests to message loop
+  scoped_refptr<Foo> foo(new Foo());
+  std::string a("a"), b("b"), c("c"), d("d");
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test0, foo.get()));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+    &Foo::Test1ConstRef, foo.get(), a));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test1Ptr, foo.get(), &b));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test1Int, foo.get(), 100));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test2Ptr, foo.get(), &a, &c));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test2Mixed, foo.get(), a, &d));
+
+  // After all tests, post a message that will shut down the message loop
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
+
+  // Now kick things off
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(foo->test_count(), 105);
+  EXPECT_EQ(foo->result(), "abacad");
+}
+
+void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  // Add tests to message loop
+  scoped_refptr<Foo> foo(new Foo());
+  std::string a("a"), b("b"), c("c"), d("d");
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test0, foo.get()));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test1ConstRef, foo.get(), a));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test1Ptr, foo.get(), &b));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test1Int, foo.get(), 100));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test2Ptr, foo.get(), &a, &c));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test2Mixed, foo.get(), a, &d));
+
+  // After all tests, post a message that will shut down the message loop
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
+
+  // Now kick things off with the SEH block active.
+  MessageLoop::current()->set_exception_restoration(true);
+  MessageLoop::current()->Run();
+  MessageLoop::current()->set_exception_restoration(false);
+
+  EXPECT_EQ(foo->test_count(), 105);
+  EXPECT_EQ(foo->result(), "abacad");
+}
+
+// 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()->Quit();
+}
+
+// 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 RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  // Test that PostDelayedTask results in a delayed task.
+
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  int num_tasks = 1;
+  Time run_time;
+
+  loop.PostDelayedTask(
+      FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+      kDelay);
+
+  Time time_before_run = Time::Now();
+  loop.Run();
+  Time time_after_run = Time::Now();
+
+  EXPECT_EQ(0, num_tasks);
+  EXPECT_LT(kDelay, time_after_run - time_before_run);
+}
+
+void RunTest_PostDelayedTask_InDelayOrder(
+    MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  // Test that two tasks with different delays run in the right order.
+  int num_tasks = 2;
+  Time run_time1, run_time2;
+
+  loop.PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
+      TimeDelta::FromMilliseconds(200));
+  // If we get a large pause in execution (due to a context switch) here, this
+  // test could fail.
+  loop.PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time2 < run_time1);
+}
+
+void RunTest_PostDelayedTask_InPostOrder(
+    MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  // Test that two tasks with the same delay run in the order in which they
+  // were posted.
+  //
+  // NOTE: This is actually an approximate test since the API only takes a
+  // "delay" parameter, so we are not exactly simulating two tasks that get
+  // posted at the exact same time.  It would be nice if the API allowed us to
+  // specify the desired run time.
+
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  int num_tasks = 2;
+  Time run_time1, run_time2;
+
+  loop.PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay);
+  loop.PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay);
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time1 < run_time2);
+}
+
+void RunTest_PostDelayedTask_InPostOrder_2(
+    MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  // Test that a delayed task still runs after a normal tasks even if the
+  // normal tasks take a long time to run.
+
+  const TimeDelta kPause = TimeDelta::FromMilliseconds(50);
+
+  int num_tasks = 2;
+  Time run_time;
+
+  loop.PostTask(FROM_HERE, base::Bind(&SlowFunc, kPause, &num_tasks));
+  loop.PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  Time time_before_run = Time::Now();
+  loop.Run();
+  Time time_after_run = Time::Now();
+
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_LT(kPause, time_after_run - time_before_run);
+}
+
+void RunTest_PostDelayedTask_InPostOrder_3(
+    MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  // Test that a delayed task still runs after a pile of normal tasks.  The key
+  // difference between this test and the previous one is that here we return
+  // the MessageLoop a lot so we give the MessageLoop plenty of opportunities
+  // to maybe run the delayed task.  It should know not to do so until the
+  // delayed task's delay has passed.
+
+  int num_tasks = 11;
+  Time run_time1, run_time2;
+
+  // Clutter the ML with tasks.
+  for (int i = 1; i < num_tasks; ++i)
+    loop.PostTask(FROM_HERE,
+                  base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks));
+
+  loop.PostDelayedTask(
+      FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(1));
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time2 > run_time1);
+}
+
+void RunTest_PostDelayedTask_SharedTimer(
+    MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  // Test that the interval of the timer, used to run the next delayed task, is
+  // set to a value corresponding to when the next delayed task should run.
+
+  // By setting num_tasks to 1, we ensure that the first task to run causes the
+  // run loop to exit.
+  int num_tasks = 1;
+  Time run_time1, run_time2;
+
+  loop.PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
+      TimeDelta::FromSeconds(1000));
+  loop.PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  Time start_time = Time::Now();
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  // Ensure that we ran in far less time than the slower timer.
+  TimeDelta total_time = Time::Now() - start_time;
+  EXPECT_GT(5000, total_time.InMilliseconds());
+
+  // In case both timers somehow run at nearly the same time, sleep a little
+  // and then run all pending to force them both to have run.  This is just
+  // encouraging flakiness if there is any.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  loop.RunUntilIdle();
+
+  EXPECT_TRUE(run_time1.is_null());
+  EXPECT_FALSE(run_time2.is_null());
+}
+
+#if defined(OS_WIN)
+
+void SubPumpFunc() {
+  MessageLoop::current()->SetNestableTasksAllowed(true);
+  MSG msg;
+  while (GetMessage(&msg, NULL, 0, 0)) {
+    TranslateMessage(&msg);
+    DispatchMessage(&msg);
+  }
+  MessageLoop::current()->Quit();
+}
+
+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, base::Bind(&SubPumpFunc));
+
+  // This very delayed task should never run.
+  loop.PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+      TimeDelta::FromSeconds(1000));
+
+  // This slightly delayed task should run from within SubPumpFunc).
+  loop.PostDelayedTask(
+      FROM_HERE,
+      base::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));
+  loop.RunUntilIdle();
+
+  EXPECT_TRUE(run_time.is_null());
+}
+
+#endif  // defined(OS_WIN)
+
+// 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 base::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 base::RefCounted<RecordDeletionProbe>;
+
+  ~RecordDeletionProbe() {
+    *was_deleted_ = true;
+    if (post_on_delete_)
+      MessageLoop::current()->PostTask(
+          FROM_HERE,
+          base::Bind(&RecordDeletionProbe::Run, post_on_delete_.get()));
+  }
+
+  scoped_refptr<RecordDeletionProbe> post_on_delete_;
+  bool* was_deleted_;
+};
+
+void RunTest_EnsureDeletion(MessageLoop::Type message_loop_type) {
+  bool a_was_deleted = false;
+  bool b_was_deleted = false;
+  {
+    MessageLoop loop(message_loop_type);
+    loop.PostTask(
+        FROM_HERE, base::Bind(&RecordDeletionProbe::Run,
+                              new RecordDeletionProbe(NULL, &a_was_deleted)));
+    // TODO(ajwong): Do we really need 1000ms here?
+    loop.PostDelayedTask(
+        FROM_HERE, base::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(MessageLoop::Type message_loop_type) {
+  bool a_was_deleted = false;
+  bool b_was_deleted = false;
+  bool c_was_deleted = false;
+  {
+    MessageLoop loop(message_loop_type);
+    // The scoped_refptr for each of the below is held either by the chained
+    // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback.
+    RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted);
+    RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted);
+    RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted);
+    loop.PostTask(FROM_HERE, base::Bind(&RecordDeletionProbe::Run, c));
+  }
+  EXPECT_TRUE(a_was_deleted);
+  EXPECT_TRUE(b_was_deleted);
+  EXPECT_TRUE(c_was_deleted);
+}
+
+void NestingFunc(int* depth) {
+  if (*depth > 0) {
+    *depth -= 1;
+    MessageLoop::current()->PostTask(FROM_HERE,
+                                     base::Bind(&NestingFunc, depth));
+
+    MessageLoop::current()->SetNestableTasksAllowed(true);
+    MessageLoop::current()->Run();
+  }
+  MessageLoop::current()->Quit();
+}
+
+#if defined(OS_WIN)
+
+LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) {
+  ADD_FAILURE() << "bad exception handler";
+  ::ExitProcess(ex_info->ExceptionRecord->ExceptionCode);
+  return EXCEPTION_EXECUTE_HANDLER;
+}
+
+// This task throws an SEH exception: initially write to an invalid address.
+// If the right SEH filter is installed, it will fix the error.
+class Crasher : public base::RefCounted<Crasher> {
+ public:
+  // Ctor. If trash_SEH_handler is true, the task will override the unhandled
+  // exception handler with one sure to crash this test.
+  explicit Crasher(bool trash_SEH_handler)
+      : trash_SEH_handler_(trash_SEH_handler) {
+  }
+
+  void Run() {
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
+    if (trash_SEH_handler_)
+      ::SetUnhandledExceptionFilter(&BadExceptionHandler);
+    // Generate a SEH fault. We do it in asm to make sure we know how to undo
+    // the damage.
+
+#if defined(_M_IX86)
+
+    __asm {
+      mov eax, dword ptr [Crasher::bad_array_]
+      mov byte ptr [eax], 66
+    }
+
+#elif defined(_M_X64)
+
+    bad_array_[0] = 66;
+
+#else
+#error "needs architecture support"
+#endif
+
+    MessageLoop::current()->Quit();
+  }
+  // Points the bad array to a valid memory location.
+  static void FixError() {
+    bad_array_ = &valid_store_;
+  }
+
+ private:
+  bool trash_SEH_handler_;
+  static volatile char* bad_array_;
+  static char valid_store_;
+};
+
+volatile char* Crasher::bad_array_ = 0;
+char Crasher::valid_store_ = 0;
+
+// This SEH filter fixes the problem and retries execution. Fixing requires
+// that the last instruction: mov eax, [Crasher::bad_array_] to be retried
+// so we move the instruction pointer 5 bytes back.
+LONG WINAPI HandleCrasherException(EXCEPTION_POINTERS *ex_info) {
+  if (ex_info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
+    return EXCEPTION_EXECUTE_HANDLER;
+
+  Crasher::FixError();
+
+#if defined(_M_IX86)
+
+  ex_info->ContextRecord->Eip -= 5;
+
+#elif defined(_M_X64)
+
+  ex_info->ContextRecord->Rip -= 5;
+
+#endif
+
+  return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+void RunTest_Crasher(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  if (::IsDebuggerPresent())
+    return;
+
+  LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
+      ::SetUnhandledExceptionFilter(&HandleCrasherException);
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&Crasher::Run, new Crasher(false)));
+  MessageLoop::current()->set_exception_restoration(true);
+  MessageLoop::current()->Run();
+  MessageLoop::current()->set_exception_restoration(false);
+
+  ::SetUnhandledExceptionFilter(old_SEH_filter);
+}
+
+void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  if (::IsDebuggerPresent())
+    return;
+
+  LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
+      ::SetUnhandledExceptionFilter(&HandleCrasherException);
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&Crasher::Run, new Crasher(true)));
+  MessageLoop::current()->set_exception_restoration(true);
+  MessageLoop::current()->Run();
+  MessageLoop::current()->set_exception_restoration(false);
+
+  ::SetUnhandledExceptionFilter(old_SEH_filter);
+}
+
+#endif  // defined(OS_WIN)
+
+void RunTest_Nesting(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  int depth = 100;
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   base::Bind(&NestingFunc, &depth));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(depth, 0);
+}
+
+const wchar_t* const 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_;
+};
+
+// Saves the order the tasks ran.
+void OrderedFunc(TaskList* order, int cookie) {
+  order->RecordStart(ORDERED, cookie);
+  order->RecordEnd(ORDERED, cookie);
+}
+
+#if defined(OS_WIN)
+
+// 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);
+  }
+}
+
+#endif  // defined(OS_WIN)
+
+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,
+        base::Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant));
+  }
+  order->RecordEnd(RECURSIVE, cookie);
+}
+
+void RecursiveSlowFunc(TaskList* order, int cookie, int depth,
+                       bool is_reentrant) {
+  RecursiveFunc(order, cookie, depth, is_reentrant);
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
+}
+
+void QuitFunc(TaskList* order, int cookie) {
+  order->RecordStart(QUITMESSAGELOOP, cookie);
+  MessageLoop::current()->Quit();
+  order->RecordEnd(QUITMESSAGELOOP, cookie);
+}
+
+void SleepFunc(TaskList* order, int cookie, TimeDelta delay) {
+  order->RecordStart(SLEEP, cookie);
+  PlatformThread::Sleep(delay);
+  order->RecordEnd(SLEEP, cookie);
+}
+
+#if defined(OS_WIN)
+void RecursiveFuncWin(MessageLoop* target,
+                      HANDLE event,
+                      bool expect_window,
+                      TaskList* order,
+                      bool is_reentrant) {
+  target->PostTask(FROM_HERE,
+                   base::Bind(&RecursiveFunc, order, 1, 2, is_reentrant));
+  target->PostTask(FROM_HERE,
+                   base::Bind(&MessageBoxFunc, order, 2, is_reentrant));
+  target->PostTask(FROM_HERE,
+                   base::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,
+                   base::Bind(&EndDialogFunc, order, 4));
+  target->PostTask(FROM_HERE,
+                   base::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;
+    }
+  }
+}
+
+#endif  // defined(OS_WIN)
+
+void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
+  TaskList order;
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&RecursiveFunc, &order, 1, 2, false));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&RecursiveFunc, &order, 2, 2, false));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&QuitFunc, &order, 3));
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(14U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+  EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
+}
+
+void RunTest_RecursiveDenial3(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
+  TaskList order;
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&RecursiveSlowFunc, &order, 1, 2, false));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&RecursiveSlowFunc, &order, 2, 2, false));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&OrderedFunc, &order, 3),
+      TimeDelta::FromMilliseconds(5));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&QuitFunc, &order, 4),
+      TimeDelta::FromMilliseconds(5));
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(16U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(7), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true));
+  EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false));
+}
+
+void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&RecursiveFunc, &order, 1, 2, true));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&RecursiveFunc, &order, 2, 2, true));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&QuitFunc, &order, 3));
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(14U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+  EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
+}
+
+#if defined(OS_WIN)
+// 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;
+  base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
+  worker.message_loop()->PostTask(FROM_HERE,
+                                  base::Bind(&RecursiveFuncWin,
+                                             MessageLoop::current(),
+                                             event.Get(),
+                                             true,
+                                             &order,
+                                             false));
+  // Let the other thread execute.
+  WaitForSingleObject(event, INFINITE);
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(order.Size(), 17);
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false));
+  // When EndDialogFunc is processed, the window is already dismissed, hence no
+  // "end" entry.
+  EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true));
+  EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true));
+  EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false));
+}
+
+// A side effect of this test is the generation a beep. Sorry.  This test also
+// needs to process windows messages on the current thread.
+void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  Thread worker("RecursiveSupport2_worker");
+  Thread::Options options;
+  options.message_loop_type = message_loop_type;
+  ASSERT_EQ(true, worker.StartWithOptions(options));
+  TaskList order;
+  base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
+  worker.message_loop()->PostTask(FROM_HERE,
+                                  base::Bind(&RecursiveFuncWin,
+                                             MessageLoop::current(),
+                                             event.Get(),
+                                             false,
+                                             &order,
+                                             true));
+  // Let the other thread execute.
+  WaitForSingleObject(event, INFINITE);
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(order.Size(), 18);
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
+  // Note that this executes in the MessageBox modal loop.
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false));
+  EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true));
+  EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false));
+  EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false));
+  /* The order can subtly change here. The reason is that when RecursiveFunc(1)
+     is called in the main thread, if it is faster than getting to the
+     PostTask(FROM_HERE, base::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 FuncThatPumps(TaskList* order, int cookie) {
+  order->RecordStart(PUMPS, cookie);
+  {
+    MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
+    MessageLoop::current()->RunUntilIdle();
+  }
+  order->RecordEnd(PUMPS, cookie);
+}
+
+void FuncThatRuns(TaskList* order, int cookie, base::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 that non nestable tasks run in FIFO if there are no nested loops.
+void RunTest_NonNestableWithNoNesting(
+    MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+
+  MessageLoop::current()->PostNonNestableTask(
+      FROM_HERE,
+      base::Bind(&OrderedFunc, &order, 1));
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   base::Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   base::Bind(&QuitFunc, &order, 3));
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(6U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+}
+
+// Tests that non nestable tasks don't run when there's code in the call stack.
+void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type,
+                                     bool use_delayed) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&FuncThatPumps, &order, 1));
+  if (use_delayed) {
+    MessageLoop::current()->PostNonNestableDelayedTask(
+        FROM_HERE,
+        base::Bind(&OrderedFunc, &order, 2),
+        TimeDelta::FromMilliseconds(1));
+  } else {
+    MessageLoop::current()->PostNonNestableTask(
+        FROM_HERE,
+        base::Bind(&OrderedFunc, &order, 2));
+  }
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   base::Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   base::Bind(&OrderedFunc, &order, 5));
+  if (use_delayed) {
+    MessageLoop::current()->PostNonNestableDelayedTask(
+        FROM_HERE,
+        base::Bind(&QuitFunc, &order, 6),
+        TimeDelta::FromMilliseconds(2));
+  } else {
+    MessageLoop::current()->PostNonNestableTask(
+        FROM_HERE,
+        base::Bind(&QuitFunc, &order, 6));
+  }
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(12U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true));
+  EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false));
+  EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true));
+  EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false));
+  EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false));
+  EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true));
+  EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false));
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_QuitNow(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+
+  base::RunLoop run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      base::Bind(&FuncThatRuns, &order, 1, base::Unretained(&run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 4)); // never runs
+
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(6U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit works before RunWithID.
+void RunTest_RunLoopQuitOrderBefore(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+
+  base::RunLoop run_loop;
+
+  run_loop.Quit();
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 1)); // never runs
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&FuncThatQuitsNow)); // never runs
+
+  run_loop.Run();
+
+  ASSERT_EQ(0U, order.Size());
+}
+
+// Tests RunLoopQuit works during RunWithID.
+void RunTest_RunLoopQuitOrderDuring(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+
+  base::RunLoop run_loop;
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 1));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 2)); // never runs
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::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(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+
+  base::RunLoop run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      base::Bind(&FuncThatRuns, &order, 1, base::Unretained(&run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, run_loop.QuitClosure()); // has no affect
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 4));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&FuncThatQuitsNow));
+
+  base::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());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitTop(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+
+  base::RunLoop outer_run_loop;
+  base::RunLoop nested_run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      base::Bind(&FuncThatRuns, &order, 1, base::Unretained(&nested_run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_run_loop.QuitClosure());
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(4U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitNested(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+
+  base::RunLoop outer_run_loop;
+  base::RunLoop nested_run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      base::Bind(&FuncThatRuns, &order, 1, base::Unretained(&nested_run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(4U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitBogus(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+
+  base::RunLoop outer_run_loop;
+  base::RunLoop nested_run_loop;
+  base::RunLoop bogus_run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      base::Bind(&FuncThatRuns, &order, 1, base::Unretained(&nested_run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, bogus_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_run_loop.QuitClosure());
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(4U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitDeep(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  TaskList order;
+
+  base::RunLoop outer_run_loop;
+  base::RunLoop nested_loop1;
+  base::RunLoop nested_loop2;
+  base::RunLoop nested_loop3;
+  base::RunLoop nested_loop4;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      base::Bind(&FuncThatRuns, &order, 1, base::Unretained(&nested_loop1)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+      base::Bind(&FuncThatRuns, &order, 2, base::Unretained(&nested_loop2)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+      base::Bind(&FuncThatRuns, &order, 3, base::Unretained(&nested_loop3)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+      base::Bind(&FuncThatRuns, &order, 4, base::Unretained(&nested_loop4)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 5));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 6));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop1.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 7));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop2.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 8));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop3.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&OrderedFunc, &order, 9));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop4.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::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());
+}
+
+#if defined(OS_WIN)
+
+class DispatcherImpl : public MessageLoopForUI::Dispatcher {
+ public:
+  DispatcherImpl() : dispatch_count_(0) {}
+
+  virtual bool Dispatch(const base::NativeEvent& msg) OVERRIDE {
+    ::TranslateMessage(&msg);
+    ::DispatchMessage(&msg);
+    // Do not count WM_TIMER since it is not what we post and it will cause
+    // flakiness.
+    if (msg.message != WM_TIMER)
+      ++dispatch_count_;
+    // We treat WM_LBUTTONUP as the last message.
+    return msg.message != WM_LBUTTONUP;
+  }
+
+  int dispatch_count_;
+};
+
+void MouseDownUp() {
+  PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
+  PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
+}
+
+void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&MouseDownUp),
+      TimeDelta::FromMilliseconds(100));
+  DispatcherImpl dispatcher;
+  base::RunLoop run_loop(&dispatcher);
+  run_loop.Run();
+  ASSERT_EQ(2, dispatcher.dispatch_count_);
+}
+
+LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) {
+  if (code == base::MessagePumpForUI::kMessageFilterCode) {
+    MSG* msg = reinterpret_cast<MSG*>(lparam);
+    if (msg->message == WM_LBUTTONDOWN)
+      return TRUE;
+  }
+  return FALSE;
+}
+
+void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&MouseDownUp),
+      TimeDelta::FromMilliseconds(100));
+  HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER,
+                                    MsgFilterProc,
+                                    NULL,
+                                    GetCurrentThreadId());
+  DispatcherImpl dispatcher;
+  base::RunLoop run_loop(&dispatcher);
+  run_loop.Run();
+  ASSERT_EQ(1, dispatcher.dispatch_count_);
+  UnhookWindowsHookEx(msg_hook);
+}
+
+class TestIOHandler : public MessageLoopForIO::IOHandler {
+ public:
+  TestIOHandler(const wchar_t* name, HANDLE signal, bool wait);
+
+  virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
+                             DWORD bytes_transfered, DWORD error);
+
+  void Init();
+  void WaitForIO();
+  OVERLAPPED* context() { return &context_.overlapped; }
+  DWORD size() { return sizeof(buffer_); }
+
+ private:
+  char buffer_[48];
+  MessageLoopForIO::IOContext context_;
+  HANDLE signal_;
+  base::win::ScopedHandle file_;
+  bool wait_;
+};
+
+TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait)
+    : signal_(signal), wait_(wait) {
+  memset(buffer_, 0, sizeof(buffer_));
+  memset(&context_, 0, sizeof(context_));
+  context_.handler = this;
+
+  file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
+                       FILE_FLAG_OVERLAPPED, NULL));
+  EXPECT_TRUE(file_.IsValid());
+}
+
+void TestIOHandler::Init() {
+  MessageLoopForIO::current()->RegisterIOHandler(file_, this);
+
+  DWORD read;
+  EXPECT_FALSE(ReadFile(file_, buffer_, size(), &read, context()));
+  EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
+  if (wait_)
+    WaitForIO();
+}
+
+void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
+                                  DWORD bytes_transfered, DWORD error) {
+  ASSERT_TRUE(context == &context_);
+  ASSERT_TRUE(SetEvent(signal_));
+}
+
+void TestIOHandler::WaitForIO() {
+  EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this));
+  EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this));
+}
+
+void RunTest_IOHandler() {
+  base::win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
+  ASSERT_TRUE(callback_called.IsValid());
+
+  const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe";
+  base::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, false);
+  thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
+                                              base::Unretained(&handler)));
+  // Make sure the thread runs and sleeps for lack of work.
+  base::PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+
+  const char buffer[] = "Hello there!";
+  DWORD written;
+  EXPECT_TRUE(WriteFile(server, buffer, sizeof(buffer), &written, NULL));
+
+  DWORD result = WaitForSingleObject(callback_called, 1000);
+  EXPECT_EQ(WAIT_OBJECT_0, result);
+
+  thread.Stop();
+}
+
+void RunTest_WaitForIO() {
+  base::win::ScopedHandle callback1_called(
+      CreateEvent(NULL, TRUE, FALSE, NULL));
+  base::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";
+  base::win::ScopedHandle server1(
+      CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
+  base::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, false);
+  TestIOHandler handler2(kPipeName2, callback2_called, true);
+  thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
+                                              base::Unretained(&handler1)));
+  // TODO(ajwong): Do we really need such long Sleeps in ths function?
+  // Make sure the thread runs and sleeps for lack of work.
+  TimeDelta delay = TimeDelta::FromMilliseconds(100);
+  base::PlatformThread::Sleep(delay);
+  thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
+                                              base::Unretained(&handler2)));
+  base::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, buffer, sizeof(buffer), &written, NULL));
+  base::PlatformThread::Sleep(2 * delay);
+  EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called, 0)) <<
+      "handler1 has not been called";
+
+  EXPECT_TRUE(WriteFile(server2, 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.
+
+TEST(MessageLoopTest, PostTask) {
+  RunTest_PostTask(MessageLoop::TYPE_DEFAULT);
+  RunTest_PostTask(MessageLoop::TYPE_UI);
+  RunTest_PostTask(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, PostTask_SEH) {
+  RunTest_PostTask_SEH(MessageLoop::TYPE_DEFAULT);
+  RunTest_PostTask_SEH(MessageLoop::TYPE_UI);
+  RunTest_PostTask_SEH(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, PostDelayedTask_Basic) {
+  RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_DEFAULT);
+  RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_UI);
+  RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, PostDelayedTask_InDelayOrder) {
+  RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_DEFAULT);
+  RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_UI);
+  RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, PostDelayedTask_InPostOrder) {
+  RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_DEFAULT);
+  RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_UI);
+  RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, PostDelayedTask_InPostOrder_2) {
+  RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_DEFAULT);
+  RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_UI);
+  RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, PostDelayedTask_InPostOrder_3) {
+  RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_DEFAULT);
+  RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_UI);
+  RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, PostDelayedTask_SharedTimer) {
+  RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_DEFAULT);
+  RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_UI);
+  RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_IO);
+}
+
+#if defined(OS_WIN)
+TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
+  RunTest_PostDelayedTask_SharedTimer_SubPump();
+}
+#endif
+
+// TODO(darin): MessageLoop does not support deleting all tasks in the
+// destructor.
+// Fails, http://crbug.com/50272.
+TEST(MessageLoopTest, DISABLED_EnsureDeletion) {
+  RunTest_EnsureDeletion(MessageLoop::TYPE_DEFAULT);
+  RunTest_EnsureDeletion(MessageLoop::TYPE_UI);
+  RunTest_EnsureDeletion(MessageLoop::TYPE_IO);
+}
+
+// TODO(darin): MessageLoop does not support deleting all tasks in the
+// destructor.
+// Fails, http://crbug.com/50272.
+TEST(MessageLoopTest, DISABLED_EnsureDeletion_Chain) {
+  RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_DEFAULT);
+  RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_UI);
+  RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_IO);
+}
+
+#if defined(OS_WIN)
+TEST(MessageLoopTest, Crasher) {
+  RunTest_Crasher(MessageLoop::TYPE_DEFAULT);
+  RunTest_Crasher(MessageLoop::TYPE_UI);
+  RunTest_Crasher(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, CrasherNasty) {
+  RunTest_CrasherNasty(MessageLoop::TYPE_DEFAULT);
+  RunTest_CrasherNasty(MessageLoop::TYPE_UI);
+  RunTest_CrasherNasty(MessageLoop::TYPE_IO);
+}
+#endif  // defined(OS_WIN)
+
+TEST(MessageLoopTest, Nesting) {
+  RunTest_Nesting(MessageLoop::TYPE_DEFAULT);
+  RunTest_Nesting(MessageLoop::TYPE_UI);
+  RunTest_Nesting(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RecursiveDenial1) {
+  RunTest_RecursiveDenial1(MessageLoop::TYPE_DEFAULT);
+  RunTest_RecursiveDenial1(MessageLoop::TYPE_UI);
+  RunTest_RecursiveDenial1(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RecursiveDenial3) {
+  RunTest_RecursiveDenial3(MessageLoop::TYPE_DEFAULT);
+  RunTest_RecursiveDenial3(MessageLoop::TYPE_UI);
+  RunTest_RecursiveDenial3(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RecursiveSupport1) {
+  RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT);
+  RunTest_RecursiveSupport1(MessageLoop::TYPE_UI);
+  RunTest_RecursiveSupport1(MessageLoop::TYPE_IO);
+}
+
+#if defined(OS_WIN)
+// This test occasionally hangs http://crbug.com/44567
+TEST(MessageLoopTest, DISABLED_RecursiveDenial2) {
+  RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
+  RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
+  RunTest_RecursiveDenial2(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RecursiveSupport2) {
+  // This test requires a UI loop
+  RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
+}
+#endif  // defined(OS_WIN)
+
+TEST(MessageLoopTest, NonNestableWithNoNesting) {
+  RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_DEFAULT);
+  RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_UI);
+  RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, NonNestableInNestedLoop) {
+  RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, false);
+  RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, false);
+  RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, false);
+}
+
+TEST(MessageLoopTest, NonNestableDelayedInNestedLoop) {
+  RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, true);
+  RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, true);
+  RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, true);
+}
+
+TEST(MessageLoopTest, QuitNow) {
+  RunTest_QuitNow(MessageLoop::TYPE_DEFAULT);
+  RunTest_QuitNow(MessageLoop::TYPE_UI);
+  RunTest_QuitNow(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RunLoopQuitTop) {
+  RunTest_RunLoopQuitTop(MessageLoop::TYPE_DEFAULT);
+  RunTest_RunLoopQuitTop(MessageLoop::TYPE_UI);
+  RunTest_RunLoopQuitTop(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RunLoopQuitNested) {
+  RunTest_RunLoopQuitNested(MessageLoop::TYPE_DEFAULT);
+  RunTest_RunLoopQuitNested(MessageLoop::TYPE_UI);
+  RunTest_RunLoopQuitNested(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RunLoopQuitBogus) {
+  RunTest_RunLoopQuitBogus(MessageLoop::TYPE_DEFAULT);
+  RunTest_RunLoopQuitBogus(MessageLoop::TYPE_UI);
+  RunTest_RunLoopQuitBogus(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RunLoopQuitDeep) {
+  RunTest_RunLoopQuitDeep(MessageLoop::TYPE_DEFAULT);
+  RunTest_RunLoopQuitDeep(MessageLoop::TYPE_UI);
+  RunTest_RunLoopQuitDeep(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RunLoopQuitOrderBefore) {
+  RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_DEFAULT);
+  RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_UI);
+  RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RunLoopQuitOrderDuring) {
+  RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_DEFAULT);
+  RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_UI);
+  RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RunLoopQuitOrderAfter) {
+  RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_DEFAULT);
+  RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_UI);
+  RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_IO);
+}
+
+void PostNTasksThenQuit(int posts_remaining) {
+  if (posts_remaining > 1) {
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&PostNTasksThenQuit, posts_remaining - 1));
+  } else {
+    MessageLoop::current()->Quit();
+  }
+}
+
+class DummyTaskObserver : public MessageLoop::TaskObserver {
+ public:
+  explicit DummyTaskObserver(int num_tasks)
+      : num_tasks_started_(0),
+        num_tasks_processed_(0),
+        num_tasks_(num_tasks) {}
+
+  virtual ~DummyTaskObserver() {}
+
+  virtual void WillProcessTask(TimeTicks time_posted) OVERRIDE {
+    num_tasks_started_++;
+    EXPECT_TRUE(time_posted != TimeTicks());
+    EXPECT_LE(num_tasks_started_, num_tasks_);
+    EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
+  }
+
+  virtual void DidProcessTask(TimeTicks time_posted) OVERRIDE {
+    num_tasks_processed_++;
+    EXPECT_TRUE(time_posted != TimeTicks());
+    EXPECT_LE(num_tasks_started_, num_tasks_);
+    EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
+  }
+
+  int num_tasks_started() const { return num_tasks_started_; }
+  int num_tasks_processed() const { return num_tasks_processed_; }
+
+ private:
+  int num_tasks_started_;
+  int num_tasks_processed_;
+  const int num_tasks_;
+
+  DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver);
+};
+
+TEST(MessageLoopTest, TaskObserver) {
+  const int kNumPosts = 6;
+  DummyTaskObserver observer(kNumPosts);
+
+  MessageLoop loop;
+  loop.AddTaskObserver(&observer);
+  loop.PostTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, kNumPosts));
+  loop.Run();
+  loop.RemoveTaskObserver(&observer);
+
+  EXPECT_EQ(kNumPosts, observer.num_tasks_started());
+  EXPECT_EQ(kNumPosts, observer.num_tasks_processed());
+}
+
+#if defined(OS_WIN)
+TEST(MessageLoopTest, Dispatcher) {
+  // This test requires a UI loop
+  RunTest_Dispatcher(MessageLoop::TYPE_UI);
+}
+
+TEST(MessageLoopTest, DispatcherWithMessageHook) {
+  // This test requires a UI loop
+  RunTest_DispatcherWithMessageHook(MessageLoop::TYPE_UI);
+}
+
+TEST(MessageLoopTest, IOHandler) {
+  RunTest_IOHandler();
+}
+
+TEST(MessageLoopTest, WaitForIO) {
+  RunTest_WaitForIO();
+}
+
+TEST(MessageLoopTest, HighResolutionTimer) {
+  MessageLoop loop;
+
+  const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5);
+  const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100);
+
+  EXPECT_FALSE(loop.high_resolution_timers_enabled());
+
+  // Post a fast task to enable the high resolution timers.
+  loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
+                       kFastTimer);
+  loop.Run();
+  EXPECT_TRUE(loop.high_resolution_timers_enabled());
+
+  // Post a slow task and verify high resolution timers
+  // are still enabled.
+  loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
+                       kSlowTimer);
+  loop.Run();
+  EXPECT_TRUE(loop.high_resolution_timers_enabled());
+
+  // Wait for a while so that high-resolution mode elapses.
+  base::PlatformThread::Sleep(TimeDelta::FromMilliseconds(
+      MessageLoop::kHighResolutionTimerModeLeaseTimeMs));
+
+  // Post a slow task to disable the high resolution timers.
+  loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
+                       kSlowTimer);
+  loop.Run();
+  EXPECT_FALSE(loop.high_resolution_timers_enabled());
+}
+
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+
+namespace {
+
+class QuitDelegate : public MessageLoopForIO::Watcher {
+ public:
+  virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {
+    MessageLoop::current()->Quit();
+  }
+  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
+    MessageLoop::current()->Quit();
+  }
+};
+
+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 (HANDLE_EINTR(close(pipefds[0])) < 0)
+    PLOG(ERROR) << "close";
+  if (HANDLE_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 (HANDLE_EINTR(close(pipefds[0])) < 0)
+    PLOG(ERROR) << "close";
+  if (HANDLE_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 base::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 base::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) {
+  }
+  virtual void WillDestroyCurrentMessageLoop() OVERRIDE {
+    task_destroyed_before_message_loop_ = *task_destroyed_;
+    *destruction_observer_called_ = true;
+  }
+  bool task_destroyed_before_message_loop() const {
+    return task_destroyed_before_message_loop_;
+  }
+ private:
+  bool* task_destroyed_;
+  bool* destruction_observer_called_;
+  bool task_destroyed_before_message_loop_;
+};
+
+}  // namespace
+
+TEST(MessageLoopTest, DestructionObserverTest) {
+  // Verify that the destruction observer gets called at the very end (after
+  // all the pending tasks have been destroyed).
+  MessageLoop* loop = new MessageLoop;
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  bool task_destroyed = false;
+  bool destruction_observer_called = false;
+
+  MLDestructionObserver observer(&task_destroyed, &destruction_observer_called);
+  loop->AddDestructionObserver(&observer);
+  loop->PostDelayedTask(
+      FROM_HERE,
+      base::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");
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::Bind(
+      &Foo::Test1ConstRef, foo.get(), a));
+
+  // Post quit task;
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
+
+  // Now kick things off
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(foo->test_count(), 1);
+  EXPECT_EQ(foo->result(), "a");
+}
+
+TEST(MessageLoopTest, IsType) {
+  MessageLoop loop(MessageLoop::TYPE_UI);
+  EXPECT_TRUE(loop.IsType(MessageLoop::TYPE_UI));
+  EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_IO));
+  EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_DEFAULT));
+}
diff --git a/base/message_pump.cc b/base/message_pump.cc
new file mode 100644
index 0000000..de7c517
--- /dev/null
+++ b/base/message_pump.cc
@@ -0,0 +1,15 @@
+// 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_pump.h"
+
+namespace base {
+
+MessagePump::MessagePump() {
+}
+
+MessagePump::~MessagePump() {
+}
+
+}  // namespace base
diff --git a/base/message_pump.h b/base/message_pump.h
new file mode 100644
index 0000000..b2e0a42
--- /dev/null
+++ b/base/message_pump.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_MESSAGE_PUMP_H_
+#define BASE_MESSAGE_PUMP_H_
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+class TimeTicks;
+
+class BASE_EXPORT MessagePump : public RefCountedThreadSafe<MessagePump> {
+ 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.
+    virtual bool DoIdleWork() = 0;
+  };
+
+  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;
+
+ protected:
+  virtual ~MessagePump();
+  friend class RefCountedThreadSafe<MessagePump>;
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_H_
diff --git a/base/message_pump_android.cc b/base/message_pump_android.cc
new file mode 100644
index 0000000..f02da67
--- /dev/null
+++ b/base/message_pump_android.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_pump_android.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/time.h"
+#include "jni/SystemMessageHandler_jni.h"
+
+using base::android::ScopedJavaLocalRef;
+
+namespace {
+
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >
+    g_system_message_handler_obj = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// ----------------------------------------------------------------------------
+// Native JNI methods called by Java.
+// ----------------------------------------------------------------------------
+// This method can not move to anonymous namespace as it has been declared as
+// 'static' in system_message_handler_jni.h.
+static jboolean DoRunLoopOnce(JNIEnv* env, jobject obj, jint native_delegate) {
+  base::MessagePump::Delegate* delegate =
+      reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
+  DCHECK(delegate);
+  // This is based on MessagePumpForUI::DoRunLoop() from desktop.
+  // Note however that our system queue is handled in the java side.
+  // In desktop we inspect and process a single system message and then
+  // we call DoWork() / DoDelayedWork().
+  // On Android, the java message queue may contain messages for other handlers
+  // that will be processed before calling here again.
+  bool more_work_is_plausible = delegate->DoWork();
+
+  // This is the time when we need to do delayed work.
+  base::TimeTicks delayed_work_time;
+  more_work_is_plausible |= delegate->DoDelayedWork(&delayed_work_time);
+
+  // This is a major difference between android and other platforms: since we
+  // can't inspect it and process just one single message, instead we'll yeld
+  // the callstack, and post a message to call us back soon.
+  if (more_work_is_plausible)
+    return true;
+
+  more_work_is_plausible = delegate->DoIdleWork();
+  if (!more_work_is_plausible && !delayed_work_time.is_null()) {
+    // We only set the timer here as returning true would post a message.
+    jlong millis =
+        (delayed_work_time - base::TimeTicks::Now()).InMillisecondsRoundedUp();
+    Java_SystemMessageHandler_setDelayedTimer(env, obj, millis);
+  }
+  return more_work_is_plausible;
+}
+
+namespace base {
+
+MessagePumpForUI::MessagePumpForUI()
+    : run_loop_(NULL) {
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+}
+
+void MessagePumpForUI::Run(Delegate* delegate) {
+  NOTREACHED() << "UnitTests should rely on MessagePumpForUIStub in"
+      " test_stub_android.h";
+}
+
+void MessagePumpForUI::Start(Delegate* delegate) {
+  run_loop_ = new base::RunLoop();
+  // Since the RunLoop was just created above, BeforeRun should be guaranteed to
+  // return true (it only returns false if the RunLoop has been Quit already).
+  if (!run_loop_->BeforeRun())
+    NOTREACHED();
+
+  DCHECK(g_system_message_handler_obj.Get().is_null());
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  g_system_message_handler_obj.Get().Reset(
+      Java_SystemMessageHandler_create(env, reinterpret_cast<jint>(delegate)));
+}
+
+void MessagePumpForUI::Quit() {
+  if (!g_system_message_handler_obj.Get().is_null()) {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    DCHECK(env);
+
+    Java_SystemMessageHandler_removeTimer(env,
+        g_system_message_handler_obj.Get().obj());
+    g_system_message_handler_obj.Get().Reset();
+  }
+
+  if (run_loop_) {
+    run_loop_->AfterRun();
+    delete run_loop_;
+    run_loop_ = NULL;
+  }
+}
+
+void MessagePumpForUI::ScheduleWork() {
+  DCHECK(!g_system_message_handler_obj.Get().is_null());
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  Java_SystemMessageHandler_setTimer(env,
+      g_system_message_handler_obj.Get().obj());
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  DCHECK(!g_system_message_handler_obj.Get().is_null());
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  jlong millis =
+      (delayed_work_time - base::TimeTicks::Now()).InMillisecondsRoundedUp();
+  // Note that we're truncating to milliseconds as required by the java side,
+  // even though delayed_work_time is microseconds resolution.
+  Java_SystemMessageHandler_setDelayedTimer(env,
+      g_system_message_handler_obj.Get().obj(), millis);
+}
+
+// static
+bool MessagePumpForUI::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/message_pump_android.h b/base/message_pump_android.h
new file mode 100644
index 0000000..5ef4bd6
--- /dev/null
+++ b/base/message_pump_android.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_PUMP_ANDROID_H_
+#define BASE_MESSAGE_PUMP_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/message_pump.h"
+
+namespace base {
+
+class RunLoop;
+class TimeTicks;
+
+// This class implements a MessagePump needed for TYPE_UI MessageLoops on
+// OS_ANDROID platform.
+class BASE_EXPORT MessagePumpForUI : public MessagePump {
+ public:
+  MessagePumpForUI();
+
+  virtual void Run(Delegate* delegate) OVERRIDE;
+  virtual void Quit() OVERRIDE;
+  virtual void ScheduleWork() OVERRIDE;
+  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+  virtual void Start(Delegate* delegate);
+
+  static bool RegisterBindings(JNIEnv* env);
+
+ protected:
+  virtual ~MessagePumpForUI();
+
+ private:
+  base::RunLoop* run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_ANDROID_H_
diff --git a/base/message_pump_aurax11.cc b/base/message_pump_aurax11.cc
new file mode 100644
index 0000000..f0eb726
--- /dev/null
+++ b/base/message_pump_aurax11.cc
@@ -0,0 +1,317 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_pump_aurax11.h"
+
+#include <glib.h>
+#include <X11/X.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/XKBlib.h>
+
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+
+namespace {
+
+gboolean XSourcePrepare(GSource* source, gint* timeout_ms) {
+  if (XPending(base::MessagePumpAuraX11::GetDefaultXDisplay()))
+    *timeout_ms = 0;
+  else
+    *timeout_ms = -1;
+  return FALSE;
+}
+
+gboolean XSourceCheck(GSource* source) {
+  return XPending(base::MessagePumpAuraX11::GetDefaultXDisplay());
+}
+
+gboolean XSourceDispatch(GSource* source,
+                         GSourceFunc unused_func,
+                         gpointer data) {
+  base::MessagePumpAuraX11* pump = static_cast<base::MessagePumpAuraX11*>(data);
+  return pump->DispatchXEvents();
+}
+
+GSourceFuncs XSourceFuncs = {
+  XSourcePrepare,
+  XSourceCheck,
+  XSourceDispatch,
+  NULL
+};
+
+// The connection is essentially a global that's accessed through a static
+// method and destroyed whenever ~MessagePumpAuraX11() is called. We do this
+// for historical reasons so user code can call
+// MessagePumpForUI::GetDefaultXDisplay() where MessagePumpForUI is a typedef
+// to whatever type in the current build.
+//
+// TODO(erg): This can be changed to something more sane like
+// MessagePumpAuraX11::Current()->display() once MessagePumpGtk goes away.
+Display* g_xdisplay = NULL;
+int g_xinput_opcode = -1;
+
+bool InitializeXInput2Internal() {
+  Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
+  if (!display)
+    return false;
+
+  int event, err;
+
+  int xiopcode;
+  if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
+    DVLOG(1) << "X Input extension not available.";
+    return false;
+  }
+  g_xinput_opcode = xiopcode;
+
+#if defined(USE_XI2_MT)
+  // USE_XI2_MT also defines the required XI2 minor minimum version.
+  int major = 2, minor = USE_XI2_MT;
+#else
+  int major = 2, minor = 0;
+#endif
+  if (XIQueryVersion(display, &major, &minor) == BadRequest) {
+    DVLOG(1) << "XInput2 not supported in the server.";
+    return false;
+  }
+#if defined(USE_XI2_MT)
+  if (major < 2 || (major == 2 && minor < USE_XI2_MT)) {
+    DVLOG(1) << "XI version on server is " << major << "." << minor << ". "
+            << "But 2." << USE_XI2_MT << " is required.";
+    return false;
+  }
+#endif
+
+  return true;
+}
+
+Window FindEventTarget(const base::NativeEvent& xev) {
+  Window target = xev->xany.window;
+  if (xev->type == GenericEvent &&
+      static_cast<XIEvent*>(xev->xcookie.data)->extension == g_xinput_opcode) {
+    target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event;
+  }
+  return target;
+}
+
+bool InitializeXInput2() {
+  static bool xinput2_supported = InitializeXInput2Internal();
+  return xinput2_supported;
+}
+
+bool InitializeXkb() {
+  Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
+  if (!display)
+    return false;
+
+  int opcode, event, error;
+  int major = XkbMajorVersion;
+  int minor = XkbMinorVersion;
+  if (!XkbQueryExtension(display, &opcode, &event, &error, &major, &minor)) {
+    DVLOG(1) << "Xkb extension not available.";
+    return false;
+  }
+
+  // Ask the server not to send KeyRelease event when the user holds down a key.
+  // crbug.com/138092
+  Bool supported_return;
+  if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) {
+    DVLOG(1) << "XKB not supported in the server.";
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+
+MessagePumpAuraX11::MessagePumpAuraX11() : MessagePumpGlib(),
+    x_source_(NULL) {
+  InitializeXInput2();
+  InitializeXkb();
+  InitXSource();
+
+  // Can't put this in the initializer list because g_xdisplay may not exist
+  // until after InitXSource().
+  x_root_window_ = DefaultRootWindow(g_xdisplay);
+}
+
+// static
+Display* MessagePumpAuraX11::GetDefaultXDisplay() {
+  if (!g_xdisplay)
+    g_xdisplay = XOpenDisplay(NULL);
+  return g_xdisplay;
+}
+
+// static
+bool MessagePumpAuraX11::HasXInput2() {
+  return InitializeXInput2();
+}
+
+// static
+MessagePumpAuraX11* MessagePumpAuraX11::Current() {
+  MessageLoopForUI* loop = MessageLoopForUI::current();
+  return static_cast<MessagePumpAuraX11*>(loop->pump_ui());
+}
+
+void MessagePumpAuraX11::AddDispatcherForWindow(
+    MessagePumpDispatcher* dispatcher,
+    unsigned long xid) {
+  dispatchers_.insert(std::make_pair(xid, dispatcher));
+}
+
+void MessagePumpAuraX11::RemoveDispatcherForWindow(unsigned long xid) {
+  dispatchers_.erase(xid);
+}
+
+void MessagePumpAuraX11::AddDispatcherForRootWindow(
+    MessagePumpDispatcher* dispatcher) {
+  DCHECK(std::find(root_window_dispatchers_.begin(),
+                   root_window_dispatchers_.end(),
+                   dispatcher) ==
+         root_window_dispatchers_.end());
+  root_window_dispatchers_.push_back(dispatcher);
+}
+
+void MessagePumpAuraX11::RemoveDispatcherForRootWindow(
+    MessagePumpDispatcher* dispatcher) {
+  root_window_dispatchers_.erase(
+      std::remove(root_window_dispatchers_.begin(),
+                  root_window_dispatchers_.end(),
+                  dispatcher));
+}
+
+bool MessagePumpAuraX11::DispatchXEvents() {
+  Display* display = GetDefaultXDisplay();
+  DCHECK(display);
+  MessagePumpDispatcher* dispatcher =
+      GetDispatcher() ? GetDispatcher() : this;
+
+  // In the general case, we want to handle all pending events before running
+  // the tasks. This is what happens in the message_pump_glib case.
+  while (XPending(display)) {
+    XEvent xev;
+    XNextEvent(display, &xev);
+    if (dispatcher && ProcessXEvent(dispatcher, &xev))
+      return TRUE;
+  }
+  return TRUE;
+}
+
+void MessagePumpAuraX11::BlockUntilWindowMapped(unsigned long xid) {
+  XEvent event;
+
+  Display* display = GetDefaultXDisplay();
+  DCHECK(display);
+
+  MessagePumpDispatcher* dispatcher =
+      GetDispatcher() ? GetDispatcher() : this;
+
+  do {
+    // Block until there's a message of |event_mask| type on |w|. Then remove
+    // it from the queue and stuff it in |event|.
+    XWindowEvent(display, xid, StructureNotifyMask, &event);
+    ProcessXEvent(dispatcher, &event);
+  } while (event.type != MapNotify);
+}
+
+MessagePumpAuraX11::~MessagePumpAuraX11() {
+  g_source_destroy(x_source_);
+  g_source_unref(x_source_);
+  XCloseDisplay(g_xdisplay);
+  g_xdisplay = NULL;
+}
+
+void MessagePumpAuraX11::InitXSource() {
+  // CHECKs are to help track down crbug.com/113106.
+  CHECK(!x_source_);
+  Display* display = GetDefaultXDisplay();
+  CHECK(display) << "Unable to get connection to X server";
+  x_poll_.reset(new GPollFD());
+  CHECK(x_poll_.get());
+  x_poll_->fd = ConnectionNumber(display);
+  x_poll_->events = G_IO_IN;
+
+  x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource));
+  g_source_add_poll(x_source_, x_poll_.get());
+  g_source_set_can_recurse(x_source_, TRUE);
+  g_source_set_callback(x_source_, NULL, this, NULL);
+  g_source_attach(x_source_, g_main_context_default());
+}
+
+bool MessagePumpAuraX11::ProcessXEvent(MessagePumpDispatcher* dispatcher,
+                                       XEvent* xev) {
+  bool should_quit = false;
+
+  bool have_cookie = false;
+  if (xev->type == GenericEvent &&
+      XGetEventData(xev->xgeneric.display, &xev->xcookie)) {
+    have_cookie = true;
+  }
+
+  if (!WillProcessXEvent(xev)) {
+    if (!dispatcher->Dispatch(xev)) {
+      should_quit = true;
+      Quit();
+    }
+    DidProcessXEvent(xev);
+  }
+
+  if (have_cookie) {
+    XFreeEventData(xev->xgeneric.display, &xev->xcookie);
+  }
+
+  return should_quit;
+}
+
+bool MessagePumpAuraX11::WillProcessXEvent(XEvent* xevent) {
+  if (!observers().might_have_observers())
+    return false;
+  ObserverListBase<MessagePumpObserver>::Iterator it(observers());
+  MessagePumpObserver* obs;
+  while ((obs = it.GetNext()) != NULL) {
+    if (obs->WillProcessEvent(xevent))
+      return true;
+  }
+  return false;
+}
+
+void MessagePumpAuraX11::DidProcessXEvent(XEvent* xevent) {
+  FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(xevent));
+}
+
+MessagePumpDispatcher* MessagePumpAuraX11::GetDispatcherForXEvent(
+    const base::NativeEvent& xev) const {
+  ::Window x_window = FindEventTarget(xev);
+  DispatchersMap::const_iterator it = dispatchers_.find(x_window);
+  return it != dispatchers_.end() ? it->second : NULL;
+}
+
+bool MessagePumpAuraX11::Dispatch(const base::NativeEvent& xev) {
+  // MappingNotify events (meaning that the keyboard or pointer buttons have
+  // been remapped) aren't associated with a window; send them to all
+  // dispatchers.
+  if (xev->type == MappingNotify) {
+    for (DispatchersMap::const_iterator it = dispatchers_.begin();
+         it != dispatchers_.end(); ++it) {
+      it->second->Dispatch(xev);
+    }
+    return true;
+  }
+
+  if (FindEventTarget(xev) == x_root_window_) {
+    for (Dispatchers::const_iterator it = root_window_dispatchers_.begin();
+         it != root_window_dispatchers_.end();
+         ++it) {
+      (*it)->Dispatch(xev);
+    }
+    return true;
+  }
+  MessagePumpDispatcher* dispatcher = GetDispatcherForXEvent(xev);
+  return dispatcher ? dispatcher->Dispatch(xev) : true;
+}
+
+}  // namespace base
diff --git a/base/message_pump_aurax11.h b/base/message_pump_aurax11.h
new file mode 100644
index 0000000..3dbf1a1
--- /dev/null
+++ b/base/message_pump_aurax11.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_PUMP_AURAX11_H
+#define BASE_MESSAGE_PUMP_AURAX11_H
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_pump.h"
+#include "base/message_pump_glib.h"
+#include "base/message_pump_dispatcher.h"
+#include "base/message_pump_observer.h"
+
+#include <bitset>
+#include <map>
+#include <vector>
+
+// It would be nice to include the X11 headers here so that we use Window
+// instead of its typedef of unsigned long, but we can't because everything in
+// chrome includes us through base/message_loop.h, and X11's crappy #define
+// heavy headers muck up half of chrome.
+
+typedef struct _GPollFD GPollFD;
+typedef struct _GSource GSource;
+typedef struct _XDisplay Display;
+
+namespace base {
+
+// This class implements a message-pump for dispatching X events.
+//
+// If there's a current dispatcher given through RunWithDispatcher(), that
+// dispatcher receives events. Otherwise, we route to messages to dispatchers
+// who have subscribed to messages from a specific X11 window.
+class BASE_EXPORT MessagePumpAuraX11 : public MessagePumpGlib,
+                                       public MessagePumpDispatcher {
+ public:
+  MessagePumpAuraX11();
+
+  // Returns default X Display.
+  static Display* GetDefaultXDisplay();
+
+  // Returns true if the system supports XINPUT2.
+  static bool HasXInput2();
+
+  // Returns the UI message pump.
+  static MessagePumpAuraX11* Current();
+
+  // Adds/Removes |dispatcher| for the |xid|. This will route all messages from
+  // the window |xid| to |dispatcher.
+  void AddDispatcherForWindow(MessagePumpDispatcher* dispatcher,
+                              unsigned long xid);
+  void RemoveDispatcherForWindow(unsigned long xid);
+
+  // Adds/Removes |dispatcher| to receive all events sent to the X root
+  // window. A root window can have multiple dispatchers, and events on root
+  // windows will be dispatched to all.
+  void AddDispatcherForRootWindow(MessagePumpDispatcher* dispatcher);
+  void RemoveDispatcherForRootWindow(MessagePumpDispatcher* dispatcher);
+
+  // Internal function. Called by the glib source dispatch function. Processes
+  // all available X events.
+  bool DispatchXEvents();
+
+  // Blocks on the X11 event queue until we receive notification from the
+  // xserver that |w| has been mapped; StructureNotifyMask events on |w| are
+  // pulled out from the queue and dispatched out of order.
+  //
+  // For those that know X11, this is really a wrapper around XWindowEvent
+  // which still makes sure the preempted event is dispatched instead of
+  // dropped on the floor. This method exists because mapping a window is
+  // asynchronous (and we receive an XEvent when mapped), while there are also
+  // functions which require a mapped window.
+  void BlockUntilWindowMapped(unsigned long xid);
+
+ protected:
+  virtual ~MessagePumpAuraX11();
+
+ private:
+  typedef std::map<unsigned long, MessagePumpDispatcher*> DispatchersMap;
+  typedef std::vector<MessagePumpDispatcher*> Dispatchers;
+
+  // Initializes the glib event source for X.
+  void InitXSource();
+
+  // Dispatches the XEvent and returns true if we should exit the current loop
+  // of message processing.
+  bool ProcessXEvent(MessagePumpDispatcher* dispatcher, XEvent* event);
+
+  // Sends the event to the observers. If an observer returns true, then it does
+  // not send the event to any other observers and returns true. Returns false
+  // if no observer returns true.
+  bool WillProcessXEvent(XEvent* xevent);
+  void DidProcessXEvent(XEvent* xevent);
+
+  // Returns the Dispatcher based on the event's target window.
+  MessagePumpDispatcher* GetDispatcherForXEvent(
+      const base::NativeEvent& xev) const;
+
+  // Overridden from MessagePumpDispatcher:
+  virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+
+  // The event source for X events.
+  GSource* x_source_;
+
+  // The poll attached to |x_source_|.
+  scoped_ptr<GPollFD> x_poll_;
+
+  DispatchersMap dispatchers_;
+  Dispatchers root_window_dispatchers_;
+
+  unsigned long x_root_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpAuraX11);
+};
+
+typedef MessagePumpAuraX11 MessagePumpForUI;
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_AURAX11_H
diff --git a/base/message_pump_default.cc b/base/message_pump_default.cc
new file mode 100644
index 0000000..9a98064
--- /dev/null
+++ b/base/message_pump_default.cc
@@ -0,0 +1,83 @@
+// 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_pump_default.h"
+
+#include "base/logging.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace base {
+
+MessagePumpDefault::MessagePumpDefault()
+    : keep_running_(true),
+      event_(false, false) {
+}
+
+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;
+
+    if (delayed_work_time_.is_null()) {
+      event_.Wait();
+    } else {
+      TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
+      if (delay > TimeDelta()) {
+        event_.TimedWait(delay);
+      } else {
+        // It looks like delayed_work_time_ indicates a time in the past, so we
+        // need to call DoDelayedWork now.
+        delayed_work_time_ = TimeTicks();
+      }
+    }
+    // Since event_ is auto-reset, we don't need to do anything special here
+    // other than service each delegate method.
+  }
+
+  keep_running_ = true;
+}
+
+void MessagePumpDefault::Quit() {
+  keep_running_ = false;
+}
+
+void MessagePumpDefault::ScheduleWork() {
+  // Since this can be called on any thread, we need to ensure that our Run
+  // loop wakes up.
+  event_.Signal();
+}
+
+void MessagePumpDefault::ScheduleDelayedWork(
+    const TimeTicks& delayed_work_time) {
+  // We know that we can't be blocked on Wait right now since this method can
+  // only be called on the same thread as Run, so we only need to update our
+  // record of how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+}  // namespace base
diff --git a/base/message_pump_default.h b/base/message_pump_default.h
new file mode 100644
index 0000000..6deec99
--- /dev/null
+++ b/base/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_PUMP_DEFAULT_H_
+#define BASE_MESSAGE_PUMP_DEFAULT_H_
+
+#include "base/message_pump.h"
+#include "base/time.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+class MessagePumpDefault : public MessagePump {
+ public:
+  MessagePumpDefault();
+
+  // MessagePump methods:
+  virtual void Run(Delegate* delegate) OVERRIDE;
+  virtual void Quit() OVERRIDE;
+  virtual void ScheduleWork() OVERRIDE;
+  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+ protected:
+  virtual ~MessagePumpDefault() {}
+
+ 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_PUMP_DEFAULT_H_
diff --git a/base/message_pump_dispatcher.h b/base/message_pump_dispatcher.h
new file mode 100644
index 0000000..c3ccf3c
--- /dev/null
+++ b/base/message_pump_dispatcher.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_PUMP_DISPATCHER_H
+#define BASE_MESSAGE_PUMP_DISPATCHER_H
+
+#include "base/base_export.h"
+#include "base/event_types.h"
+
+namespace base {
+
+// Dispatcher is used during a nested invocation of Run to dispatch events when
+// |RunLoop(dispatcher).Run()| is used.  If |RunLoop().Run()| is invoked,
+// MessageLoop does not dispatch events (or invoke TranslateMessage), rather
+// every message is passed to Dispatcher's Dispatch method for dispatch. It is
+// up to the Dispatcher whether or not to dispatch the event.
+//
+// The nested loop is exited by either posting a quit, or returning false
+// from Dispatch.
+class BASE_EXPORT MessagePumpDispatcher {
+ public:
+  virtual ~MessagePumpDispatcher() {}
+
+  // Dispatches the event. If true is returned processing continues as
+  // normal. If false is returned, the nested loop exits immediately.
+  virtual bool Dispatch(const NativeEvent& event) = 0;
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_DISPATCHER_H
diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc
new file mode 100644
index 0000000..99d1eee
--- /dev/null
+++ b/base/message_pump_glib.cc
@@ -0,0 +1,330 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_pump_glib.h"
+
+#include <fcntl.h>
+#include <math.h>
+
+#include <glib.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+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 base::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 - base::TimeTicks::Now()).InMillisecondsF()));
+
+  // If this value is negative, then we need to run delayed work soon.
+  return delay < 0 ? 0 : delay;
+}
+
+// A brief refresher on GLib:
+//     GLib sources have four callbacks: Prepare, Check, Dispatch and Finalize.
+// On each iteration of the GLib pump, it calls each source's Prepare function.
+// This function should return TRUE if it wants GLib to call its Dispatch, and
+// FALSE otherwise.  It can also set a timeout in this case for the next time
+// Prepare should be called again (it may be called sooner).
+//     After the Prepare calls, GLib does a poll to check for events from the
+// system.  File descriptors can be attached to the sources.  The poll may block
+// if none of the Prepare calls returned TRUE.  It will block indefinitely, or
+// by the minimum time returned by a source in Prepare.
+//     After the poll, GLib calls Check for each source that returned FALSE
+// from Prepare.  The return value of Check has the same meaning as for Prepare,
+// making Check a second chance to tell GLib we are ready for Dispatch.
+//     Finally, GLib calls Dispatch for each source that is ready.  If Dispatch
+// returns FALSE, GLib will destroy the source.  Dispatch calls may be recursive
+// (i.e., you can call Run from them), but Prepare and Check cannot.
+//     Finalize is called when the source is destroyed.
+// NOTE: It is common for subsytems to want to process pending events while
+// doing intensive work, for example the flash plugin. They usually use the
+// following pattern (recommended by the GTK docs):
+// while (gtk_events_pending()) {
+//   gtk_main_iteration();
+// }
+//
+// gtk_events_pending just calls g_main_context_pending, which does the
+// following:
+// - Call prepare on all the sources.
+// - Do the poll with a timeout of 0 (not blocking).
+// - Call check on all the sources.
+// - *Does not* call dispatch on the sources.
+// - Return true if any of prepare() or check() returned true.
+//
+// gtk_main_iteration just calls g_main_context_iteration, which does the whole
+// thing, respecting the timeout for the poll (and block, although it is
+// expected not to if gtk_events_pending returned true), and call dispatch.
+//
+// Thus it is important to only return true from prepare or check if we
+// actually have events or work to do. We also need to make sure we keep
+// internal state consistent so that if prepare/check return true when called
+// from gtk_events_pending, they will still return true when called right
+// after, from gtk_main_iteration.
+//
+// For the GLib pump we try to follow the Windows UI pump model:
+// - Whenever we receive a wakeup event or the timer for delayed work expires,
+// we run DoWork and/or DoDelayedWork. That part will also run in the other
+// event pumps.
+// - We also run DoWork, DoDelayedWork, and possibly DoIdleWork in the main
+// loop, around event handling.
+
+struct WorkSource : public GSource {
+  base::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
+};
+
+}  // namespace
+
+
+namespace base {
+
+struct MessagePumpGlib::RunState {
+  Delegate* delegate;
+  MessagePumpDispatcher* dispatcher;
+
+  // Used to flag that the current Run() invocation should return ASAP.
+  bool should_quit;
+
+  // Used to count how many Run() invocations are on the stack.
+  int run_depth;
+
+  // 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_);
+}
+
+void MessagePumpGlib::RunWithDispatcher(Delegate* delegate,
+                                        MessagePumpDispatcher* dispatcher) {
+#ifndef NDEBUG
+  // Make sure we only run this on one thread. X/GTK only has one message pump
+  // so we can only have one UI loop per process.
+  static base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
+  DCHECK(thread_id == base::PlatformThread::CurrentId()) <<
+      "Running MessagePumpGlib on two different threads; "
+      "this is unsupported by GLib!";
+#endif
+
+  RunState state;
+  state.delegate = delegate;
+  state.dispatcher = dispatcher;
+  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;
+}
+
+// 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 should only ever have a single message on the wakeup pipe, since we
+  // are only signaled when the queue went from empty to non-empty.  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;
+    if (HANDLE_EINTR(read(wakeup_pipe_read_, &msg, 1)) != 1 || msg != '!') {
+      NOTREACHED() << "Error reading from the wakeup pipe.";
+    }
+    // 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::AddObserver(MessagePumpObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void MessagePumpGlib::RemoveObserver(MessagePumpObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void MessagePumpGlib::Run(Delegate* delegate) {
+  RunWithDispatcher(delegate, NULL);
+}
+
+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();
+}
+
+MessagePumpGlib::~MessagePumpGlib() {
+  g_source_destroy(work_source_);
+  g_source_unref(work_source_);
+  close(wakeup_pipe_read_);
+  close(wakeup_pipe_write_);
+}
+
+MessagePumpDispatcher* MessagePumpGlib::GetDispatcher() {
+  return state_ ? state_->dispatcher : NULL;
+}
+
+}  // namespace base
diff --git a/base/message_pump_glib.h b/base/message_pump_glib.h
new file mode 100644
index 0000000..48afb55
--- /dev/null
+++ b/base/message_pump_glib.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_MESSAGE_PUMP_GLIB_H_
+#define BASE_MESSAGE_PUMP_GLIB_H_
+
+#include "base/base_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_pump.h"
+#include "base/observer_list.h"
+#include "base/time.h"
+
+typedef struct _GMainContext GMainContext;
+typedef struct _GPollFD GPollFD;
+typedef struct _GSource GSource;
+
+namespace base {
+
+// MessagePumpObserver is notified prior to an event being dispatched. As
+// Observers are notified of every change, they have to be FAST! The platform
+// specific implementation of the class is in message_pump_gtk/message_pump_x.
+class MessagePumpObserver;
+
+// MessagePumpDispatcher is used during a nested invocation of Run to dispatch
+// events. If Run is invoked with a non-NULL MessagePumpDispatcher, MessageLoop
+// does not dispatch events (or invoke gtk_main_do_event), rather every event is
+// passed to Dispatcher's Dispatch method for dispatch. It is up to the
+// Dispatcher to dispatch, or not, the event. The platform specific
+// implementation of the class is in message_pump_gtk/message_pump_x.
+class MessagePumpDispatcher;
+
+// This class implements a base MessagePump needed for TYPE_UI MessageLoops on
+// platforms using GLib.
+class BASE_EXPORT MessagePumpGlib : public MessagePump {
+ public:
+  MessagePumpGlib();
+
+  // Like MessagePump::Run, but events are routed through dispatcher.
+  virtual void RunWithDispatcher(Delegate* delegate,
+                                 MessagePumpDispatcher* dispatcher);
+
+  // 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();
+
+  // Adds an Observer, which will start receiving notifications immediately.
+  void AddObserver(MessagePumpObserver* observer);
+
+  // Removes an Observer.  It is safe to call this method while an Observer is
+  // receiving a notification callback.
+  void RemoveObserver(MessagePumpObserver* observer);
+
+  // Overridden from MessagePump:
+  virtual void Run(Delegate* delegate) OVERRIDE;
+  virtual void Quit() OVERRIDE;
+  virtual void ScheduleWork() OVERRIDE;
+  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+ protected:
+  virtual ~MessagePumpGlib();
+
+  // Returns the dispatcher for the current run state (|state_->dispatcher|).
+  MessagePumpDispatcher* GetDispatcher();
+
+  ObserverList<MessagePumpObserver>& observers() { return observers_; }
+
+ private:
+  // We may make recursive calls to Run, so we save state that needs to be
+  // separate between them in this structure type.
+  struct RunState;
+
+  RunState* state_;
+
+  // This is a GLib structure that we can add event sources to.  We use the
+  // default GLib context, which is the one to which all GTK events are
+  // dispatched.
+  GMainContext* context_;
+
+  // This is the time when we need to do delayed work.
+  TimeTicks delayed_work_time_;
+
+  // The work source.  It is shared by all calls to Run and destroyed when
+  // the message pump is destroyed.
+  GSource* work_source_;
+
+  // We use a wakeup pipe to make sure we'll get out of the glib polling phase
+  // when another thread has scheduled us to do some work.  There is a glib
+  // mechanism g_main_context_wakeup, but this won't guarantee that our event's
+  // Dispatch() will be called.
+  int wakeup_pipe_read_;
+  int wakeup_pipe_write_;
+  // Use a scoped_ptr to avoid needing the definition of GPollFD in the header.
+  scoped_ptr<GPollFD> wakeup_gpollfd_;
+
+  // List of observers.
+  ObserverList<MessagePumpObserver> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpGlib);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_GLIB_H_
diff --git a/base/message_pump_glib_unittest.cc b/base/message_pump_glib_unittest.cc
new file mode 100644
index 0000000..e23cc1e
--- /dev/null
+++ b/base/message_pump_glib_unittest.cc
@@ -0,0 +1,577 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_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.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+#endif
+
+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;
+    base::TimeDelta delta = events_[0].time - base::Time::NowFromSystemTime();
+    return std::max(0, static_cast<int>(ceil(delta.InMillisecondsF())));
+  }
+
+  bool HandleCheck() {
+    if (events_.empty())
+      return false;
+    return events_[0].time <= base::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 base::Closure& callback) {
+    AddEventHelper(delay_ms, callback, base::Closure());
+  }
+
+  void AddDummyEvent(int delay_ms) {
+    AddEventHelper(delay_ms, base::Closure(), base::Closure());
+  }
+
+  void AddEventAsTask(int delay_ms, const base::Closure& task) {
+    AddEventHelper(delay_ms, base::Closure(), task);
+  }
+
+  void Reset() {
+    processed_events_ = 0;
+    events_.clear();
+  }
+
+  int processed_events() const { return processed_events_; }
+
+ private:
+  struct Event {
+    base::Time time;
+    base::Closure callback;
+    base::Closure task;
+  };
+
+  struct Source : public GSource {
+    EventInjector* injector;
+  };
+
+  void AddEventHelper(
+      int delay_ms, const base::Closure& callback, const base::Closure& task) {
+    base::Time last_time;
+    if (!events_.empty())
+      last_time = (events_.end()-1)->time;
+    else
+      last_time = base::Time::NowFromSystemTime();
+
+    base::Time future = last_time + base::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 base::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:
+  virtual void SetUp() OVERRIDE {
+    loop_ = new MessageLoop(MessageLoop::TYPE_UI);
+    injector_ = new EventInjector();
+  }
+  virtual 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
+  loop()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+  loop()->Run();
+  EXPECT_EQ(0, injector()->processed_events());
+
+  injector()->Reset();
+  // Quit from an event
+  injector()->AddEvent(0, MessageLoop::QuitClosure());
+  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, base::Bind(&base::DoNothing));
+  base::Closure check_task =
+      base::Bind(&ExpectProcessedEvents, base::Unretained(injector()), 2);
+  base::Closure posted_task =
+      base::Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+  injector()->AddEventAsTask(0, posted_task);
+  injector()->AddEventAsTask(0, base::Bind(&base::DoNothing));
+  injector()->AddEvent(0, MessageLoop::QuitClosure());
+  loop()->Run();
+  EXPECT_EQ(4, injector()->processed_events());
+
+  injector()->Reset();
+  injector()->AddEventAsTask(0, base::Bind(&base::DoNothing));
+  check_task =
+      base::Bind(&ExpectProcessedEvents, base::Unretained(injector()), 2);
+  posted_task = base::Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+  injector()->AddEventAsTask(0, posted_task);
+  injector()->AddEventAsTask(10, base::Bind(&base::DoNothing));
+  injector()->AddEvent(0, MessageLoop::QuitClosure());
+  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, base::Bind(&IncrementInt, &task_count));
+  }
+  // After all the previous tasks have executed, enqueue an event that will
+  // quit.
+  loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&EventInjector::AddEvent, base::Unretained(injector()), 0,
+                 MessageLoop::QuitClosure()));
+  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,
+        base::Bind(&IncrementInt, &task_count),
+        base::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,
+      base::Bind(&EventInjector::AddEvent, base::Unretained(injector()), 10,
+                 MessageLoop::QuitClosure()),
+      base::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).
+  base::Closure check_task =
+      base::Bind(&ExpectProcessedEvents, base::Unretained(injector()), 11);
+  base::Closure posted_task =
+      base::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::QuitClosure());
+  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 base::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()->Quit();
+    } else {
+      MessageLoop::current()->PostTask(
+          FROM_HERE, base::Bind(&ConcurrentHelper::FromTask, this));
+    }
+  }
+
+  void FromEvent() {
+    if (event_count_ > 0) {
+      --event_count_;
+    }
+    if (task_count_ == 0 && event_count_ == 0) {
+        MessageLoop::current()->Quit();
+    } else {
+      injector_->AddEventAsTask(
+          0, base::Bind(&ConcurrentHelper::FromEvent, this));
+    }
+  }
+
+  int event_count() const { return event_count_; }
+  int task_count() const { return task_count_; }
+
+ private:
+  friend class base::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::Quit() 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, base::Bind(&ConcurrentHelper::FromEvent, helper.get()));
+  injector()->AddEventAsTask(
+      0, base::Bind(&ConcurrentHelper::FromEvent, helper.get()));
+
+  // Similarly post 2 tasks.
+  loop()->PostTask(
+      FROM_HERE, base::Bind(&ConcurrentHelper::FromTask, helper.get()));
+  loop()->PostTask(
+      FROM_HERE, base::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::QuitClosure());
+
+  // Post a couple of dummy tasks
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&base::DoNothing));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&base::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,
+      base::Bind(&AddEventsAndDrainGLib, base::Unretained(injector())));
+  loop()->Run();
+
+  EXPECT_EQ(3, injector()->processed_events());
+}
+
+
+namespace {
+
+#if defined(TOOLKIT_GTK)
+void AddEventsAndDrainGtk(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::QuitClosure());
+
+  // Post a couple of dummy tasks
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&base::DoNothing));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&base::DoNothing));
+
+  // Drain the events
+  while (gtk_events_pending()) {
+    gtk_main_iteration();
+  }
+}
+#endif
+
+}  // namespace
+
+#if defined(TOOLKIT_GTK)
+TEST_F(MessagePumpGLibTest, TestDrainingGtk) {
+  // Tests that draining events using Gtk works.
+  loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&AddEventsAndDrainGtk, base::Unretained(injector())));
+  loop()->Run();
+
+  EXPECT_EQ(3, injector()->processed_events());
+}
+#endif
+
+namespace {
+
+// Helper class that lets us run the GLib message loop.
+class GLibLoopRunner : public base::RefCounted<GLibLoopRunner> {
+ public:
+  GLibLoopRunner() : quit_(false) { }
+
+  void RunGLib() {
+    while (!quit_) {
+      g_main_context_iteration(NULL, TRUE);
+    }
+  }
+
+  void RunLoop() {
+#if defined(TOOLKIT_GTK)
+    while (!quit_) {
+      gtk_main_iteration();
+    }
+#else
+    while (!quit_) {
+      g_main_context_iteration(NULL, TRUE);
+    }
+#endif
+  }
+
+  void Quit() {
+    quit_ = true;
+  }
+
+  void Reset() {
+    quit_ = false;
+  }
+
+ private:
+  friend class base::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, base::Bind(&IncrementInt, &task_count));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&IncrementInt, &task_count));
+  // Delayed events
+  injector->AddDummyEvent(10);
+  injector->AddDummyEvent(10);
+  // Delayed work
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&IncrementInt, &task_count),
+      base::TimeDelta::FromMilliseconds(30));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&GLibLoopRunner::Quit, runner.get()),
+      base::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()->Quit();
+}
+
+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, base::Bind(&IncrementInt, &task_count));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&IncrementInt, &task_count));
+  // Delayed events
+  injector->AddDummyEvent(10);
+  injector->AddDummyEvent(10);
+  // Delayed work
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&IncrementInt, &task_count),
+      base::TimeDelta::FromMilliseconds(30));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&GLibLoopRunner::Quit, runner.get()),
+      base::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()->Quit();
+}
+
+}  // 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,
+      base::Bind(&TestGLibLoopInternal, base::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,
+      base::Bind(&TestGtkLoopInternal, base::Unretained(injector())));
+  loop()->Run();
+}
diff --git a/base/message_pump_gtk.cc b/base/message_pump_gtk.cc
new file mode 100644
index 0000000..780b4d8
--- /dev/null
+++ b/base/message_pump_gtk.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/message_pump_gtk.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include "base/profiler/scoped_profile.h"
+#include "base/debug/trace_event.h"
+
+namespace {
+
+const char* EventToTypeString(const GdkEvent* event) {
+  switch (event->type) {
+    case GDK_NOTHING:           return "GDK_NOTHING";
+    case GDK_DELETE:            return "GDK_DELETE";
+    case GDK_DESTROY:           return "GDK_DESTROY";
+    case GDK_EXPOSE:            return "GDK_EXPOSE";
+    case GDK_MOTION_NOTIFY:     return "GDK_MOTION_NOTIFY";
+    case GDK_BUTTON_PRESS:      return "GDK_BUTTON_PRESS";
+    case GDK_2BUTTON_PRESS:     return "GDK_2BUTTON_PRESS";
+    case GDK_3BUTTON_PRESS:     return "GDK_3BUTTON_PRESS";
+    case GDK_BUTTON_RELEASE:    return "GDK_BUTTON_RELEASE";
+    case GDK_KEY_PRESS:         return "GDK_KEY_PRESS";
+    case GDK_KEY_RELEASE:       return "GDK_KEY_RELEASE";
+    case GDK_ENTER_NOTIFY:      return "GDK_ENTER_NOTIFY";
+    case GDK_LEAVE_NOTIFY:      return "GDK_LEAVE_NOTIFY";
+    case GDK_FOCUS_CHANGE:      return "GDK_FOCUS_CHANGE";
+    case GDK_CONFIGURE:         return "GDK_CONFIGURE";
+    case GDK_MAP:               return "GDK_MAP";
+    case GDK_UNMAP:             return "GDK_UNMAP";
+    case GDK_PROPERTY_NOTIFY:   return "GDK_PROPERTY_NOTIFY";
+    case GDK_SELECTION_CLEAR:   return "GDK_SELECTION_CLEAR";
+    case GDK_SELECTION_REQUEST: return "GDK_SELECTION_REQUEST";
+    case GDK_SELECTION_NOTIFY:  return "GDK_SELECTION_NOTIFY";
+    case GDK_PROXIMITY_IN:      return "GDK_PROXIMITY_IN";
+    case GDK_PROXIMITY_OUT:     return "GDK_PROXIMITY_OUT";
+    case GDK_DRAG_ENTER:        return "GDK_DRAG_ENTER";
+    case GDK_DRAG_LEAVE:        return "GDK_DRAG_LEAVE";
+    case GDK_DRAG_MOTION:       return "GDK_DRAG_MOTION";
+    case GDK_DRAG_STATUS:       return "GDK_DRAG_STATUS";
+    case GDK_DROP_START:        return "GDK_DROP_START";
+    case GDK_DROP_FINISHED:     return "GDK_DROP_FINISHED";
+    case GDK_CLIENT_EVENT:      return "GDK_CLIENT_EVENT";
+    case GDK_VISIBILITY_NOTIFY: return "GDK_VISIBILITY_NOTIFY";
+    case GDK_NO_EXPOSE:         return "GDK_NO_EXPOSE";
+    case GDK_SCROLL:            return "GDK_SCROLL";
+    case GDK_WINDOW_STATE:      return "GDK_WINDOW_STATE";
+    case GDK_SETTING:           return "GDK_SETTING";
+    case GDK_OWNER_CHANGE:      return "GDK_OWNER_CHANGE";
+    case GDK_GRAB_BROKEN:       return "GDK_GRAB_BROKEN";
+    case GDK_DAMAGE:            return "GDK_DAMAGE";
+    default:
+      return "Unknown Gdk Event";
+  }
+}
+
+}
+
+namespace base {
+
+MessagePumpGtk::MessagePumpGtk() : MessagePumpGlib() {
+  gdk_event_handler_set(&EventDispatcher, this, NULL);
+}
+
+void MessagePumpGtk::DispatchEvents(GdkEvent* event) {
+  UNSHIPPED_TRACE_EVENT1("task", "MessagePumpGtk::DispatchEvents",
+                         "type", EventToTypeString(event));
+
+  WillProcessEvent(event);
+
+  MessagePumpDispatcher* dispatcher = GetDispatcher();
+  if (!dispatcher)
+    gtk_main_do_event(event);
+  else if (!dispatcher->Dispatch(event))
+    Quit();
+
+  DidProcessEvent(event);
+}
+
+// static
+Display* MessagePumpGtk::GetDefaultXDisplay() {
+  static GdkDisplay* display = gdk_display_get_default();
+  if (!display) {
+    // GTK / GDK has not been initialized, which is a decision we wish to
+    // support, for example for the GPU process.
+    static Display* xdisplay = XOpenDisplay(NULL);
+    return xdisplay;
+  }
+  return GDK_DISPLAY_XDISPLAY(display);
+}
+
+MessagePumpGtk::~MessagePumpGtk() {
+  gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event),
+                        this, NULL);
+}
+
+void MessagePumpGtk::WillProcessEvent(GdkEvent* event) {
+  FOR_EACH_OBSERVER(MessagePumpObserver, observers(), WillProcessEvent(event));
+}
+
+void MessagePumpGtk::DidProcessEvent(GdkEvent* event) {
+  FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(event));
+}
+
+// static
+void MessagePumpGtk::EventDispatcher(GdkEvent* event, gpointer data) {
+  MessagePumpGtk* message_pump = reinterpret_cast<MessagePumpGtk*>(data);
+  message_pump->DispatchEvents(event);
+}
+
+}  // namespace base
diff --git a/base/message_pump_gtk.h b/base/message_pump_gtk.h
new file mode 100644
index 0000000..ba5cff1
--- /dev/null
+++ b/base/message_pump_gtk.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_MESSAGE_PUMP_GTK_H_
+#define BASE_MESSAGE_PUMP_GTK_H_
+
+#include "base/message_pump_glib.h"
+
+typedef union _GdkEvent GdkEvent;
+typedef struct _XDisplay Display;
+
+namespace base {
+
+// The documentation for this class is in message_pump_glib.h
+class MessagePumpObserver {
+ public:
+  // This method is called before processing a message.
+  virtual void WillProcessEvent(GdkEvent* event) = 0;
+
+  // This method is called after processing a message.
+  virtual void DidProcessEvent(GdkEvent* event) = 0;
+
+ protected:
+  virtual ~MessagePumpObserver() {}
+};
+
+// The documentation for this class is in message_pump_glib.h
+//
+// The nested loop is exited by either posting a quit, or returning false
+// from Dispatch.
+class MessagePumpDispatcher {
+ public:
+  // Dispatches the event. If true is returned processing continues as
+  // normal. If false is returned, the nested loop exits immediately.
+  virtual bool Dispatch(GdkEvent* event) = 0;
+
+ protected:
+  virtual ~MessagePumpDispatcher() {}
+};
+
+// This class implements a message-pump for dispatching GTK events.
+class BASE_EXPORT MessagePumpGtk : public MessagePumpGlib {
+ public:
+  MessagePumpGtk();
+
+  // Dispatch an available GdkEvent. Essentially this allows a subclass to do
+  // some task before/after calling the default handler (EventDispatcher).
+  void DispatchEvents(GdkEvent* event);
+
+  // Returns default X Display.
+  static Display* GetDefaultXDisplay();
+
+ protected:
+  virtual ~MessagePumpGtk();
+
+ private:
+  // Invoked from EventDispatcher. Notifies all observers we're about to
+  // process an event.
+  void WillProcessEvent(GdkEvent* event);
+
+  // Invoked from EventDispatcher. Notifies all observers we processed an
+  // event.
+  void DidProcessEvent(GdkEvent* event);
+
+  // Callback prior to gdk dispatching an event.
+  static void EventDispatcher(GdkEvent* event, void* data);
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpGtk);
+};
+
+typedef MessagePumpGtk MessagePumpForUI;
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_GTK_H_
diff --git a/base/message_pump_libevent.cc b/base/message_pump_libevent.cc
new file mode 100644
index 0000000..b948cc0
--- /dev/null
+++ b/base/message_pump_libevent.cc
@@ -0,0 +1,383 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_pump_libevent.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/auto_reset.h"
+#include "base/compiler_specific.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/time.h"
+#if defined(USE_SYSTEM_LIBEVENT)
+#include <event.h>
+#else
+#include "third_party/libevent/event.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+// Lifecycle of struct event
+// Libevent uses two main data structures:
+// struct event_base (of which there is one per message pump), and
+// struct event (of which there is roughly one per socket).
+// The socket's struct event is created in
+// MessagePumpLibevent::WatchFileDescriptor(),
+// is owned by the FileDescriptorWatcher, and is destroyed in
+// StopWatchingFileDescriptor().
+// It is moved into and out of lists in struct event_base by
+// the libevent functions event_add() and event_del().
+//
+// TODO(dkegel):
+// At the moment bad things happen if a FileDescriptorWatcher
+// is active after its MessagePumpLibevent has been destroyed.
+// See MessageLoopTest.FileDescriptorWatcherOutlivesMessageLoop
+// Not clear yet whether that situation occurs in practice,
+// but if it does, we need to fix it.
+
+namespace base {
+
+// Return 0 on success
+// Too small a function to bother putting in a library?
+static int SetNonBlocking(int fd) {
+  int flags = fcntl(fd, F_GETFL, 0);
+  if (flags == -1)
+    flags = 0;
+  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
+    : event_(NULL),
+      pump_(NULL),
+      watcher_(NULL),
+      ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
+}
+
+MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
+  if (event_) {
+    StopWatchingFileDescriptor();
+  }
+}
+
+bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
+  event* e = ReleaseEvent();
+  if (e == NULL)
+    return true;
+
+  // event_del() is a no-op if the event isn't active.
+  int rv = event_del(e);
+  delete e;
+  pump_ = NULL;
+  watcher_ = NULL;
+  return (rv == 0);
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e) {
+  DCHECK(e);
+  DCHECK(!event_);
+
+  event_ = e;
+}
+
+event *MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() {
+  struct event *e = event_;
+  event_ = NULL;
+  return e;
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking(
+    int fd, MessagePumpLibevent* pump) {
+  // Since OnFileCanWriteWithoutBlocking() gets called first, it can stop
+  // watching the file descriptor.
+  if (!watcher_)
+    return;
+  pump->WillProcessIOEvent();
+  watcher_->OnFileCanReadWithoutBlocking(fd);
+  pump->DidProcessIOEvent();
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
+    int fd, MessagePumpLibevent* pump) {
+  DCHECK(watcher_);
+  pump->WillProcessIOEvent();
+  watcher_->OnFileCanWriteWithoutBlocking(fd);
+  pump->DidProcessIOEvent();
+}
+
+MessagePumpLibevent::MessagePumpLibevent()
+    : keep_running_(true),
+      in_run_(false),
+      processed_io_events_(false),
+      event_base_(event_base_new()),
+      wakeup_pipe_in_(-1),
+      wakeup_pipe_out_(-1) {
+  if (!Init())
+     NOTREACHED();
+}
+
+MessagePumpLibevent::~MessagePumpLibevent() {
+  DCHECK(wakeup_event_);
+  DCHECK(event_base_);
+  event_del(wakeup_event_);
+  delete wakeup_event_;
+  if (wakeup_pipe_in_ >= 0) {
+    if (HANDLE_EINTR(close(wakeup_pipe_in_)) < 0)
+      DPLOG(ERROR) << "close";
+  }
+  if (wakeup_pipe_out_ >= 0) {
+    if (HANDLE_EINTR(close(wakeup_pipe_out_)) < 0)
+      DPLOG(ERROR) << "close";
+  }
+  event_base_free(event_base_);
+}
+
+bool MessagePumpLibevent::WatchFileDescriptor(int fd,
+                                              bool persistent,
+                                              Mode 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) != 0) {
+    event_mask |= EV_READ;
+  }
+  if ((mode & WATCH_WRITE) != 0) {
+    event_mask |= EV_WRITE;
+  }
+
+  scoped_ptr<event> evt(controller->ReleaseEvent());
+  if (evt.get() == NULL) {
+    // Ownership is transferred to the controller.
+    evt.reset(new event);
+  } else {
+    // Make sure we don't pick up any funky internal libevent masks.
+    int old_interest_mask = evt.get()->ev_events &
+        (EV_READ | EV_WRITE | EV_PERSIST);
+
+    // Combine old/new event masks.
+    event_mask |= old_interest_mask;
+
+    // Must disarm the event before we can reuse it.
+    event_del(evt.get());
+
+    // It's illegal to use this function to listen on 2 separate fds with the
+    // same |controller|.
+    if (EVENT_FD(evt.get()) != fd) {
+      NOTREACHED() << "FDs don't match" << EVENT_FD(evt.get()) << "!=" << fd;
+      return false;
+    }
+  }
+
+  // Set current interest mask and message pump for this event.
+  event_set(evt.get(), fd, event_mask, OnLibeventNotification, controller);
+
+  // Tell libevent which message pump this socket will belong to when we add it.
+  if (event_base_set(event_base_, evt.get()) != 0) {
+    return false;
+  }
+
+  // Add this socket to the list of monitored sockets.
+  if (event_add(evt.get(), NULL) != 0) {
+    return false;
+  }
+
+  // Transfer ownership of evt to controller.
+  controller->Init(evt.release());
+
+  controller->set_watcher(delegate);
+  controller->set_pump(this);
+
+  return true;
+}
+
+void MessagePumpLibevent::AddIOObserver(IOObserver *obs) {
+  io_observers_.AddObserver(obs);
+}
+
+void MessagePumpLibevent::RemoveIOObserver(IOObserver *obs) {
+  io_observers_.RemoveObserver(obs);
+}
+
+// Tell libevent to break out of inner loop.
+static void timer_callback(int fd, short events, void *context)
+{
+  event_base_loopbreak((struct event_base *)context);
+}
+
+// Reentrant!
+void MessagePumpLibevent::Run(Delegate* delegate) {
+  DCHECK(keep_running_) << "Quit must have been called outside of Run!";
+  AutoReset<bool> auto_reset_in_run(&in_run_, true);
+
+  // event_base_loopexit() + EVLOOP_ONCE is leaky, see http://crbug.com/25641.
+  // Instead, make our own timer and reuse it on each call to event_base_loop().
+  scoped_ptr<event> timer_event(new event);
+
+  for (;;) {
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+    bool did_work = delegate->DoWork();
+    if (!keep_running_)
+      break;
+
+    event_base_loop(event_base_, EVLOOP_NONBLOCK);
+    did_work |= processed_io_events_;
+    processed_io_events_ = false;
+    if (!keep_running_)
+      break;
+
+    did_work |= delegate->DoDelayedWork(&delayed_work_time_);
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    did_work = delegate->DoIdleWork();
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    // EVLOOP_ONCE tells libevent to only block once,
+    // but to service all pending events when it wakes up.
+    if (delayed_work_time_.is_null()) {
+      event_base_loop(event_base_, EVLOOP_ONCE);
+    } else {
+      TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
+      if (delay > TimeDelta()) {
+        struct timeval poll_tv;
+        poll_tv.tv_sec = delay.InSeconds();
+        poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
+        event_set(timer_event.get(), -1, 0, timer_callback, event_base_);
+        event_base_set(event_base_, timer_event.get());
+        event_add(timer_event.get(), &poll_tv);
+        event_base_loop(event_base_, EVLOOP_ONCE);
+        event_del(timer_event.get());
+      } else {
+        // It looks like delayed_work_time_ indicates a time in the past, so we
+        // need to call DoDelayedWork now.
+        delayed_work_time_ = TimeTicks();
+      }
+    }
+  }
+
+  keep_running_ = true;
+}
+
+void MessagePumpLibevent::Quit() {
+  DCHECK(in_run_);
+  // Tell both libevent and Run that they should break out of their loops.
+  keep_running_ = false;
+  ScheduleWork();
+}
+
+void MessagePumpLibevent::ScheduleWork() {
+  // Tell libevent (in a threadsafe way) that it should break out of its loop.
+  char buf = 0;
+  int nwrite = HANDLE_EINTR(write(wakeup_pipe_in_, &buf, 1));
+  DCHECK(nwrite == 1 || errno == EAGAIN)
+      << "[nwrite:" << nwrite << "] [errno:" << errno << "]";
+}
+
+void MessagePumpLibevent::ScheduleDelayedWork(
+    const TimeTicks& delayed_work_time) {
+  // We know that we can't be blocked on Wait right now since this method can
+  // only be called on the same thread as Run, so we only need to update our
+  // record of how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+void MessagePumpLibevent::WillProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpLibevent::DidProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+bool MessagePumpLibevent::Init() {
+  int fds[2];
+  if (pipe(fds)) {
+    DLOG(ERROR) << "pipe() failed, errno: " << errno;
+    return false;
+  }
+  if (SetNonBlocking(fds[0])) {
+    DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
+    return false;
+  }
+  if (SetNonBlocking(fds[1])) {
+    DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
+    return false;
+  }
+  wakeup_pipe_out_ = fds[0];
+  wakeup_pipe_in_ = fds[1];
+
+  wakeup_event_ = new event;
+  event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
+            OnWakeup, this);
+  event_base_set(event_base_, wakeup_event_);
+
+  if (event_add(wakeup_event_, 0))
+    return false;
+  return true;
+}
+
+// static
+void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
+                                                 void* context) {
+  base::WeakPtr<FileDescriptorWatcher> controller =
+      static_cast<FileDescriptorWatcher*>(context)->weak_factory_.GetWeakPtr();
+  DCHECK(controller.get());
+
+  MessagePumpLibevent* pump = controller->pump();
+  pump->processed_io_events_ = true;
+
+  if (flags & EV_WRITE) {
+    controller->OnFileCanWriteWithoutBlocking(fd, pump);
+  }
+  // Check |controller| in case it's been deleted in
+  // controller->OnFileCanWriteWithoutBlocking().
+  if (controller.get() && flags & EV_READ) {
+    controller->OnFileCanReadWithoutBlocking(fd, pump);
+  }
+}
+
+// Called if a byte is received on the wakeup pipe.
+// static
+void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
+  base::MessagePumpLibevent* that =
+              static_cast<base::MessagePumpLibevent*>(context);
+  DCHECK(that->wakeup_pipe_out_ == socket);
+
+  // Remove and discard the wakeup byte.
+  char buf;
+  int nread = HANDLE_EINTR(read(socket, &buf, 1));
+  DCHECK_EQ(nread, 1);
+  that->processed_io_events_ = true;
+  // Tell libevent to break out of inner loop.
+  event_base_loopbreak(that->event_base_);
+}
+
+}  // namespace base
diff --git a/base/message_pump_libevent.h b/base/message_pump_libevent.h
new file mode 100644
index 0000000..7c689b9
--- /dev/null
+++ b/base/message_pump_libevent.h
@@ -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.
+
+#ifndef BASE_MESSAGE_PUMP_LIBEVENT_H_
+#define BASE_MESSAGE_PUMP_LIBEVENT_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_pump.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
+#include "base/time.h"
+
+// Declare structs we need from libevent.h rather than including it
+struct event_base;
+struct event;
+
+namespace base {
+
+// Class to monitor sockets and issue callbacks when sockets are ready for I/O
+// TODO(dkegel): add support for background file IO somehow
+class BASE_EXPORT MessagePumpLibevent : public MessagePump {
+ public:
+  class IOObserver {
+   public:
+    IOObserver() {}
+
+    // An IOObserver is an object that receives IO notifications from the
+    // MessagePump.
+    //
+    // NOTE: An IOObserver implementation should be extremely fast!
+    virtual void WillProcessIOEvent() = 0;
+    virtual void DidProcessIOEvent() = 0;
+
+   protected:
+    virtual ~IOObserver() {}
+  };
+
+  class FileDescriptorWatcher;
+
+  // 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() { 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_;
+    base::WeakPtrFactory<FileDescriptorWatcher> weak_factory_;
+
+    DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
+  };
+
+  enum Mode {
+    WATCH_READ = 1 << 0,
+    WATCH_WRITE = 1 << 1,
+    WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
+  };
+
+  MessagePumpLibevent();
+
+  // 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,
+                           Mode mode,
+                           FileDescriptorWatcher *controller,
+                           Watcher *delegate);
+
+  void AddIOObserver(IOObserver* obs);
+  void RemoveIOObserver(IOObserver* obs);
+
+  // MessagePump methods:
+  virtual void Run(Delegate* delegate) OVERRIDE;
+  virtual void Quit() OVERRIDE;
+  virtual void ScheduleWork() OVERRIDE;
+  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+ protected:
+  virtual ~MessagePumpLibevent();
+
+ private:
+  friend class MessagePumpLibeventTest;
+
+  void WillProcessIOEvent();
+  void DidProcessIOEvent();
+
+  // Risky part of constructor.  Returns true on success.
+  bool Init();
+
+  // Called by libevent to tell us a registered FD can be read/written to.
+  static void OnLibeventNotification(int fd, short flags,
+                                     void* context);
+
+  // Unix pipe used to implement ScheduleWork()
+  // ... callback; called by libevent inside Run() when pipe is ready to read
+  static void OnWakeup(int socket, short flags, void* context);
+
+  // This flag is set to false when Run should return.
+  bool keep_running_;
+
+  // This flag is set when inside Run.
+  bool in_run_;
+
+  // This flag is set if libevent has processed I/O events.
+  bool processed_io_events_;
+
+  // The time at which we should call DoDelayedWork.
+  TimeTicks delayed_work_time_;
+
+  // Libevent dispatcher.  Watches all sockets registered with it, and sends
+  // readiness callbacks when a socket is ready for I/O.
+  event_base* event_base_;
+
+  // ... write end; ScheduleWork() writes a single byte to it
+  int wakeup_pipe_in_;
+  // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
+  int wakeup_pipe_out_;
+  // ... libevent wrapper for read end
+  event* wakeup_event_;
+
+  ObserverList<IOObserver> io_observers_;
+  ThreadChecker watch_file_descriptor_caller_checker_;
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_LIBEVENT_H_
diff --git a/base/message_pump_libevent_unittest.cc b/base/message_pump_libevent_unittest.cc
new file mode 100644
index 0000000..b94b382
--- /dev/null
+++ b/base/message_pump_libevent_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/message_pump_libevent.h"
+
+#include <unistd.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/message_loop.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(USE_SYSTEM_LIBEVENT)
+#include <event.h>
+#else
+#include "third_party/libevent/event.h"
+#endif
+
+namespace base {
+
+class MessagePumpLibeventTest : public testing::Test {
+ protected:
+  MessagePumpLibeventTest()
+      : ui_loop_(MessageLoop::TYPE_UI),
+        io_thread_("MessagePumpLibeventTestIOThread") {}
+  virtual ~MessagePumpLibeventTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    Thread::Options options(MessageLoop::TYPE_IO, 0);
+    ASSERT_TRUE(io_thread_.StartWithOptions(options));
+    ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
+    int err = pipe(pipefds_);
+    ASSERT_EQ(0, err);
+  }
+
+  virtual void TearDown() OVERRIDE {
+    if (HANDLE_EINTR(close(pipefds_[0])) < 0)
+      PLOG(ERROR) << "close";
+    if (HANDLE_EINTR(close(pipefds_[1])) < 0)
+      PLOG(ERROR) << "close";
+  }
+
+  MessageLoop* ui_loop() { return &ui_loop_; }
+  MessageLoopForIO* io_loop() const {
+    return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
+  }
+
+  void OnLibeventNotification(
+      MessagePumpLibevent* pump,
+      MessagePumpLibevent::FileDescriptorWatcher* controller) {
+    pump->OnLibeventNotification(0, EV_WRITE | EV_READ, controller);
+  }
+
+  MessageLoop ui_loop_;
+  Thread io_thread_;
+  int pipefds_[2];
+};
+
+namespace {
+
+// Concrete implementation of MessagePumpLibevent::Watcher that does
+// nothing useful.
+class StupidWatcher : public MessagePumpLibevent::Watcher {
+ public:
+  virtual ~StupidWatcher() {}
+
+  // base:MessagePumpLibevent::Watcher interface
+  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {}
+  virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
+};
+
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+// Test to make sure that we catch calling WatchFileDescriptor off of the
+// wrong thread.
+TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) {
+  MessagePumpLibevent::FileDescriptorWatcher watcher;
+  StupidWatcher delegate;
+
+  ASSERT_DEATH(io_loop()->WatchFileDescriptor(
+      STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate),
+      "Check failed: "
+      "watch_file_descriptor_caller_checker_.CalledOnValidThread()");
+}
+
+#endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+class BaseWatcher : public MessagePumpLibevent::Watcher {
+ public:
+  BaseWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller)
+      : controller_(controller) {
+    DCHECK(controller_);
+  }
+  virtual ~BaseWatcher() {}
+
+  // base:MessagePumpLibevent::Watcher interface
+  virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE {
+    NOTREACHED();
+  }
+
+  virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
+    NOTREACHED();
+  }
+
+ protected:
+  MessagePumpLibevent::FileDescriptorWatcher* controller_;
+};
+
+class DeleteWatcher : public BaseWatcher {
+ public:
+  explicit DeleteWatcher(
+      MessagePumpLibevent::FileDescriptorWatcher* controller)
+      : BaseWatcher(controller) {}
+
+  virtual ~DeleteWatcher() {
+    DCHECK(!controller_);
+  }
+
+  virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
+    DCHECK(controller_);
+    delete controller_;
+    controller_ = NULL;
+  }
+};
+
+TEST_F(MessagePumpLibeventTest, DeleteWatcher) {
+  scoped_refptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+  MessagePumpLibevent::FileDescriptorWatcher* watcher =
+      new MessagePumpLibevent::FileDescriptorWatcher;
+  DeleteWatcher delegate(watcher);
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpLibevent::WATCH_READ_WRITE, watcher, &delegate);
+
+  // Spoof a libevent notification.
+  OnLibeventNotification(pump, watcher);
+}
+
+class StopWatcher : public BaseWatcher {
+ public:
+  explicit StopWatcher(
+      MessagePumpLibevent::FileDescriptorWatcher* controller)
+      : BaseWatcher(controller) {}
+
+  virtual ~StopWatcher() {}
+
+  virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
+    controller_->StopWatchingFileDescriptor();
+  }
+};
+
+TEST_F(MessagePumpLibeventTest, StopWatcher) {
+  scoped_refptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+  MessagePumpLibevent::FileDescriptorWatcher watcher;
+  StopWatcher delegate(&watcher);
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpLibevent::WATCH_READ_WRITE, &watcher, &delegate);
+
+  // Spoof a libevent notification.
+  OnLibeventNotification(pump, &watcher);
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/message_pump_mac.h b/base/message_pump_mac.h
new file mode 100644
index 0000000..2dd5ecf
--- /dev/null
+++ b/base/message_pump_mac.h
@@ -0,0 +1,337 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The basis for all native run loops on the Mac is the CFRunLoop.  It can be
+// used directly, it can be used as the driving force behind the similar
+// Foundation NSRunLoop, and it can be used to implement higher-level event
+// loops such as the NSApplication event loop.
+//
+// This file introduces a basic CFRunLoop-based implementation of the
+// MessagePump interface called CFRunLoopBase.  CFRunLoopBase contains all
+// of the machinery necessary to dispatch events to a delegate, but does not
+// implement the specific run loop.  Concrete subclasses must provide their
+// own DoRun and Quit implementations.
+//
+// A concrete subclass that just runs a CFRunLoop loop is provided in
+// MessagePumpCFRunLoop.  For an NSRunLoop, the similar MessagePumpNSRunLoop
+// is provided.
+//
+// For the application's event loop, an implementation based on AppKit's
+// NSApplication event system is provided in MessagePumpNSApplication.
+//
+// Typically, MessagePumpNSApplication only makes sense on a Cocoa
+// application's main thread.  If a CFRunLoop-based message pump is needed on
+// any other thread, one of the other concrete subclasses is preferrable.
+// MessagePumpMac::Create is defined, which returns a new NSApplication-based
+// or NSRunLoop-based MessagePump subclass depending on which thread it is
+// called on.
+
+#ifndef BASE_MESSAGE_PUMP_MAC_H_
+#define BASE_MESSAGE_PUMP_MAC_H_
+
+#include "base/message_pump.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#if !defined(__OBJC__)
+class NSAutoreleasePool;
+#else  // !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;
+
+class MessagePumpCFRunLoopBase : public MessagePump {
+  // Needs access to CreateAutoreleasePool.
+  friend class MessagePumpScopedAutoreleasePool;
+ public:
+  MessagePumpCFRunLoopBase();
+
+  // 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.
+  virtual void Run(Delegate* delegate) OVERRIDE;
+  virtual void DoRun(Delegate* delegate) = 0;
+
+  virtual void ScheduleWork() OVERRIDE;
+  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+ protected:
+  virtual ~MessagePumpCFRunLoopBase();
+
+  // 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 NSAutoreleasePool* 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_;
+
+  // 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 MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpCFRunLoop();
+
+  virtual void DoRun(Delegate* delegate) OVERRIDE;
+  virtual void Quit() OVERRIDE;
+
+ protected:
+  virtual ~MessagePumpCFRunLoop();
+
+ private:
+  virtual 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 MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+  BASE_EXPORT MessagePumpNSRunLoop();
+
+  virtual void DoRun(Delegate* delegate) OVERRIDE;
+  virtual void Quit() OVERRIDE;
+
+ protected:
+  virtual ~MessagePumpNSRunLoop();
+
+ 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();
+  virtual void DoRun(Delegate* delegate) OVERRIDE;
+  virtual 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);
+
+ protected:
+  virtual ~MessagePumpUIApplication();
+
+ private:
+  base::RunLoop* run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpUIApplication);
+};
+
+#else
+
+class MessagePumpNSApplication : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpNSApplication();
+
+  virtual void DoRun(Delegate* delegate) OVERRIDE;
+  virtual void Quit() OVERRIDE;
+
+ protected:
+  virtual ~MessagePumpNSApplication();
+
+ 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();
+
+ protected:
+  virtual ~MessagePumpCrApplication() {}
+
+  // Returns nil if NSApp is currently in the middle of calling
+  // -sendEvent.  Requires NSApp implementing CrAppProtocol.
+  virtual NSAutoreleasePool* CreateAutoreleasePool() OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpCrApplication);
+};
+#endif  // !defined(OS_IOS)
+
+class 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.
+  BASE_EXPORT static bool UsingCrApp();
+
+  // Wrapper to query -[NSApp isHandlingSendEvent] from C++ code.
+  // Requires NSApp to implement CrAppProtocol.
+  BASE_EXPORT static bool IsHandlingSendEvent();
+#endif  // !defined(OS_IOS)
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_MAC_H_
diff --git a/base/message_pump_mac.mm b/base/message_pump_mac.mm
new file mode 100644
index 0000000..3878eb8
--- /dev/null
+++ b/base/message_pump_mac.mm
@@ -0,0 +1,699 @@
+// Copyright (c) 2012 The Chromium 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_pump_mac.h"
+
+#import <Foundation/Foundation.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/time.h"
+
+#if !defined(OS_IOS)
+#import <AppKit/AppKit.h>
+#endif  // !defined(OS_IOS)
+
+namespace {
+
+void NoOp(void* info) {
+}
+
+const CFTimeInterval kCFTimeIntervalMax =
+    std::numeric_limits<CFTimeInterval>::max();
+
+// Set to true if MessagePumpMac::Create() is called before NSApp is
+// initialized.  Only accessed from the main thread.
+bool not_using_crapp = false;
+
+}  // namespace
+
+namespace base {
+
+// 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),
+      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);
+  CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
+
+  CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
+  source_context.info = this;
+  source_context.perform = RunWorkSource;
+  work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                       1,     // priority
+                                       &source_context);
+  CFRunLoopAddSource(run_loop_, work_source_, kCFRunLoopCommonModes);
+
+  source_context.perform = RunIdleWorkSource;
+  idle_work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                            2,     // priority
+                                            &source_context);
+  CFRunLoopAddSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
+
+  source_context.perform = RunNestingDeferredWorkSource;
+  nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                                        0,     // priority
+                                                        &source_context);
+  CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_,
+                     kCFRunLoopCommonModes);
+
+  CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
+  observer_context.info = this;
+  pre_wait_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
+                                               kCFRunLoopBeforeWaiting,
+                                               true,  // repeat
+                                               0,     // priority
+                                               PreWaitObserver,
+                                               &observer_context);
+  CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
+
+  pre_source_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
+                                                 kCFRunLoopBeforeSources,
+                                                 true,  // repeat
+                                                 0,     // priority
+                                                 PreSourceObserver,
+                                                 &observer_context);
+  CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes);
+
+  enter_exit_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
+                                                 kCFRunLoopEntry |
+                                                     kCFRunLoopExit,
+                                                 true,  // repeat
+                                                 0,     // priority
+                                                 EnterExitObserver,
+                                                 &observer_context);
+  CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
+}
+
+// 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() {
+  CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_,
+                          kCFRunLoopCommonModes);
+  CFRelease(enter_exit_observer_);
+
+  CFRunLoopRemoveObserver(run_loop_, pre_source_observer_,
+                          kCFRunLoopCommonModes);
+  CFRelease(pre_source_observer_);
+
+  CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_,
+                          kCFRunLoopCommonModes);
+  CFRelease(pre_wait_observer_);
+
+  CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_,
+                        kCFRunLoopCommonModes);
+  CFRelease(nesting_deferred_work_source_);
+
+  CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
+  CFRelease(idle_work_source_);
+
+  CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes);
+  CFRelease(work_source_);
+
+  CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
+  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_);
+}
+
+// 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.
+NSAutoreleasePool* 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);
+  CFRunLoopAddSource(run_loop(), quit_source_, kCFRunLoopCommonModes);
+}
+
+MessagePumpNSRunLoop::~MessagePumpNSRunLoop() {
+  CFRunLoopRemoveSource(run_loop(), quit_source_, kCFRunLoopCommonModes);
+  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 base::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:NSMakePoint(0, 0)
+                                 modifierFlags:0
+                                     timestamp:0
+                                  windowNumber:0
+                                       context:NULL
+                                       subtype:0
+                                         data1:0
+                                         data2:0]
+           atStart:NO];
+}
+
+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.
+NSAutoreleasePool* 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 (not_using_crapp)
+    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];
+    not_using_crapp = true;
+    return new MessagePumpNSApplication;
+#endif
+  }
+
+  return new MessagePumpNSRunLoop;
+}
+
+}  // namespace base
diff --git a/base/message_pump_observer.h b/base/message_pump_observer.h
new file mode 100644
index 0000000..a7d2aa7
--- /dev/null
+++ b/base/message_pump_observer.h
@@ -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.
+
+#ifndef BASE_MESSAGE_PUMP_OBSERVER_H
+#define BASE_MESSAGE_PUMP_OBSERVER_H
+
+#include "base/base_export.h"
+#include "base/event_types.h"
+
+namespace base {
+
+enum EventStatus {
+  EVENT_CONTINUE,    // The event should be dispatched as normal.
+#if defined(USE_X11)
+  EVENT_HANDLED      // The event should not be processed any farther.
+#endif
+};
+
+// A MessagePumpObserver is an object that receives global
+// notifications from the UI MessageLoop with MessagePumpWin or
+// MessagePumpAuraX11.
+//
+// NOTE: An Observer implementation should be extremely fast!
+//
+// For use with MessagePumpAuraX11, please see message_pump_glib.h for more
+// info about how this is invoked in this environment.
+class BASE_EXPORT MessagePumpObserver {
+ public:
+  // This method is called before processing a NativeEvent. If the
+  // method returns EVENT_HANDLED, it indicates the event has already
+  // been handled, so the event is not processed any farther. If the
+  // method returns EVENT_CONTINUE, the event dispatching proceeds as
+  // normal.
+  virtual EventStatus WillProcessEvent(const NativeEvent& event) = 0;
+
+  // This method is called after processing a message. This method
+  // will not be called if WillProcessEvent returns EVENT_HANDLED.
+  virtual void DidProcessEvent(const NativeEvent& event) = 0;
+
+ protected:
+  virtual ~MessagePumpObserver() {}
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_OBSERVER_VIEWS_H
diff --git a/base/message_pump_win.cc b/base/message_pump_win.cc
new file mode 100644
index 0000000..fb962ca
--- /dev/null
+++ b/base/message_pump_win.cc
@@ -0,0 +1,680 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_pump_win.h"
+
+#include <math.h>
+
+#include "base/debug/trace_event.h"
+#include "base/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/process_util.h"
+#include "base/win/wrapped_window_proc.h"
+
+namespace {
+
+enum MessageLoopProblems {
+  MESSAGE_POST_ERROR,
+  COMPLETION_POST_ERROR,
+  SET_TIMER_ERROR,
+  MESSAGE_LOOP_PROBLEM_MAX,
+};
+
+}  // namespace
+
+namespace base {
+
+static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow";
+
+// Message sent to get an additional time slice for pumping (processing) another
+// task (a series of such messages creates a continuous task pump).
+static const int kMsgHaveWork = WM_USER + 1;
+
+//-----------------------------------------------------------------------------
+// MessagePumpWin public:
+
+void MessagePumpWin::AddObserver(MessagePumpObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void MessagePumpWin::RemoveObserver(MessagePumpObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void MessagePumpWin::WillProcessMessage(const MSG& msg) {
+  FOR_EACH_OBSERVER(MessagePumpObserver, observers_, WillProcessEvent(msg));
+}
+
+void MessagePumpWin::DidProcessMessage(const MSG& msg) {
+  FOR_EACH_OBSERVER(MessagePumpObserver, observers_, DidProcessEvent(msg));
+}
+
+void MessagePumpWin::RunWithDispatcher(
+    Delegate* delegate, MessagePumpDispatcher* dispatcher) {
+  RunState s;
+  s.delegate = delegate;
+  s.dispatcher = dispatcher;
+  s.should_quit = false;
+  s.run_depth = state_ ? state_->run_depth + 1 : 1;
+
+  RunState* previous_state = state_;
+  state_ = &s;
+
+  DoRunLoop();
+
+  state_ = previous_state;
+}
+
+void MessagePumpWin::Quit() {
+  DCHECK(state_);
+  state_->should_quit = true;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpWin protected:
+
+int MessagePumpWin::GetCurrentDelay() const {
+  if (delayed_work_time_.is_null())
+    return -1;
+
+  // Be careful here.  TimeDelta has a precision of microseconds, but we want a
+  // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or
+  // 6?  It should be 6 to avoid executing delayed work too early.
+  double timeout =
+      ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF());
+
+  // If this value is negative, then we need to run delayed work soon.
+  int delay = static_cast<int>(timeout);
+  if (delay < 0)
+    delay = 0;
+
+  return delay;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI public:
+
+MessagePumpForUI::MessagePumpForUI()
+    : instance_(NULL),
+      message_filter_(new MessageFilter) {
+  InitMessageWnd();
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+  DestroyWindow(message_hwnd_);
+  UnregisterClass(kWndClass, instance_);
+}
+
+void MessagePumpForUI::ScheduleWork() {
+  if (InterlockedExchange(&have_work_, 1))
+    return;  // Someone else continued the pumping.
+
+  // Make sure the MessagePump does some work for us.
+  BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork,
+                         reinterpret_cast<WPARAM>(this), 0);
+  if (ret)
+    return;  // There was room in the Window Message queue.
+
+  // We have failed to insert a have-work message, so there is a chance that we
+  // will starve tasks/timers while sitting in a nested message loop.  Nested
+  // loops only look at Windows Message queues, and don't look at *our* task
+  // queues, etc., so we might not get a time slice in such. :-(
+  // We could abort here, but the fear is that this failure mode is plausibly
+  // common (queue is full, of about 2000 messages), so we'll do a near-graceful
+  // recovery.  Nested loops are pretty transient (we think), so this will
+  // probably be recoverable.
+  InterlockedExchange(&have_work_, 0);  // Clarify that we didn't really insert.
+  UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
+                            MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  //
+  // We would *like* to provide high resolution timers.  Windows timers using
+  // SetTimer() have a 10ms granularity.  We have to use WM_TIMER as a wakeup
+  // mechanism because the application can enter modal windows loops where it
+  // is not running our MessageLoop; the only way to have our timers fire in
+  // these cases is to post messages there.
+  //
+  // To provide sub-10ms timers, we process timers directly from our run loop.
+  // For the common case, timers will be processed there as the run loop does
+  // its normal work.  However, we *also* set the system timer so that WM_TIMER
+  // events fire.  This mops up the case of timers not being able to work in
+  // modal message loops.  It is possible for the SetTimer to pop and have no
+  // pending timers, because they could have already been processed by the
+  // run loop itself.
+  //
+  // We use a single SetTimer corresponding to the timer that will expire
+  // soonest.  As new timers are created and destroyed, we update SetTimer.
+  // Getting a spurrious SetTimer event firing is benign, as we'll just be
+  // processing an empty timer queue.
+  //
+  delayed_work_time_ = delayed_work_time;
+
+  int delay_msec = GetCurrentDelay();
+  DCHECK_GE(delay_msec, 0);
+  if (delay_msec < USER_TIMER_MINIMUM)
+    delay_msec = USER_TIMER_MINIMUM;
+
+  // Create a WM_TIMER event that will wake us up to check for any pending
+  // timers (in case we are running within a nested, external sub-pump).
+  BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this),
+                      delay_msec, NULL);
+  if (ret)
+    return;
+  // If we can't set timers, we are in big trouble... but cross our fingers for
+  // now.
+  // TODO(jar): If we don't see this error, use a CHECK() here instead.
+  UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
+                            MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+void MessagePumpForUI::PumpOutPendingPaintMessages() {
+  // If we are being called outside of the context of Run, then don't try to do
+  // any work.
+  if (!state_)
+    return;
+
+  // Create a mini-message-pump to force immediate processing of only Windows
+  // WM_PAINT messages.  Don't provide an infinite loop, but do enough peeking
+  // to get the job done.  Actual common max is 4 peeks, but we'll be a little
+  // safe here.
+  const int kMaxPeekCount = 20;
+  int peek_count;
+  for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) {
+    MSG msg;
+    if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT))
+      break;
+    ProcessMessageHelper(msg);
+    if (state_->should_quit)  // Handle WM_QUIT.
+      break;
+  }
+  // Histogram what was really being used, to help to adjust kMaxPeekCount.
+  DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count);
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI private:
+
+// static
+LRESULT CALLBACK MessagePumpForUI::WndProcThunk(
+    HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
+  switch (message) {
+    case kMsgHaveWork:
+      reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage();
+      break;
+    case WM_TIMER:
+      reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage();
+      break;
+  }
+  return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+void MessagePumpForUI::DoRunLoop() {
+  // IF this was just a simple PeekMessage() loop (servicing all possible work
+  // queues), then Windows would try to achieve the following order according
+  // to MSDN documentation about PeekMessage with no filter):
+  //    * Sent messages
+  //    * Posted messages
+  //    * Sent messages (again)
+  //    * WM_PAINT messages
+  //    * WM_TIMER messages
+  //
+  // Summary: none of the above classes is starved, and sent messages has twice
+  // the chance of being processed (i.e., reduced service time).
+
+  for (;;) {
+    // If we do any work, we may create more messages etc., and more work may
+    // possibly be waiting in another task group.  When we (for example)
+    // ProcessNextWindowsMessage(), there is a good chance there are still more
+    // messages waiting.  On the other hand, when any of these methods return
+    // having done no work, then it is pretty unlikely that calling them again
+    // quickly will find any work to do.  Finally, if they all say they had no
+    // work, then it is a good time to consider sleeping (waiting) for more
+    // work.
+
+    bool more_work_is_plausible = ProcessNextWindowsMessage();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |= state_->delegate->DoWork();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |=
+        state_->delegate->DoDelayedWork(&delayed_work_time_);
+    // If we did not process any delayed work, then we can assume that our
+    // existing WM_TIMER if any will fire when delayed work should run.  We
+    // don't want to disturb that timer if it is already in flight.  However,
+    // if we did do all remaining delayed work, then lets kill the WM_TIMER.
+    if (more_work_is_plausible && delayed_work_time_.is_null())
+      KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    more_work_is_plausible = state_->delegate->DoIdleWork();
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    WaitForWork();  // Wait (sleep) until we have work to do again.
+  }
+}
+
+void MessagePumpForUI::InitMessageWnd() {
+  WNDCLASSEX wc = {0};
+  wc.cbSize = sizeof(wc);
+  wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>;
+  wc.hInstance = base::GetModuleFromAddress(wc.lpfnWndProc);
+  wc.lpszClassName = kWndClass;
+  instance_ = wc.hInstance;
+  RegisterClassEx(&wc);
+
+  message_hwnd_ =
+      CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, instance_, 0);
+  DCHECK(message_hwnd_);
+}
+
+void MessagePumpForUI::WaitForWork() {
+  // Wait until a message is available, up to the time needed by the timer
+  // manager to fire the next set of timers.
+  int delay = GetCurrentDelay();
+  if (delay < 0)  // Negative value means no timers waiting.
+    delay = INFINITE;
+
+  DWORD result;
+  result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
+                                       MWMO_INPUTAVAILABLE);
+
+  if (WAIT_OBJECT_0 == result) {
+    // A WM_* message is available.
+    // If a parent child relationship exists between windows across threads
+    // then their thread inputs are implicitly attached.
+    // This causes the MsgWaitForMultipleObjectsEx API to return indicating
+    // that messages are ready for processing (Specifically, mouse messages
+    // intended for the child window may appear if the child window has
+    // capture).
+    // The subsequent PeekMessages call may fail to return any messages thus
+    // causing us to enter a tight loop at times.
+    // The WaitMessage call below is a workaround to give the child window
+    // some time to process its input messages.
+    MSG msg = {0};
+    DWORD queue_status = GetQueueStatus(QS_MOUSE);
+    if (HIWORD(queue_status) & QS_MOUSE &&
+        !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) {
+      WaitMessage();
+    }
+    return;
+  }
+
+  DCHECK_NE(WAIT_FAILED, result) << GetLastError();
+}
+
+void MessagePumpForUI::HandleWorkMessage() {
+  // If we are being called outside of the context of Run, then don't try to do
+  // any work.  This could correspond to a MessageBox call or something of that
+  // sort.
+  if (!state_) {
+    // Since we handled a kMsgHaveWork message, we must still update this flag.
+    InterlockedExchange(&have_work_, 0);
+    return;
+  }
+
+  // Let whatever would have run had we not been putting messages in the queue
+  // run now.  This is an attempt to make our dummy message not starve other
+  // messages that may be in the Windows message queue.
+  ProcessPumpReplacementMessage();
+
+  // Now give the delegate a chance to do some work.  He'll let us know if he
+  // needs to do more work.
+  if (state_->delegate->DoWork())
+    ScheduleWork();
+}
+
+void MessagePumpForUI::HandleTimerMessage() {
+  KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
+
+  // If we are being called outside of the context of Run, then don't do
+  // anything.  This could correspond to a MessageBox call or something of
+  // that sort.
+  if (!state_)
+    return;
+
+  state_->delegate->DoDelayedWork(&delayed_work_time_);
+  if (!delayed_work_time_.is_null()) {
+    // A bit gratuitous to set delayed_work_time_ again, but oh well.
+    ScheduleDelayedWork(delayed_work_time_);
+  }
+}
+
+bool MessagePumpForUI::ProcessNextWindowsMessage() {
+  // If there are sent messages in the queue then PeekMessage internally
+  // dispatches the message and returns false. We return true in this
+  // case to ensure that the message loop peeks again instead of calling
+  // MsgWaitForMultipleObjectsEx again.
+  bool sent_messages_in_queue = false;
+  DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE);
+  if (HIWORD(queue_status) & QS_SENDMESSAGE)
+    sent_messages_in_queue = true;
+
+  MSG msg;
+  if (message_filter_->DoPeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+    return ProcessMessageHelper(msg);
+
+  return sent_messages_in_queue;
+}
+
+bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
+  TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper",
+               "message", msg.message);
+  if (WM_QUIT == msg.message) {
+    // Repost the QUIT message so that it will be retrieved by the primary
+    // GetMessage() loop.
+    state_->should_quit = true;
+    PostQuitMessage(static_cast<int>(msg.wParam));
+    return false;
+  }
+
+  // While running our main message pump, we discard kMsgHaveWork messages.
+  if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_)
+    return ProcessPumpReplacementMessage();
+
+  if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
+    return true;
+
+  WillProcessMessage(msg);
+
+  if (!message_filter_->ProcessMessage(msg)) {
+    if (state_->dispatcher) {
+      if (!state_->dispatcher->Dispatch(msg))
+        state_->should_quit = true;
+    } else {
+      TranslateMessage(&msg);
+      DispatchMessage(&msg);
+    }
+  }
+
+  DidProcessMessage(msg);
+  return true;
+}
+
+bool MessagePumpForUI::ProcessPumpReplacementMessage() {
+  // When we encounter a kMsgHaveWork message, this method is called to peek
+  // and process a replacement message, such as a WM_PAINT or WM_TIMER.  The
+  // goal is to make the kMsgHaveWork as non-intrusive as possible, even though
+  // a continuous stream of such messages are posted.  This method carefully
+  // peeks a message while there is no chance for a kMsgHaveWork to be pending,
+  // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to
+  // possibly be posted), and finally dispatches that peeked replacement.  Note
+  // that the re-post of kMsgHaveWork may be asynchronous to this thread!!
+
+  bool have_message = false;
+  MSG msg;
+  // We should not process all window messages if we are in the context of an
+  // OS modal loop, i.e. in the context of a windows API call like MessageBox.
+  // This is to ensure that these messages are peeked out by the OS modal loop.
+  if (MessageLoop::current()->os_modal_loop()) {
+    // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above.
+    have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
+                   PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
+  } else {
+    have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0,
+                                                    PM_REMOVE);
+  }
+
+  DCHECK(!have_message || kMsgHaveWork != msg.message ||
+         msg.hwnd != message_hwnd_);
+
+  // Since we discarded a kMsgHaveWork message, we must update the flag.
+  int old_have_work = InterlockedExchange(&have_work_, 0);
+  DCHECK(old_have_work);
+
+  // We don't need a special time slice if we didn't have_message to process.
+  if (!have_message)
+    return false;
+
+  // Guarantee we'll get another time slice in the case where we go into native
+  // windows code.   This ScheduleWork() may hurt performance a tiny bit when
+  // tasks appear very infrequently, but when the event queue is busy, the
+  // kMsgHaveWork events get (percentage wise) rarer and rarer.
+  ScheduleWork();
+  return ProcessMessageHelper(msg);
+}
+
+void MessagePumpForUI::SetMessageFilter(
+    scoped_ptr<MessageFilter> message_filter) {
+  message_filter_ = message_filter.Pass();
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO public:
+
+MessagePumpForIO::MessagePumpForIO() {
+  port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1));
+  DCHECK(port_.IsValid());
+}
+
+void MessagePumpForIO::ScheduleWork() {
+  if (InterlockedExchange(&have_work_, 1))
+    return;  // Someone else continued the pumping.
+
+  // Make sure the MessagePump does some work for us.
+  BOOL ret = PostQueuedCompletionStatus(port_, 0,
+                                        reinterpret_cast<ULONG_PTR>(this),
+                                        reinterpret_cast<OVERLAPPED*>(this));
+  if (ret)
+    return;  // Post worked perfectly.
+
+  // See comment in MessagePumpForUI::ScheduleWork() for this error recovery.
+  InterlockedExchange(&have_work_, 0);  // Clarify that we didn't succeed.
+  UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR,
+                            MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  // We know that we can't be blocked right now since this method can only be
+  // called on the same thread as Run, so we only need to update our record of
+  // how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle,
+                                         IOHandler* handler) {
+  ULONG_PTR key = HandlerToKey(handler, true);
+  HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1);
+  DPCHECK(port);
+}
+
+bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle,
+                                         IOHandler* handler) {
+  // Job object notifications use the OVERLAPPED pointer to carry the message
+  // data. Mark the completion key correspondingly, so we will not try to
+  // convert OVERLAPPED* to IOContext*.
+  ULONG_PTR key = HandlerToKey(handler, false);
+  JOBOBJECT_ASSOCIATE_COMPLETION_PORT info;
+  info.CompletionKey = reinterpret_cast<void*>(key);
+  info.CompletionPort = port_;
+  return SetInformationJobObject(job_handle,
+                                 JobObjectAssociateCompletionPortInformation,
+                                 &info,
+                                 sizeof(info)) != FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO private:
+
+void MessagePumpForIO::DoRunLoop() {
+  for (;;) {
+    // If we do any work, we may create more messages etc., and more work may
+    // possibly be waiting in another task group.  When we (for example)
+    // WaitForIOCompletion(), there is a good chance there are still more
+    // messages waiting.  On the other hand, when any of these methods return
+    // having done no work, then it is pretty unlikely that calling them
+    // again quickly will find any work to do.  Finally, if they all say they
+    // had no work, then it is a good time to consider sleeping (waiting) for
+    // more work.
+
+    bool more_work_is_plausible = state_->delegate->DoWork();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |= WaitForIOCompletion(0, NULL);
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |=
+        state_->delegate->DoDelayedWork(&delayed_work_time_);
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    more_work_is_plausible = state_->delegate->DoIdleWork();
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    WaitForWork();  // Wait (sleep) until we have work to do again.
+  }
+}
+
+// Wait until IO completes, up to the time needed by the timer manager to fire
+// the next set of timers.
+void MessagePumpForIO::WaitForWork() {
+  // We do not support nested IO message loops. This is to avoid messy
+  // recursion problems.
+  DCHECK_EQ(1, state_->run_depth) << "Cannot nest an IO message loop!";
+
+  int timeout = GetCurrentDelay();
+  if (timeout < 0)  // Negative value means no timers waiting.
+    timeout = INFINITE;
+
+  WaitForIOCompletion(timeout, NULL);
+}
+
+bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
+  IOItem item;
+  if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) {
+    // We have to ask the system for another IO completion.
+    if (!GetIOItem(timeout, &item))
+      return false;
+
+    if (ProcessInternalIOItem(item))
+      return true;
+  }
+
+  // If |item.has_valid_io_context| is false then |item.context| does not point
+  // to a context structure, and so should not be dereferenced, although it may
+  // still hold valid non-pointer data.
+  if (!item.has_valid_io_context || item.context->handler) {
+    if (filter && item.handler != filter) {
+      // Save this item for later
+      completed_io_.push_back(item);
+    } else {
+      DCHECK(!item.has_valid_io_context ||
+             (item.context->handler == item.handler));
+      WillProcessIOEvent();
+      item.handler->OnIOCompleted(item.context, item.bytes_transfered,
+                                  item.error);
+      DidProcessIOEvent();
+    }
+  } else {
+    // The handler must be gone by now, just cleanup the mess.
+    delete item.context;
+  }
+  return true;
+}
+
+// Asks the OS for another IO completion result.
+bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) {
+  memset(item, 0, sizeof(*item));
+  ULONG_PTR key = NULL;
+  OVERLAPPED* overlapped = NULL;
+  if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key,
+                                 &overlapped, timeout)) {
+    if (!overlapped)
+      return false;  // Nothing in the queue.
+    item->error = GetLastError();
+    item->bytes_transfered = 0;
+  }
+
+  item->handler = KeyToHandler(key, &item->has_valid_io_context);
+  item->context = reinterpret_cast<IOContext*>(overlapped);
+  return true;
+}
+
+bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) {
+  if (this == reinterpret_cast<MessagePumpForIO*>(item.context) &&
+      this == reinterpret_cast<MessagePumpForIO*>(item.handler)) {
+    // This is our internal completion.
+    DCHECK(!item.bytes_transfered);
+    InterlockedExchange(&have_work_, 0);
+    return true;
+  }
+  return false;
+}
+
+// Returns a completion item that was previously received.
+bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) {
+  DCHECK(!completed_io_.empty());
+  for (std::list<IOItem>::iterator it = completed_io_.begin();
+       it != completed_io_.end(); ++it) {
+    if (!filter || it->handler == filter) {
+      *item = *it;
+      completed_io_.erase(it);
+      return true;
+    }
+  }
+  return false;
+}
+
+void MessagePumpForIO::AddIOObserver(IOObserver *obs) {
+  io_observers_.AddObserver(obs);
+}
+
+void MessagePumpForIO::RemoveIOObserver(IOObserver *obs) {
+  io_observers_.RemoveObserver(obs);
+}
+
+void MessagePumpForIO::WillProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpForIO::DidProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+// static
+ULONG_PTR MessagePumpForIO::HandlerToKey(IOHandler* handler,
+                                         bool has_valid_io_context) {
+  ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler);
+
+  // |IOHandler| is at least pointer-size aligned, so the lowest two bits are
+  // always cleared. We use the lowest bit to distinguish completion keys with
+  // and without the associated |IOContext|.
+  DCHECK((key & 1) == 0);
+
+  // Mark the completion key as context-less.
+  if (!has_valid_io_context)
+    key = key | 1;
+  return key;
+}
+
+// static
+MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler(
+    ULONG_PTR key,
+    bool* has_valid_io_context) {
+  *has_valid_io_context = ((key & 1) == 0);
+  return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1));
+}
+
+}  // namespace base
diff --git a/base/message_pump_win.h b/base/message_pump_win.h
new file mode 100644
index 0000000..5ea195f
--- /dev/null
+++ b/base/message_pump_win.h
@@ -0,0 +1,396 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_PUMP_WIN_H_
+#define BASE_MESSAGE_PUMP_WIN_H_
+
+#include <windows.h>
+
+#include <list>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_pump.h"
+#include "base/message_pump_dispatcher.h"
+#include "base/message_pump_observer.h"
+#include "base/observer_list.h"
+#include "base/time.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+// MessagePumpWin serves as the base for specialized versions of the MessagePump
+// for Windows. It provides basic functionality like handling of observers and
+// controlling the lifetime of the message pump.
+class BASE_EXPORT MessagePumpWin : public MessagePump {
+ public:
+  MessagePumpWin() : have_work_(0), state_(NULL) {}
+  virtual ~MessagePumpWin() {}
+
+  // Add an Observer, which will start receiving notifications immediately.
+  void AddObserver(MessagePumpObserver* observer);
+
+  // Remove an Observer.  It is safe to call this method while an Observer is
+  // receiving a notification callback.
+  void RemoveObserver(MessagePumpObserver* observer);
+
+  // Give a chance to code processing additional messages to notify the
+  // message loop observers that another message has been processed.
+  void WillProcessMessage(const MSG& msg);
+  void DidProcessMessage(const MSG& msg);
+
+  // Like MessagePump::Run, but MSG objects are routed through dispatcher.
+  void RunWithDispatcher(Delegate* delegate, MessagePumpDispatcher* dispatcher);
+
+  // MessagePump methods:
+  virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); }
+  virtual void Quit();
+
+ protected:
+  struct RunState {
+    Delegate* delegate;
+    MessagePumpDispatcher* dispatcher;
+
+    // Used to flag that the current Run() invocation should return ASAP.
+    bool should_quit;
+
+    // Used to count how many Run() invocations are on the stack.
+    int run_depth;
+  };
+
+  virtual void DoRunLoop() = 0;
+  int GetCurrentDelay() const;
+
+  ObserverList<MessagePumpObserver> observers_;
+
+  // The time at which delayed work should run.
+  TimeTicks delayed_work_time_;
+
+  // A boolean value used to indicate if there is a kMsgDoWork message pending
+  // in the Windows Message queue.  There is at most one such message, and it
+  // can drive execution of tasks when a native message pump is running.
+  LONG have_work_;
+
+  // State for the current invocation of Run.
+  RunState* state_;
+};
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI extends MessagePumpWin with methods that are particular to a
+// MessageLoop instantiated with TYPE_UI.
+//
+// MessagePumpForUI implements a "traditional" Windows message pump. It contains
+// a nearly infinite loop that peeks out messages, and then dispatches them.
+// Intermixed with those peeks are callouts to DoWork for pending tasks, and
+// DoDelayedWork for pending timers. When there are no events to be serviced,
+// this pump goes into a wait state. In most cases, this message pump handles
+// all processing.
+//
+// However, when a task, or windows event, invokes on the stack a native dialog
+// box or such, that window typically provides a bare bones (native?) message
+// pump.  That bare-bones message pump generally supports little more than a
+// peek of the Windows message queue, followed by a dispatch of the peeked
+// message.  MessageLoop extends that bare-bones message pump to also service
+// Tasks, at the cost of some complexity.
+//
+// The basic structure of the extension (refered to as a sub-pump) is that a
+// special message, kMsgHaveWork, is repeatedly injected into the Windows
+// Message queue.  Each time the kMsgHaveWork message is peeked, checks are
+// made for an extended set of events, including the availability of Tasks to
+// run.
+//
+// After running a task, the special message kMsgHaveWork is again posted to
+// the Windows Message queue, ensuring a future time slice for processing a
+// future event.  To prevent flooding the Windows Message queue, care is taken
+// to be sure that at most one kMsgHaveWork message is EVER pending in the
+// Window's Message queue.
+//
+// There are a few additional complexities in this system where, when there are
+// no Tasks to run, this otherwise infinite stream of messages which drives the
+// sub-pump is halted.  The pump is automatically re-started when Tasks are
+// queued.
+//
+// A second complexity is that the presence of this stream of posted tasks may
+// prevent a bare-bones message pump from ever peeking a WM_PAINT or WM_TIMER.
+// Such paint and timer events always give priority to a posted message, such as
+// kMsgHaveWork messages.  As a result, care is taken to do some peeking in
+// between the posting of each kMsgHaveWork message (i.e., after kMsgHaveWork
+// is peeked, and before a replacement kMsgHaveWork is posted).
+//
+// NOTE: Although it may seem odd that messages are used to start and stop this
+// flow (as opposed to signaling objects, etc.), it should be understood that
+// the native message pump will *only* respond to messages.  As a result, it is
+// an excellent choice.  It is also helpful that the starter messages that are
+// placed in the queue when new task arrive also awakens DoRunLoop.
+//
+class BASE_EXPORT MessagePumpForUI : public MessagePumpWin {
+ public:
+  // A MessageFilter implements the common Peek/Translate/Dispatch code to deal
+  // with windows messages.
+  // This abstraction is used to inject TSF message peeking. See
+  // TextServicesMessageFilter.
+  class BASE_EXPORT MessageFilter {
+   public:
+    virtual ~MessageFilter() {}
+    // Implements the functionality exposed by the OS through PeekMessage.
+    virtual BOOL DoPeekMessage(MSG* msg,
+                               HWND window_handle,
+                               UINT msg_filter_min,
+                               UINT msg_filter_max,
+                               UINT remove_msg) {
+      return PeekMessage(msg, window_handle, msg_filter_min, msg_filter_max,
+                         remove_msg);
+    }
+    // Returns true if |message| was consumed by the filter and no extra
+    // processing is required. If this method returns false, it is the
+    // responsibility of the caller to ensure that normal processing takes
+    // place.
+    // The priority to consume messages is the following:
+    // - Native Windows' message filter (CallMsgFilter).
+    // - MessageFilter::ProcessMessage.
+    // - MessagePumpDispatcher.
+    // - TranslateMessage / DispatchMessage.
+    virtual bool ProcessMessage(const MSG& msg) { return false;}
+  };
+  // The application-defined code passed to the hook procedure.
+  static const int kMessageFilterCode = 0x5001;
+
+  MessagePumpForUI();
+  virtual ~MessagePumpForUI();
+
+  // Sets a new MessageFilter. MessagePumpForUI takes ownership of
+  // |message_filter|. When SetMessageFilter is called, old MessageFilter is
+  // deleted.
+  void SetMessageFilter(scoped_ptr<MessageFilter> message_filter);
+
+  // MessagePump methods:
+  virtual void ScheduleWork();
+  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+
+  // Applications can call this to encourage us to process all pending WM_PAINT
+  // messages.  This method will process all paint messages the Windows Message
+  // queue can provide, up to some fixed number (to avoid any infinite loops).
+  void PumpOutPendingPaintMessages();
+
+ private:
+  static LRESULT CALLBACK WndProcThunk(HWND window_handle,
+                                       UINT message,
+                                       WPARAM wparam,
+                                       LPARAM lparam);
+  virtual void DoRunLoop();
+  void InitMessageWnd();
+  void WaitForWork();
+  void HandleWorkMessage();
+  void HandleTimerMessage();
+  bool ProcessNextWindowsMessage();
+  bool ProcessMessageHelper(const MSG& msg);
+  bool ProcessPumpReplacementMessage();
+
+  // Instance of the module containing the window procedure.
+  HMODULE instance_;
+
+  // A hidden message-only window.
+  HWND message_hwnd_;
+
+  scoped_ptr<MessageFilter> message_filter_;
+};
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO extends MessagePumpWin with methods that are particular to a
+// MessageLoop instantiated with TYPE_IO. This version of MessagePump does not
+// deal with Windows mesagges, and instead has a Run loop based on Completion
+// Ports so it is better suited for IO operations.
+//
+class BASE_EXPORT MessagePumpForIO : public MessagePumpWin {
+ public:
+  struct IOContext;
+
+  // Clients interested in receiving OS notifications when asynchronous IO
+  // operations complete should implement this interface and register themselves
+  // with the message pump.
+  //
+  // Typical use #1:
+  //   // Use only when there are no user's buffers involved on the actual IO,
+  //   // so that all the cleanup can be done by the message pump.
+  //   class MyFile : public IOHandler {
+  //     MyFile() {
+  //       ...
+  //       context_ = new IOContext;
+  //       context_->handler = this;
+  //       message_pump->RegisterIOHandler(file_, this);
+  //     }
+  //     ~MyFile() {
+  //       if (pending_) {
+  //         // By setting the handler to NULL, we're asking for this context
+  //         // to be deleted when received, without calling back to us.
+  //         context_->handler = NULL;
+  //       } else {
+  //         delete context_;
+  //      }
+  //     }
+  //     virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+  //                                DWORD error) {
+  //         pending_ = false;
+  //     }
+  //     void DoSomeIo() {
+  //       ...
+  //       // The only buffer required for this operation is the overlapped
+  //       // structure.
+  //       ConnectNamedPipe(file_, &context_->overlapped);
+  //       pending_ = true;
+  //     }
+  //     bool pending_;
+  //     IOContext* context_;
+  //     HANDLE file_;
+  //   };
+  //
+  // Typical use #2:
+  //   class MyFile : public IOHandler {
+  //     MyFile() {
+  //       ...
+  //       message_pump->RegisterIOHandler(file_, this);
+  //     }
+  //     // Plus some code to make sure that this destructor is not called
+  //     // while there are pending IO operations.
+  //     ~MyFile() {
+  //     }
+  //     virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+  //                                DWORD error) {
+  //       ...
+  //       delete context;
+  //     }
+  //     void DoSomeIo() {
+  //       ...
+  //       IOContext* context = new IOContext;
+  //       // This is not used for anything. It just prevents the context from
+  //       // being considered "abandoned".
+  //       context->handler = this;
+  //       ReadFile(file_, buffer, num_bytes, &read, &context->overlapped);
+  //     }
+  //     HANDLE file_;
+  //   };
+  //
+  // Typical use #3:
+  // Same as the previous example, except that in order to deal with the
+  // requirement stated for the destructor, the class calls WaitForIOCompletion
+  // from the destructor to block until all IO finishes.
+  //     ~MyFile() {
+  //       while(pending_)
+  //         message_pump->WaitForIOCompletion(INFINITE, this);
+  //     }
+  //
+  class IOHandler {
+   public:
+    virtual ~IOHandler() {}
+    // This will be called once the pending IO operation associated with
+    // |context| completes. |error| is the Win32 error code of the IO operation
+    // (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero
+    // on error.
+    virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+                               DWORD error) = 0;
+  };
+
+  // An IOObserver is an object that receives IO notifications from the
+  // MessagePump.
+  //
+  // NOTE: An IOObserver implementation should be extremely fast!
+  class IOObserver {
+   public:
+    IOObserver() {}
+
+    virtual void WillProcessIOEvent() = 0;
+    virtual void DidProcessIOEvent() = 0;
+
+   protected:
+    virtual ~IOObserver() {}
+  };
+
+  // The extended context that should be used as the base structure on every
+  // overlapped IO operation. |handler| must be set to the registered IOHandler
+  // for the given file when the operation is started, and it can be set to NULL
+  // before the operation completes to indicate that the handler should not be
+  // called anymore, and instead, the IOContext should be deleted when the OS
+  // notifies the completion of this operation. Please remember that any buffers
+  // involved with an IO operation should be around until the callback is
+  // received, so this technique can only be used for IO that do not involve
+  // additional buffers (other than the overlapped structure itself).
+  struct IOContext {
+    OVERLAPPED overlapped;
+    IOHandler* handler;
+  };
+
+  MessagePumpForIO();
+  virtual ~MessagePumpForIO() {}
+
+  // MessagePump methods:
+  virtual void ScheduleWork();
+  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+
+  // Register the handler to be used when asynchronous IO for the given file
+  // completes. The registration persists as long as |file_handle| is valid, so
+  // |handler| must be valid as long as there is pending IO for the given file.
+  void RegisterIOHandler(HANDLE file_handle, IOHandler* handler);
+
+  // Register the handler to be used to process job events. The registration
+  // persists as long as the job object is live, so |handler| must be valid
+  // until the job object is destroyed. Returns true if the registration
+  // succeeded, and false otherwise.
+  bool RegisterJobObject(HANDLE job_handle, IOHandler* handler);
+
+  // Waits for the next IO completion that should be processed by |filter|, for
+  // up to |timeout| milliseconds. Return true if any IO operation completed,
+  // regardless of the involved handler, and false if the timeout expired. If
+  // the completion port received any message and the involved IO handler
+  // matches |filter|, the callback is called before returning from this code;
+  // if the handler is not the one that we are looking for, the callback will
+  // be postponed for another time, so reentrancy problems can be avoided.
+  // External use of this method should be reserved for the rare case when the
+  // caller is willing to allow pausing regular task dispatching on this thread.
+  bool WaitForIOCompletion(DWORD timeout, IOHandler* filter);
+
+  void AddIOObserver(IOObserver* obs);
+  void RemoveIOObserver(IOObserver* obs);
+
+ private:
+  struct IOItem {
+    IOHandler* handler;
+    IOContext* context;
+    DWORD bytes_transfered;
+    DWORD error;
+
+    // In some cases |context| can be a non-pointer value casted to a pointer.
+    // |has_valid_io_context| is true if |context| is a valid IOContext
+    // pointer, and false otherwise.
+    bool has_valid_io_context;
+  };
+
+  virtual void DoRunLoop();
+  void WaitForWork();
+  bool MatchCompletedIOItem(IOHandler* filter, IOItem* item);
+  bool GetIOItem(DWORD timeout, IOItem* item);
+  bool ProcessInternalIOItem(const IOItem& item);
+  void WillProcessIOEvent();
+  void DidProcessIOEvent();
+
+  // Converts an IOHandler pointer to a completion port key.
+  // |has_valid_io_context| specifies whether completion packets posted to
+  // |handler| will have valid OVERLAPPED pointers.
+  static ULONG_PTR HandlerToKey(IOHandler* handler, bool has_valid_io_context);
+
+  // Converts a completion port key to an IOHandler pointer.
+  static IOHandler* KeyToHandler(ULONG_PTR key, bool* has_valid_io_context);
+
+  // The completion port associated with this thread.
+  win::ScopedHandle port_;
+  // This list will be empty almost always. It stores IO completions that have
+  // not been delivered yet because somebody was doing cleanup.
+  std::list<IOItem> completed_io_;
+
+  ObserverList<IOObserver> io_observers_;
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_WIN_H_
diff --git a/base/metrics/OWNERS b/base/metrics/OWNERS
new file mode 100644
index 0000000..17a1945
--- /dev/null
+++ b/base/metrics/OWNERS
@@ -0,0 +1,8 @@
+# Primary OWNER
+jar@chromium.org
+
+# Secondary OWNER; can review simpler changes
+isherman@chromium.org
+
+# Note that all members of the parent file base/OWNERS can also stamp trivial
+# changes, but will probably defer to Jim for meatier changes.
diff --git a/base/metrics/bucket_ranges.cc b/base/metrics/bucket_ranges.cc
new file mode 100644
index 0000000..949c813
--- /dev/null
+++ b/base/metrics/bucket_ranges.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/bucket_ranges.h"
+
+#include <cmath>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Static table of checksums for all possible 8 bit bytes.
+const uint32 kCrcTable[256] = { 0x0, 0x77073096L, 0xee0e612cL,
+0x990951baL, 0x76dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L,
+0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL,
+0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL,
+0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L,
+0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL,
+0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L,
+0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL,
+0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL,
+0xb6662d3dL, 0x76dc4190L, 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L,
+0x6b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL,
+0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L,
+0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L,
+0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL,
+0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L,
+0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL,
+0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L,
+0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L,
+0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L,
+0x9abfb3b6L, 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L,
+0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL,
+0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L,
+0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L,
+0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L,
+0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L,
+0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL,
+0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L,
+0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L,
+0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L, 0x95bf4a82L,
+0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L,
+0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL,
+0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL,
+0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL,
+0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L,
+0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L,
+0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL,
+0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+0x2d02ef8dL,
+};
+
+// We generate the CRC-32 using the low order bits to select whether to XOR in
+// the reversed polynomial 0xedb88320L.  This is nice and simple, and allows us
+// to keep the quotient in a uint32.  Since we're not concerned about the nature
+// of corruptions (i.e., we don't care about bit sequencing, since we are
+// handling memory changes, which are more grotesque) so we don't bother to
+// get the CRC correct for big-endian vs little-ending calculations.  All we
+// need is a nice hash, that tends to depend on all the bits of the sample, with
+// very little chance of changes in one place impacting changes in another
+// place.
+static uint32 Crc32(uint32 sum, HistogramBase::Sample value) {
+  // TODO(jar): Switch to false and watch stats.
+  const bool kUseRealCrc = true;
+
+  if (kUseRealCrc) {
+    union {
+      HistogramBase::Sample range;
+      unsigned char bytes[sizeof(HistogramBase::Sample)];
+    } converter;
+    converter.range = value;
+    for (size_t i = 0; i < sizeof(converter); ++i)
+      sum = kCrcTable[(sum & 0xff) ^ converter.bytes[i]] ^ (sum >> 8);
+  } else {
+    // Use hash techniques provided in ReallyFastHash, except we don't care
+    // about "avalanching" (which would worsten the hash, and add collisions),
+    // and we don't care about edge cases since we have an even number of bytes.
+    union {
+      HistogramBase::Sample range;
+      uint16 ints[sizeof(HistogramBase::Sample) / 2];
+    } converter;
+    DCHECK_EQ(sizeof(HistogramBase::Sample), sizeof(converter));
+    converter.range = value;
+    sum += converter.ints[0];
+    sum = (sum << 16) ^ sum ^ (static_cast<uint32>(converter.ints[1]) << 11);
+    sum += sum >> 11;
+  }
+  return sum;
+}
+
+BucketRanges::BucketRanges(size_t num_ranges)
+    : ranges_(num_ranges, 0),
+      checksum_(0) {}
+
+BucketRanges::~BucketRanges() {}
+
+void BucketRanges::set_range(size_t i, HistogramBase::Sample value) {
+  DCHECK_LT(i, ranges_.size());
+  CHECK_GE(value, 0);
+  ranges_[i] = value;
+}
+
+uint32 BucketRanges::CalculateChecksum() const {
+  // Seed checksum.
+  uint32 checksum = static_cast<uint32>(ranges_.size());
+
+  for (size_t index = 0; index < ranges_.size(); ++index)
+    checksum = Crc32(checksum, ranges_[index]);
+  return checksum;
+}
+
+bool BucketRanges::HasValidChecksum() const {
+  return CalculateChecksum() == checksum_;
+}
+
+void BucketRanges::ResetChecksum() {
+  checksum_ = CalculateChecksum();
+}
+
+bool BucketRanges::Equals(const BucketRanges* other) const {
+  if (checksum_ != other->checksum_)
+    return false;
+  if (ranges_.size() != other->ranges_.size())
+    return false;
+  for (size_t index = 0; index < ranges_.size(); ++index) {
+    if (ranges_[index] != other->ranges_[index])
+      return false;
+  }
+  return true;
+}
+
+}  // namespace base
diff --git a/base/metrics/bucket_ranges.h b/base/metrics/bucket_ranges.h
new file mode 100644
index 0000000..90b9047
--- /dev/null
+++ b/base/metrics/bucket_ranges.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.
+//
+// BucketRanges stores the vector of ranges that delimit what samples are
+// tallied in the corresponding buckets of a histogram. Histograms that have
+// same ranges for all their corresponding buckets should share the same
+// BucketRanges object.
+//
+// E.g. A 5 buckets LinearHistogram with 1 as minimal value and 4 as maximal
+// value will need a BucketRanges with 6 ranges:
+// 0, 1, 2, 3, 4, INT_MAX
+//
+// TODO(kaiwang): Currently we keep all negative values in 0~1 bucket. Consider
+// changing 0 to INT_MIN.
+
+#ifndef BASE_METRICS_BUCKET_RANGES_H_
+#define BASE_METRICS_BUCKET_RANGES_H_
+
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/metrics/histogram_base.h"
+
+namespace base {
+
+class BASE_EXPORT BucketRanges {
+ public:
+  typedef std::vector<HistogramBase::Sample> Ranges;
+
+  BucketRanges(size_t num_ranges);
+  ~BucketRanges();
+
+  size_t size() const { return ranges_.size(); }
+  HistogramBase::Sample range(size_t i) const { return ranges_[i]; }
+  void set_range(size_t i, HistogramBase::Sample value);
+  uint32 checksum() const { return checksum_; }
+  void set_checksum(uint32 checksum) { checksum_ = checksum; }
+
+  // Checksum methods to verify whether the ranges are corrupted (e.g. bad
+  // memory access).
+  uint32 CalculateChecksum() const;
+  bool HasValidChecksum() const;
+  void ResetChecksum();
+
+  // Return true iff |other| object has same ranges_ as |this| object's ranges_.
+  bool Equals(const BucketRanges* other) const;
+
+ private:
+  // A monotonically increasing list of values which determine which bucket to
+  // put a sample into.  For each index, show the smallest sample that can be
+  // added to the corresponding bucket.
+  Ranges ranges_;
+
+  // Checksum for the conntents of ranges_.  Used to detect random over-writes
+  // of our data, and to quickly see if some other BucketRanges instance is
+  // possibly Equal() to this instance.
+  // TODO(kaiwang): Consider change this to uint64. Because we see a lot of
+  // noise on UMA dashboard.
+  uint32 checksum_;
+
+  DISALLOW_COPY_AND_ASSIGN(BucketRanges);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// Expose only for test.
+BASE_EXPORT_PRIVATE extern const uint32 kCrcTable[256];
+
+}  // namespace base
+
+#endif  // BASE_METRICS_BUCKET_RANGES_H_
diff --git a/base/metrics/bucket_ranges_unittest.cc b/base/metrics/bucket_ranges_unittest.cc
new file mode 100644
index 0000000..424ff63
--- /dev/null
+++ b/base/metrics/bucket_ranges_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/bucket_ranges.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(BucketRangesTest, NormalSetup) {
+  BucketRanges ranges(5);
+  ASSERT_EQ(5u, ranges.size());
+
+  for (int i = 0; i < 5; i++) {
+    EXPECT_EQ(0, ranges.range(i));
+  }
+  EXPECT_EQ(0u, ranges.checksum());
+
+  ranges.set_range(3, 100);
+  EXPECT_EQ(100, ranges.range(3));
+}
+
+TEST(BucketRangesTest, Equals) {
+  // Compare empty ranges.
+  BucketRanges ranges1(3);
+  BucketRanges ranges2(3);
+  BucketRanges ranges3(5);
+
+  EXPECT_TRUE(ranges1.Equals(&ranges2));
+  EXPECT_FALSE(ranges1.Equals(&ranges3));
+  EXPECT_FALSE(ranges2.Equals(&ranges3));
+
+  // Compare full filled ranges.
+  ranges1.set_range(0, 0);
+  ranges1.set_range(1, 1);
+  ranges1.set_range(2, 2);
+  ranges1.set_checksum(100);
+  ranges2.set_range(0, 0);
+  ranges2.set_range(1, 1);
+  ranges2.set_range(2, 2);
+  ranges2.set_checksum(100);
+
+  EXPECT_TRUE(ranges1.Equals(&ranges2));
+
+  // Checksum does not match.
+  ranges1.set_checksum(99);
+  EXPECT_FALSE(ranges1.Equals(&ranges2));
+  ranges1.set_checksum(100);
+
+  // Range does not match.
+  ranges1.set_range(1, 3);
+  EXPECT_FALSE(ranges1.Equals(&ranges2));
+}
+
+TEST(BucketRangesTest, Checksum) {
+  BucketRanges ranges(3);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+
+  ranges.ResetChecksum();
+  EXPECT_EQ(289217253u, ranges.checksum());
+
+  ranges.set_range(2, 3);
+  EXPECT_FALSE(ranges.HasValidChecksum());
+
+  ranges.ResetChecksum();
+  EXPECT_EQ(2843835776u, ranges.checksum());
+  EXPECT_TRUE(ranges.HasValidChecksum());
+}
+
+// Table was generated similarly to sample code for CRC-32 given on:
+// http://www.w3.org/TR/PNG/#D-CRCAppendix.
+TEST(BucketRangesTest, Crc32TableTest) {
+  for (int i = 0; i < 256; ++i) {
+    uint32 checksum = i;
+    for (int j = 0; j < 8; ++j) {
+      const uint32 kReversedPolynomial = 0xedb88320L;
+      if (checksum & 1)
+        checksum = kReversedPolynomial ^ (checksum >> 1);
+      else
+        checksum >>= 1;
+    }
+    EXPECT_EQ(kCrcTable[i], checksum);
+  }
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
new file mode 100644
index 0000000..3214f63
--- /dev/null
+++ b/base/metrics/field_trial.cc
@@ -0,0 +1,470 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/field_trial.h"
+
+#include "base/build_time.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/rand_util.h"
+#include "base/sha1.h"
+#include "base/stringprintf.h"
+#include "base/string_util.h"
+#include "base/sys_byteorder.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+// Created a time value based on |year|, |month| and |day_of_month| parameters.
+Time CreateTimeFromParams(int year, int month, int day_of_month) {
+  DCHECK_GT(year, 1970);
+  DCHECK_GT(month, 0);
+  DCHECK_LT(month, 13);
+  DCHECK_GT(day_of_month, 0);
+  DCHECK_LT(day_of_month, 32);
+
+  Time::Exploded exploded;
+  exploded.year = year;
+  exploded.month = month;
+  exploded.day_of_week = 0;  // Should be unused.
+  exploded.day_of_month = day_of_month;
+  exploded.hour = 0;
+  exploded.minute = 0;
+  exploded.second = 0;
+  exploded.millisecond = 0;
+
+  return Time::FromLocalExploded(exploded);
+}
+
+}  // namespace
+
+static const char kHistogramFieldTrialSeparator('_');
+
+// statics
+const int FieldTrial::kNotFinalized = -1;
+const int FieldTrial::kDefaultGroupNumber = 0;
+bool FieldTrial::enable_benchmarking_ = false;
+
+const char FieldTrialList::kPersistentStringSeparator('/');
+int FieldTrialList::kExpirationYearInFuture = 0;
+
+//------------------------------------------------------------------------------
+// FieldTrial methods and members.
+
+FieldTrial::FieldTrial(const std::string& name,
+                       const Probability total_probability,
+                       const std::string& default_group_name)
+    : name_(name),
+      divisor_(total_probability),
+      default_group_name_(default_group_name),
+      random_(static_cast<Probability>(divisor_ * RandDouble())),
+      accumulated_group_probability_(0),
+      next_group_number_(kDefaultGroupNumber + 1),
+      group_(kNotFinalized),
+      enable_field_trial_(true),
+      forced_(false),
+      group_reported_(false) {
+  DCHECK_GT(total_probability, 0);
+  DCHECK(!name_.empty());
+  DCHECK(!default_group_name_.empty());
+}
+
+FieldTrial::EntropyProvider::~EntropyProvider() {
+}
+
+void FieldTrial::UseOneTimeRandomization() {
+  // No need to specify randomization when the group choice was forced.
+  if (forced_)
+    return;
+  DCHECK_EQ(group_, kNotFinalized);
+  DCHECK_EQ(kDefaultGroupNumber + 1, next_group_number_);
+  const EntropyProvider* entropy_provider =
+      FieldTrialList::GetEntropyProviderForOneTimeRandomization();
+  if (!entropy_provider) {
+    NOTREACHED();
+    // TODO(stevet): Remove this temporary histogram when logging
+    // investigations are complete.
+    UMA_HISTOGRAM_BOOLEAN("Variations.DisabledNoEntropyProvider", true);
+    Disable();
+    return;
+  }
+
+  random_ = static_cast<Probability>(
+      divisor_ * entropy_provider->GetEntropyForTrial(name_));
+}
+
+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_) {
+      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 (!group_reported_) {
+    if (enable_field_trial_)
+      FieldTrialList::NotifyFieldTrialGroupSelection(name_, group_name_);
+    group_reported_ = true;
+  }
+  return group_;
+}
+
+std::string FieldTrial::group_name() {
+  // Call |group()| to ensure group gets assigned and observers are notified.
+  group();
+  DCHECK(!group_name_.empty());
+  return group_name_;
+}
+
+// static
+std::string FieldTrial::MakeName(const std::string& name_prefix,
+                                 const std::string& trial_name) {
+  std::string big_string(name_prefix);
+  big_string.append(1, kHistogramFieldTrialSeparator);
+  return big_string.append(FieldTrialList::FindFullName(trial_name));
+}
+
+// static
+void FieldTrial::EnableBenchmarking() {
+  DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
+  enable_benchmarking_ = true;
+}
+
+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;
+  // Explicit forcing should only be for cases where we want to set the group
+  // probabilities before the hard coded field trial setup is executed. So
+  // there must have been at least one non-default group appended at that point.
+  DCHECK_GT(next_group_number_, kDefaultGroupNumber + 1);
+
+  // And we must finalize the group choice before we mark ourselves as forced.
+  FinalizeGroupChoice();
+  forced_ = true;
+}
+
+FieldTrial::~FieldTrial() {}
+
+void FieldTrial::SetGroupChoice(const std::string& name, int number) {
+  group_ = number;
+  if (name.empty())
+    StringAppendF(&group_name_, "%d", group_);
+  else
+    group_name_ = name;
+  DVLOG(1) << "Field 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_;
+  active_group->group = group_name_;
+  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::Exploded exploded;
+  Time two_years_from_now =
+      Time::NowFromSystemTime() + TimeDelta::FromDays(730);
+  two_years_from_now.LocalExplode(&exploded);
+  kExpirationYearInFuture = exploded.year;
+}
+
+FieldTrialList::~FieldTrialList() {
+  AutoLock auto_lock(lock_);
+  while (!registered_.empty()) {
+    RegistrationList::iterator it = registered_.begin();
+    it->second->Release();
+    registered_.erase(it->first);
+  }
+  DCHECK_EQ(this, global_);
+  global_ = NULL;
+}
+
+// static
+FieldTrial* FieldTrialList::FactoryGetFieldTrial(
+    const std::string& name,
+    FieldTrial::Probability total_probability,
+    const std::string& default_group_name,
+    const int year,
+    const int month,
+    const int day_of_month,
+    int* default_group_number) {
+  if (default_group_number)
+    *default_group_number = FieldTrial::kDefaultGroupNumber;
+  // Check if the field trial has already been created in some other way.
+  FieldTrial* existing_trial = Find(name);
+  if (existing_trial) {
+    CHECK(existing_trial->forced_);
+    // If the field trial has already been forced, check whether it was forced
+    // to the default group. Return the chosen group number, in that case..
+    if (default_group_number &&
+        default_group_name == existing_trial->default_group_name()) {
+      *default_group_number = existing_trial->group();
+    }
+    return existing_trial;
+  }
+
+  FieldTrial* field_trial =
+      new FieldTrial(name, total_probability, default_group_name);
+  if (GetBuildTime() > CreateTimeFromParams(year, month, day_of_month))
+    field_trial->Disable();
+  FieldTrialList::Register(field_trial);
+  return field_trial;
+}
+
+// static
+FieldTrial* FieldTrialList::Find(const std::string& name) {
+  if (!global_)
+    return NULL;
+  AutoLock auto_lock(global_->lock_);
+  return global_->PreLockedFind(name);
+}
+
+// static
+int FieldTrialList::FindValue(const std::string& name) {
+  FieldTrial* field_trial = Find(name);
+  if (field_trial)
+    return field_trial->group();
+  return FieldTrial::kNotFinalized;
+}
+
+// static
+std::string FieldTrialList::FindFullName(const std::string& name) {
+  FieldTrial* field_trial = Find(name);
+  if (field_trial)
+    return field_trial->group_name();
+  return "";
+}
+
+// static
+bool FieldTrialList::TrialExists(const std::string& name) {
+  return Find(name) != NULL;
+}
+
+// static
+void FieldTrialList::StatesToString(std::string* output) {
+  FieldTrial::ActiveGroups active_groups;
+  GetActiveFieldTrialGroups(&active_groups);
+  for (FieldTrial::ActiveGroups::const_iterator it = active_groups.begin();
+       it != active_groups.end(); ++it) {
+    DCHECK_EQ(std::string::npos, it->trial.find(kPersistentStringSeparator));
+    DCHECK_EQ(std::string::npos, it->group.find(kPersistentStringSeparator));
+    output->append(it->trial);
+    output->append(1, kPersistentStringSeparator);
+    output->append(it->group);
+    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 (RegistrationList::iterator it = global_->registered_.begin();
+       it != global_->registered_.end(); ++it) {
+    FieldTrial::ActiveGroup active_group;
+    if (it->second->GetActiveGroup(&active_group))
+      active_groups->push_back(active_group);
+  }
+}
+
+// static
+bool FieldTrialList::CreateTrialsFromString(const std::string& trials_string) {
+  DCHECK(global_);
+  if (trials_string.empty() || !global_)
+    return true;
+
+  size_t next_item = 0;
+  while (next_item < trials_string.length()) {
+    size_t name_end = trials_string.find(kPersistentStringSeparator, next_item);
+    if (name_end == trials_string.npos || next_item == name_end)
+      return false;
+    size_t group_name_end = trials_string.find(kPersistentStringSeparator,
+                                               name_end + 1);
+    if (group_name_end == trials_string.npos || name_end + 1 == group_name_end)
+      return false;
+    std::string name(trials_string, next_item, name_end - next_item);
+    std::string group_name(trials_string, name_end + 1,
+                           group_name_end - name_end - 1);
+    next_item = group_name_end + 1;
+
+    if (!CreateFieldTrial(name, group_name))
+      return false;
+  }
+  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);
+  // This is where we may assign a group number different from
+  // kDefaultGroupNumber to the default group.
+  field_trial->AppendGroup(group_name, kTotalProbability);
+  field_trial->forced_ = true;
+  FieldTrialList::Register(field_trial);
+  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(
+    const std::string& name,
+    const std::string& group_name) {
+  if (!global_)
+    return;
+  global_->observer_list_->Notify(
+      &FieldTrialList::Observer::OnFieldTrialGroupFinalized,
+      name,
+      group_name);
+}
+
+// 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) {
+  RegistrationList::iterator it = registered_.find(name);
+  if (registered_.end() == it)
+    return NULL;
+  return it->second;
+}
+
+// static
+void FieldTrialList::Register(FieldTrial* trial) {
+  if (!global_) {
+    used_without_global_ = true;
+    return;
+  }
+  AutoLock auto_lock(global_->lock_);
+  DCHECK(!global_->PreLockedFind(trial->name()));
+  trial->AddRef();
+  global_->registered_[trial->name()] = trial;
+}
+
+}  // namespace base
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
new file mode 100644
index 0000000..765c50f
--- /dev/null
+++ b/base/metrics/field_trial.h
@@ -0,0 +1,444 @@
+// Copyright (c) 2012 The Chromium 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 startup randomization (generated each time the
+// application starts up, but held constant during the duration of the
+// process), or by continuous randomization across a run (where the state
+// can be recalculated again and again, many times during a process).
+// Continuous randomization is not yet implemented.
+
+//------------------------------------------------------------------------------
+// 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:
+
+//   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,
+//                                                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.
+
+// We then, in addition to our original histogram, output histograms which have
+// slightly different names depending on what group the trial instance happened
+// to randomly be assigned:
+
+// HISTOGRAM_COUNTS("Memory.RendererTotal", count);  // The original histogram.
+// static const bool memory_renderer_total_trial_exists =
+//     FieldTrialList::TrialExists("MemoryExperiment");
+// if (memory_renderer_total_trial_exists) {
+//   HISTOGRAM_COUNTS(FieldTrial::MakeName("Memory.RendererTotal",
+//                                         "MemoryExperiment"), count);
+// }
+
+// The above code will create four distinct histograms, with each run of the
+// application being assigned to of of the three groups, and for each group, the
+// correspondingly named histogram will be populated:
+
+// Memory.RendererTotal              // 100% of users still fill this histogram.
+// Memory.RendererTotal_HighMem      // 2% of users will fill this histogram.
+// Memory.RendererTotal_LowMem       // 2% of users will fill this histogram.
+// Memory.RendererTotal_StandardMem  // 96% of users will fill this histogram.
+
+//------------------------------------------------------------------------------
+
+#ifndef BASE_METRICS_FIELD_TRIAL_H_
+#define BASE_METRICS_FIELD_TRIAL_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/synchronization/lock.h"
+#include "base/time.h"
+
+namespace base {
+
+class FieldTrialList;
+
+class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
+ public:
+  typedef int Probability;  // Probability type for being selected in a trial.
+
+  // 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) based on |trial_name| that will
+    // be used for the dice roll for the specified field trial. A given instance
+    // should always return the same value given the same input |trial_name|.
+    virtual double GetEntropyForTrial(const std::string& trial_name) const = 0;
+  };
+
+  // A pair representing a Field Trial and its selected group.
+  struct ActiveGroup {
+    std::string trial;
+    std::string group;
+  };
+
+  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;
+
+  // Changes the field trial to use one-time randomization, i.e. produce the
+  // same result for the current trial on every run of this client. Must be
+  // called right after construction.
+  void UseOneTimeRandomization();
+
+  // 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).
+  std::string name() const { return 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.
+  std::string group_name();
+
+  // Helper function for the most common use: as an argument to specify the
+  // name of a HISTOGRAM.  Use the original histogram name as the name_prefix.
+  static std::string MakeName(const std::string& name_prefix,
+                              const std::string& trial_name);
+
+  // Enable benchmarking sets field trials to a common setting.
+  static void EnableBenchmarking();
+
+  // 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();
+
+ 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, ActiveGroupsNotFinalized);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MakeName);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientId);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientIdIsUniform);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, NameGroupIds);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, UseOneTimeRandomization);
+
+  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;
+
+  FieldTrial(const std::string& name,
+             Probability total_probability,
+             const std::string& default_group_name);
+  virtual ~FieldTrial();
+
+  // Return the default group name of the FieldTrial.
+  std::string default_group_name() const { return default_group_name_; }
+
+  // Sets the group_name as well as group_name_hash to make sure they are sync.
+  void SetGroupChoice(const std::string& 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 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 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_;
+
+  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_;
+
+  // 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:
+  // Define a separator character to use when creating a persistent form of an
+  // instance.  This is intended for use as a command line argument, passed to a
+  // second process to mimic our state (i.e., provide the same group name).
+  static const char kPersistentStringSeparator;  // Currently a slash.
+
+  // Define expiration year in future. It is initialized to two years from Now.
+  static int kExpirationYearInFuture;
+
+  // 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. |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. If you want a one-time randomized
+  // trial, call UseOneTimeRandomization() right after creation.
+  static FieldTrial* FactoryGetFieldTrial(
+      const std::string& name,
+      FieldTrial::Probability total_probability,
+      const std::string& default_group_name,
+      const int year,
+      const int month,
+      const int day_of_month,
+      int* default_group_number);
+
+  // The Find() method can be used to test to see if a named Trial was already
+  // registered, or to retrieve a pointer to it from the global map.
+  static FieldTrial* Find(const std::string& name);
+
+  // Returns the group number chosen for the named trial, or
+  // FieldTrial::kNotFinalized if the trial does not exist.
+  static int FindValue(const std::string& name);
+
+  // Returns the group name chosen for the named trial, or the
+  // empty string if the trial does not exist.
+  static std::string FindFullName(const std::string& name);
+
+  // Returns true if the named trial has been registered.
+  static bool TrialExists(const std::string& name);
+
+  // Creates a persistent representation of active FieldTrial instances for
+  // resurrection in another process. This allows randomization to be done in
+  // one process, and secondary processes can be synchronized on the result.
+  // The resulting string contains the name and group name pairs of all
+  // registered FieldTrials for which the group has been chosen and externally
+  // observed (via |group()|) and which have not been disabled, with "/" used
+  // to separate all names and to terminate the string. This string is parsed
+  // by |CreateTrialsFromString()|.
+  static void StatesToString(std::string* output);
+
+  // Fills in the supplied vector |active_groups| (which must be empty when
+  // called) with a snapshot of all registered FieldTrials for which the group
+  // has been chosen and externally observed (via |group()|) and which have
+  // not been disabled.
+  static void GetActiveFieldTrialGroups(
+      FieldTrial::ActiveGroups* active_groups);
+
+  // Use a state string (re: StatesToString()) to augment the current list of
+  // field tests to include the supplied tests, and using a 100% probability for
+  // each test, 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.
+  static bool CreateTrialsFromString(const std::string& prior_trials);
+
+  // 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 is finalized for the named Trial.
+  static void NotifyFieldTrialGroupSelection(const std::string& name,
+                                             const std::string& group_name);
+
+  // Return the number of active field trials.
+  static size_t GetFieldTrialCount();
+
+  // If one-time randomization is enabled, returns a weak pointer to the
+  // corresponding EntropyProvider. Otherwise, returns NULL.
+  static const FieldTrial::EntropyProvider*
+      GetEntropyProviderForOneTimeRandomization();
+
+ private:
+  // A map from FieldTrial names to the actual instances.
+  typedef std::map<std::string, FieldTrial*> RegistrationList;
+
+  // 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_;
+  RegistrationList registered_;
+
+  // Entropy provider to be used for one-time randomized field trials. If NULL,
+  // one-time randomization is not supported.
+  scoped_ptr<const FieldTrial::EntropyProvider> entropy_provider_;
+
+  // List of observers to be notified when a group is selected for a FieldTrial.
+  scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(FieldTrialList);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_FIELD_TRIAL_H_
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
new file mode 100644
index 0000000..673e6b6
--- /dev/null
+++ b/base/metrics/field_trial_unittest.cc
@@ -0,0 +1,649 @@
+// Copyright (c) 2012 The Chromium Authors. All 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.h"
+#include "base/metrics/field_trial.h"
+#include "base/rand_util.h"
+#include "base/stringprintf.h"
+#include "base/string_number_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Default group name used by several tests.
+const char kDefaultGroupName[] = "DefaultGroup";
+
+// FieldTrialList::Observer implementation for testing.
+class TestFieldTrialObserver : public FieldTrialList::Observer {
+ public:
+  TestFieldTrialObserver() {
+    FieldTrialList::AddObserver(this);
+  }
+
+  virtual ~TestFieldTrialObserver() {
+    FieldTrialList::RemoveObserver(this);
+  }
+
+  virtual 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) {
+    Time now = Time::NowFromSystemTime();
+    TimeDelta one_year = TimeDelta::FromDays(365);
+    Time::Exploded exploded;
+
+    Time next_year_time = now + one_year;
+    next_year_time.LocalExplode(&exploded);
+    next_year_ = exploded.year;
+
+    Time last_year_time = now - one_year;
+    last_year_time.LocalExplode(&exploded);
+    last_year_ = exploded.year;
+  }
+
+ protected:
+  int next_year_;
+  int last_year_;
+  MessageLoop message_loop_;
+
+ private:
+  FieldTrialList trial_list_;
+};
+
+// Test registration, and also check that destructors are called for trials
+// (and that Valgrind doesn't catch us leaking).
+TEST_F(FieldTrialTest, Registration) {
+  const char* name1 = "name 1 test";
+  const char* name2 = "name 2 test";
+  EXPECT_FALSE(FieldTrialList::Find(name1));
+  EXPECT_FALSE(FieldTrialList::Find(name2));
+
+  FieldTrial* trial1 = FieldTrialList::FactoryGetFieldTrial(
+      name1, 10, "default name 1 test", next_year_, 12, 31, NULL);
+  EXPECT_EQ(FieldTrial::kNotFinalized, trial1->group_);
+  EXPECT_EQ(name1, trial1->name());
+  EXPECT_EQ("", trial1->group_name_internal());
+
+  trial1->AppendGroup("", 7);
+
+  EXPECT_EQ(trial1, FieldTrialList::Find(name1));
+  EXPECT_FALSE(FieldTrialList::Find(name2));
+
+  FieldTrial* trial2 = FieldTrialList::FactoryGetFieldTrial(
+      name2, 10, "default name 2 test", next_year_, 12, 31, NULL);
+  EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_);
+  EXPECT_EQ(name2, trial2->name());
+  EXPECT_EQ("", trial2->group_name_internal());
+
+  trial2->AppendGroup("a first group", 7);
+
+  EXPECT_EQ(trial1, FieldTrialList::Find(name1));
+  EXPECT_EQ(trial2, 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.
+    always_true[0] = i;
+    default_always_true[0] = i;
+    always_false[0] = i;
+    default_always_false[0] = i;
+
+    FieldTrial* trial_true = FieldTrialList::FactoryGetFieldTrial(
+        always_true, 10, default_always_true, next_year_, 12, 31, 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());
+
+    FieldTrial* trial_false = FieldTrialList::FactoryGetFieldTrial(
+        always_false, 10, default_always_false, next_year_, 12, 31, 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 = FieldTrialList::FactoryGetFieldTrial(
+        name, 10, winner, next_year_, 12, 31, &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(FieldTrialList::FactoryGetFieldTrial(
+        name, 2, default_group_name, next_year_, 12, 31, 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) {
+    name[0] = i;
+    default_group_name[0] = i;
+    FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
+        name, 10, default_group_name, next_year_, 12, 31, 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;
+  FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
+      name, group_count, default_group_name, next_year_, 12, 31,
+      &default_group_number);
+  int winner_index(-2);
+  std::string winner_name;
+
+  for (int i = 1; i <= group_count; ++i) {
+    int might_win = trial->AppendGroup("", 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;
+  scoped_refptr<FieldTrial> trial;
+  trial = FieldTrialList::FactoryGetFieldTrial(
+      name, 1000000000, default_group_name, last_year_, 1, 1,
+      &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(FieldTrialList::FactoryGetFieldTrial(
+      no_group, 10, "Default", next_year_, 12, 31, 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 = FieldTrialList::FactoryGetFieldTrial(
+      one_winner, 10, "Default", next_year_, 12, 31, 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);
+  EXPECT_EQ(winner, active_group.group);
+
+  std::string multi_group("MultiGroup");
+  scoped_refptr<FieldTrial> multi_group_trial =
+      FieldTrialList::FactoryGetFieldTrial(multi_group, 9, "Default",
+                                            next_year_, 12, 31, 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);
+  EXPECT_EQ(multi_group_trial->group_name(), active_group.group);
+
+  // 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);
+    EXPECT_TRUE(one_winner != active_groups[i].trial ||
+                winner == active_groups[i].group);
+    EXPECT_TRUE(multi_group != active_groups[i].trial ||
+                multi_group_trial->group_name() == active_groups[i].group);
+  }
+}
+
+TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) {
+  const char kTrialName[] = "TestTrial";
+  const char kSecondaryGroupName[] = "SecondaryGroup";
+
+  int default_group = -1;
+  FieldTrial* trial =
+      FieldTrialList::FactoryGetFieldTrial(kTrialName, 100, kDefaultGroupName,
+                                           next_year_, 12, 31, &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);
+  if (chosen_group == default_group)
+    EXPECT_EQ(kDefaultGroupName, active_group.group);
+  else
+    EXPECT_EQ(kSecondaryGroupName, active_group.group);
+
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_EQ(1U, active_groups.size());
+  EXPECT_EQ(kTrialName, active_groups[0].trial);
+  EXPECT_EQ(active_group.group, active_groups[0].group);
+}
+
+TEST_F(FieldTrialTest, Save) {
+  std::string save_string;
+
+  FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
+      "Some name", 10, "Default some name", next_year_, 12, 31, 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.
+  FieldTrial* trial2 = FieldTrialList::FactoryGetFieldTrial(
+      "xxx", 10, "Default xxx", next_year_, 12, 31, 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.
+  FieldTrial* trial3 = FieldTrialList::FactoryGetFieldTrial(
+      "zzz", 10, "default", next_year_, 12, 31, 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, Restore) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("xxx"));
+
+  FieldTrialList::CreateTrialsFromString("Some_name/Winner/xxx/yyyy/");
+
+  FieldTrial* trial = FieldTrialList::Find("Some_name");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("Winner", trial->group_name());
+  EXPECT_EQ("Some_name", trial->name());
+
+  trial = FieldTrialList::Find("xxx");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("yyyy", trial->group_name());
+  EXPECT_EQ("xxx", trial->name());
+}
+
+TEST_F(FieldTrialTest, BogusRestore) {
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingSlash"));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingGroupName/"));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "MissingFinalSlash/gname"));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "noname, only group/"));
+}
+
+TEST_F(FieldTrialTest, DuplicateRestore) {
+  FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
+      "Some name", 10, "Default some name", next_year_, 12, 31, 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));
+
+  // But it is an error to try to change to a different winner.
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("Some name/Loser/"));
+}
+
+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->name());
+}
+
+TEST_F(FieldTrialTest, DuplicateFieldTrial) {
+  FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
+      "Some_name", 10, "Default some name", next_year_, 12, 31, 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, MakeName) {
+  FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
+      "Field Trial", 10, "Winner", next_year_, 12, 31, NULL);
+  trial->group();
+  EXPECT_EQ("Histogram_Winner",
+            FieldTrial::MakeName("Histogram", "Field Trial"));
+}
+
+TEST_F(FieldTrialTest, DisableImmediately) {
+  int default_group_number = -1;
+  FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
+      "trial", 100, "default", next_year_, 12, 31, &default_group_number);
+  trial->Disable();
+  ASSERT_EQ("default", trial->group_name());
+  ASSERT_EQ(default_group_number, trial->group());
+}
+
+TEST_F(FieldTrialTest, DisableAfterInitialization) {
+  FieldTrial* trial =
+      FieldTrialList::FactoryGetFieldTrial("trial", 100, "default",
+                                            next_year_, 12, 31, 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;
+  FieldTrial* factory_trial = FieldTrialList::FactoryGetFieldTrial(
+      "Use the", 1000, "default", next_year_, 12, 31, &default_group_number);
+  EXPECT_EQ(factory_trial, 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);
+
+  // Forcing the default should use the proper group ID.
+  forced_trial = FieldTrialList::CreateFieldTrial("Trial Name", "Default");
+  factory_trial = FieldTrialList::FactoryGetFieldTrial(
+      "Trial Name", 1000, "Default", next_year_, 12, 31, &default_group_number);
+  EXPECT_EQ(forced_trial, factory_trial);
+
+  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;
+  FieldTrial* forced_trial = FieldTrialList::FactoryGetFieldTrial(
+      "Use the", 1, "default", next_year_, 12, 31, &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.
+  FieldTrial* hard_coded_trial = FieldTrialList::FactoryGetFieldTrial(
+      "Use the", 1, "default", next_year_, 12, 31, &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.
+  FieldTrial* other_hard_coded_trial = FieldTrialList::FactoryGetFieldTrial(
+      "Use the", 1, "default", next_year_, 12, 31, &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, Observe) {
+  const char kTrialName[] = "TrialToObserve1";
+  const char kSecondaryGroupName[] = "SecondaryGroup";
+
+  TestFieldTrialObserver observer;
+  int default_group = -1;
+  FieldTrial* trial =
+      FieldTrialList::FactoryGetFieldTrial(kTrialName, 100, kDefaultGroupName,
+                                           next_year_, 12, 31, &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);
+
+  message_loop_.RunAllPending();
+  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;
+  FieldTrial* trial =
+      FieldTrialList::FactoryGetFieldTrial(kTrialName, 100, kDefaultGroupName,
+                                           next_year_, 12, 31, &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.
+  message_loop_.RunAllPending();
+  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());
+  message_loop_.RunAllPending();
+  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;
+  FieldTrial* trial =
+      FieldTrialList::FactoryGetFieldTrial(kTrialName, 100, kDefaultGroupName,
+                                           next_year_, 12, 31, &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.
+  message_loop_.RunAllPending();
+  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());
+  message_loop_.RunAllPending();
+  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));
+
+  FieldTrial* trial =
+      FieldTrialList::FactoryGetFieldTrial(kTrialName, 100, kDefaultGroupName,
+                                           next_year_, 12, 31, 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());
+}
+
+
+}  // namespace base
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
new file mode 100644
index 0000000..795ea3a
--- /dev/null
+++ b/base/metrics/histogram.cc
@@ -0,0 +1,866 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Histogram is an object that aggregates statistics, and can summarize them in
+// various forms, including ASCII graphical, HTML, and numerically (as a
+// vector of numbers corresponding to each of the aggregating buckets).
+// See header file for details and examples.
+
+#include "base/metrics/histogram.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/debug/alias.h"
+#include "base/logging.h"
+#include "base/metrics/sample_vector.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/values.h"
+
+using std::string;
+using std::vector;
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+// static
+const size_t Histogram::kBucketCount_MAX = 16384u;
+
+// TODO(rtenneti): delete this code after debugging.
+void CheckCorruption(const Histogram& histogram, bool new_histogram) {
+  const std::string& histogram_name = histogram.histogram_name();
+  char histogram_name_buf[128];
+  base::strlcpy(histogram_name_buf,
+                histogram_name.c_str(),
+                arraysize(histogram_name_buf));
+  base::debug::Alias(histogram_name_buf);
+
+  bool debug_new_histogram[1];
+  debug_new_histogram[0] = new_histogram;
+  base::debug::Alias(debug_new_histogram);
+
+  Sample previous_range = -1;  // Bottom range is always 0.
+  for (size_t index = 0; index < histogram.bucket_count(); ++index) {
+    int new_range = histogram.ranges(index);
+    CHECK_LT(previous_range, new_range);
+    previous_range = new_range;
+  }
+
+  CHECK(histogram.bucket_ranges()->HasValidChecksum());
+}
+
+Histogram* Histogram::FactoryGet(const string& name,
+                                 Sample minimum,
+                                 Sample maximum,
+                                 size_t bucket_count,
+                                 int32 flags) {
+  bool valid_arguments =
+      InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
+  DCHECK(valid_arguments);
+
+  Histogram* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    BucketRanges* ranges = new BucketRanges(bucket_count + 1);
+    InitializeBucketRanges(minimum, maximum, bucket_count, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    Histogram* tentative_histogram =
+        new Histogram(name, minimum, maximum, bucket_count, registered_ranges);
+    CheckCorruption(*tentative_histogram, true);
+
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+  // TODO(rtenneti): delete this code after debugging.
+  CheckCorruption(*histogram, false);
+
+  CHECK_EQ(HISTOGRAM, histogram->GetHistogramType());
+  CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count));
+  return histogram;
+}
+
+Histogram* Histogram::FactoryTimeGet(const string& name,
+                                     TimeDelta minimum,
+                                     TimeDelta maximum,
+                                     size_t bucket_count,
+                                     int32 flags) {
+  return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
+                    bucket_count, flags);
+}
+
+TimeTicks Histogram::DebugNow() {
+#ifndef NDEBUG
+  return TimeTicks::Now();
+#else
+  return TimeTicks();
+#endif
+}
+
+// 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,
+                                       size_t bucket_count,
+                                       BucketRanges* ranges) {
+  DCHECK_EQ(ranges->size(), bucket_count + 1);
+  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);
+  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->size() - 1, HistogramBase::kSampleType_MAX);
+  ranges->ResetChecksum();
+}
+
+void Histogram::AddBoolean(bool value) {
+  DCHECK(false);
+}
+
+void Histogram::AddSamples(const HistogramSamples& samples) {
+  samples_->Add(samples);
+}
+
+bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
+  return samples_->AddFromPickle(iter);
+}
+
+// static
+string Histogram::SerializeHistogramInfo(const Histogram& histogram,
+                                         const HistogramSamples& snapshot) {
+  DCHECK(histogram.bucket_ranges()->HasValidChecksum());
+
+  Pickle pickle;
+  pickle.WriteString(histogram.histogram_name());
+  pickle.WriteInt(histogram.declared_min());
+  pickle.WriteInt(histogram.declared_max());
+  pickle.WriteUInt64(histogram.bucket_count());
+  pickle.WriteUInt32(histogram.bucket_ranges()->checksum());
+  pickle.WriteInt(histogram.GetHistogramType());
+  pickle.WriteInt(histogram.flags());
+
+  histogram.SerializeRanges(&pickle);
+
+  snapshot.Serialize(&pickle);
+
+  return string(static_cast<const char*>(pickle.data()), pickle.size());
+}
+
+// static
+bool Histogram::DeserializeHistogramInfo(const string& histogram_info) {
+  if (histogram_info.empty()) {
+    return false;
+  }
+
+  Pickle pickle(histogram_info.data(),
+                static_cast<int>(histogram_info.size()));
+  string histogram_name;
+  int declared_min;
+  int declared_max;
+  uint64 bucket_count;
+  uint32 range_checksum;
+  int histogram_type;
+  int pickle_flags;
+
+  PickleIterator iter(pickle);
+  if (!iter.ReadString(&histogram_name) ||
+      !iter.ReadInt(&declared_min) ||
+      !iter.ReadInt(&declared_max) ||
+      !iter.ReadUInt64(&bucket_count) ||
+      !iter.ReadUInt32(&range_checksum) ||
+      !iter.ReadInt(&histogram_type) ||
+      !iter.ReadInt(&pickle_flags)) {
+    DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
+    return false;
+  }
+
+  DCHECK(pickle_flags & kIPCSerializationSourceFlag);
+  // 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(Count) <= bucket_count || bucket_count < 2) {
+    DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
+    return false;
+  }
+
+  Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag);
+
+  Histogram* render_histogram(NULL);
+
+  if (histogram_type == HISTOGRAM) {
+    render_histogram = Histogram::FactoryGet(
+        histogram_name, declared_min, declared_max, bucket_count, flags);
+  } else if (histogram_type == LINEAR_HISTOGRAM) {
+    render_histogram = LinearHistogram::FactoryGet(
+        histogram_name, declared_min, declared_max, bucket_count, flags);
+  } else if (histogram_type == BOOLEAN_HISTOGRAM) {
+    render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
+  } else if (histogram_type == CUSTOM_HISTOGRAM) {
+    vector<Sample> sample_ranges(bucket_count);
+    if (!CustomHistogram::DeserializeRanges(&iter, &sample_ranges)) {
+      DLOG(ERROR) << "Pickle error decoding ranges: " << histogram_name;
+      return false;
+    }
+    render_histogram =
+        CustomHistogram::FactoryGet(histogram_name, sample_ranges, flags);
+  } else {
+    DLOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
+                << histogram_type;
+    return false;
+  }
+
+  DCHECK_EQ(render_histogram->declared_min(), declared_min);
+  DCHECK_EQ(render_histogram->declared_max(), declared_max);
+  DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
+  DCHECK_EQ(render_histogram->GetHistogramType(), histogram_type);
+
+  if (render_histogram->bucket_ranges()->checksum() != range_checksum) {
+    return false;
+  }
+
+  if (render_histogram->flags() & kIPCSerializationSourceFlag) {
+    DVLOG(1) << "Single process mode, histogram observed and not copied: "
+             << histogram_name;
+    return true;
+  }
+
+  DCHECK_EQ(flags & render_histogram->flags(), flags);
+  return render_histogram->AddSamplesFromPickle(&iter);
+}
+
+// static
+const int Histogram::kCommonRaceBasedCountMismatch = 5;
+
+Histogram::Inconsistencies Histogram::FindCorruption(
+    const HistogramSamples& samples) const {
+  int inconsistencies = NO_INCONSISTENCIES;
+  Sample previous_range = -1;  // Bottom range is always 0.
+  for (size_t index = 0; index < bucket_count(); ++index) {
+    int new_range = ranges(index);
+    if (previous_range >= new_range)
+      inconsistencies |= BUCKET_ORDER_ERROR;
+    previous_range = new_range;
+  }
+
+  if (!bucket_ranges()->HasValidChecksum())
+    inconsistencies |= RANGE_CHECKSUM_ERROR;
+
+  int64 delta64 = samples.redundant_count() - samples.TotalCount();
+  if (delta64 != 0) {
+    int delta = static_cast<int>(delta64);
+    if (delta != delta64)
+      delta = INT_MAX;  // Flag all giant errors as INT_MAX.
+    if (delta > 0) {
+      UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
+      if (delta > kCommonRaceBasedCountMismatch)
+        inconsistencies |= COUNT_HIGH_ERROR;
+    } else {
+      DCHECK_GT(0, delta);
+      UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
+      if (-delta > kCommonRaceBasedCountMismatch)
+        inconsistencies |= COUNT_LOW_ERROR;
+    }
+  }
+  return static_cast<Inconsistencies>(inconsistencies);
+}
+
+Sample Histogram::ranges(size_t i) const {
+  return bucket_ranges_->range(i);
+}
+
+size_t Histogram::bucket_count() const {
+  return bucket_count_;
+}
+
+// static
+bool Histogram::InspectConstructionArguments(const string& name,
+                                             Sample* minimum,
+                                             Sample* maximum,
+                                             size_t* bucket_count) {
+  // Defensive code for backward compatibility.
+  if (*minimum < 1) {
+    DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum;
+    *minimum = 1;
+  }
+  if (*maximum >= kSampleType_MAX) {
+    DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum;
+    *maximum = kSampleType_MAX - 1;
+  }
+  if (*bucket_count >= kBucketCount_MAX) {
+    DVLOG(1) << "Histogram: " << name << " has bad bucket_count: "
+             << *bucket_count;
+    *bucket_count = kBucketCount_MAX - 1;
+  }
+
+  if (*minimum >= *maximum)
+    return false;
+  if (*bucket_count < 3)
+    return false;
+  if (*bucket_count > static_cast<size_t>(*maximum - *minimum + 2))
+    return false;
+  return true;
+}
+
+HistogramType Histogram::GetHistogramType() const {
+  return HISTOGRAM;
+}
+
+bool Histogram::HasConstructionArguments(Sample minimum,
+                                         Sample maximum,
+                                         size_t bucket_count) const {
+  return ((minimum == declared_min_) && (maximum == declared_max_) &&
+          (bucket_count == bucket_count_));
+}
+
+void Histogram::Add(int value) {
+  DCHECK_EQ(0, ranges(0));
+  DCHECK_EQ(kSampleType_MAX, ranges(bucket_count_));
+
+  if (value > kSampleType_MAX - 1)
+    value = kSampleType_MAX - 1;
+  if (value < 0)
+    value = 0;
+  samples_->Accumulate(value, 1);
+}
+
+scoped_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
+  return SnapshotSampleVector().PassAs<HistogramSamples>();
+}
+
+// The following methods provide a graphical histogram display.
+void Histogram::WriteHTMLGraph(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(string* output) const {
+  WriteAsciiImpl(true, "\n", output);
+}
+
+Histogram::Histogram(const string& name,
+                     Sample minimum,
+                     Sample maximum,
+                     size_t bucket_count,
+                     const BucketRanges* ranges)
+  : HistogramBase(name),
+    bucket_ranges_(ranges),
+    declared_min_(minimum),
+    declared_max_(maximum),
+    bucket_count_(bucket_count) {
+  if (ranges)
+    samples_.reset(new SampleVector(ranges));
+}
+
+Histogram::~Histogram() {
+  if (StatisticsRecorder::dump_on_exit()) {
+    string output;
+    WriteAsciiImpl(true, "\n", &output);
+    DLOG(INFO) << output;
+  }
+}
+
+bool Histogram::SerializeRanges(Pickle* pickle) const {
+  return true;
+}
+
+bool Histogram::PrintEmptyBucket(size_t index) const {
+  return true;
+}
+
+// Use the actual bucket widths (like a linear histogram) until the widths get
+// over some transition value, and then use that transition width.  Exponentials
+// get so big so fast (and we don't expect to see a lot of entries in the large
+// buckets), so we need this to make it possible to see what is going on and
+// not have 0-graphical-height buckets.
+double Histogram::GetBucketSize(Count current, size_t i) const {
+  DCHECK_GT(ranges(i + 1), ranges(i));
+  static const double kTransitionWidth = 5;
+  double denominator = ranges(i + 1) - ranges(i);
+  if (denominator > kTransitionWidth)
+    denominator = kTransitionWidth;  // Stop trying to normalize.
+  return current/denominator;
+}
+
+const string Histogram::GetAsciiBucketRange(size_t i) const {
+  string result;
+  if (kHexRangePrintingFlag & flags())
+    StringAppendF(&result, "%#x", ranges(i));
+  else
+    StringAppendF(&result, "%d", ranges(i));
+  return result;
+}
+
+//------------------------------------------------------------------------------
+// Private methods
+
+scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const {
+  scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
+  samples->Add(*samples_);
+  return samples.Pass();
+}
+
+void Histogram::WriteAsciiImpl(bool graph_it,
+                               const string& newline,
+                               string* output) const {
+  // Get local (stack) copies of all effectively volatile class data so that we
+  // are consistent across our output activities.
+  scoped_ptr<SampleVector> snapshot = SnapshotSampleVector();
+  Count sample_count = snapshot->TotalCount();
+
+  WriteAsciiHeader(*snapshot, sample_count, output);
+  output->append(newline);
+
+  // Prepare to normalize graphical rendering of bucket contents.
+  double max_size = 0;
+  if (graph_it)
+    max_size = GetPeakBucketSize(*snapshot);
+
+  // Calculate space needed to print bucket range numbers.  Leave room to print
+  // nearly the largest bucket range without sliding over the histogram.
+  size_t largest_non_empty_bucket = bucket_count() - 1;
+  while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket)) {
+    if (0 == largest_non_empty_bucket)
+      break;  // All buckets are empty.
+    --largest_non_empty_bucket;
+  }
+
+  // Calculate largest print width needed for any of our bucket range displays.
+  size_t print_width = 1;
+  for (size_t i = 0; i < bucket_count(); ++i) {
+    if (snapshot->GetCountAtIndex(i)) {
+      size_t width = GetAsciiBucketRange(i).size() + 1;
+      if (width > print_width)
+        print_width = width;
+    }
+  }
+
+  int64 remaining = sample_count;
+  int64 past = 0;
+  // Output the actual histogram graph.
+  for (size_t i = 0; i < bucket_count(); ++i) {
+    Count current = snapshot->GetCountAtIndex(i);
+    if (!current && !PrintEmptyBucket(i))
+      continue;
+    remaining -= current;
+    string range = GetAsciiBucketRange(i);
+    output->append(range);
+    for (size_t j = 0; range.size() + j < print_width + 1; ++j)
+      output->push_back(' ');
+    if (0 == current && i < bucket_count() - 1 &&
+        0 == snapshot->GetCountAtIndex(i + 1)) {
+      while (i < bucket_count() - 1 &&
+             0 == snapshot->GetCountAtIndex(i + 1)) {
+        ++i;
+      }
+      output->append("... ");
+      output->append(newline);
+      continue;  // No reason to plot emptiness.
+    }
+    double current_size = GetBucketSize(current, i);
+    if (graph_it)
+      WriteAsciiBucketGraph(current_size, max_size, output);
+    WriteAsciiBucketContext(past, current, remaining, i, output);
+    output->append(newline);
+    past += current;
+  }
+  DCHECK_EQ(sample_count, past);
+}
+
+double Histogram::GetPeakBucketSize(const SampleVector& samples) const {
+  double max = 0;
+  for (size_t i = 0; i < bucket_count() ; ++i) {
+    double current_size = GetBucketSize(samples.GetCountAtIndex(i), i);
+    if (current_size > max)
+      max = current_size;
+  }
+  return max;
+}
+
+void Histogram::WriteAsciiHeader(const SampleVector& samples,
+                                 Count sample_count,
+                                 string* output) const {
+  StringAppendF(output,
+                "Histogram: %s recorded %d samples",
+                histogram_name().c_str(),
+                sample_count);
+  if (0 == sample_count) {
+    DCHECK_EQ(samples.sum(), 0);
+  } else {
+    double average = static_cast<float>(samples.sum()) / sample_count;
+
+    StringAppendF(output, ", average = %.1f", average);
+  }
+  if (flags() & ~kHexRangePrintingFlag)
+    StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
+}
+
+void Histogram::WriteAsciiBucketContext(const int64 past,
+                                        const Count current,
+                                        const int64 remaining,
+                                        const size_t i,
+                                        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::WriteAsciiBucketValue(Count current,
+                                      double scaled_sum,
+                                      string* output) const {
+  StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
+}
+
+void Histogram::WriteAsciiBucketGraph(double current_size,
+                                      double max_size,
+                                      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(" ");
+}
+
+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, ListValue* buckets) const {
+  scoped_ptr<SampleVector> snapshot = SnapshotSampleVector();
+  *count = snapshot->TotalCount();
+  size_t index = 0;
+  for (size_t i = 0; i < bucket_count(); ++i) {
+    Sample count = snapshot->GetCountAtIndex(i);
+    if (count > 0) {
+      scoped_ptr<DictionaryValue> bucket_value(new DictionaryValue());
+      bucket_value->SetInteger("low", ranges(i));
+      if (i != bucket_count() - 1)
+        bucket_value->SetInteger("high", ranges(i + 1));
+      bucket_value->SetInteger("count", count);
+      buckets->Set(index, bucket_value.release());
+      ++index;
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+// LinearHistogram: This histogram uses a traditional set of evenly spaced
+// buckets.
+//------------------------------------------------------------------------------
+
+LinearHistogram::~LinearHistogram() {}
+
+Histogram* LinearHistogram::FactoryGet(const string& name,
+                                       Sample minimum,
+                                       Sample maximum,
+                                       size_t bucket_count,
+                                       int32 flags) {
+  return FactoryGetWithRangeDescription(
+      name, minimum, maximum, bucket_count, flags, NULL);
+}
+
+Histogram* LinearHistogram::FactoryTimeGet(const string& name,
+                                           TimeDelta minimum,
+                                           TimeDelta maximum,
+                                           size_t bucket_count,
+                                           int32 flags) {
+  return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
+                    bucket_count, flags);
+}
+
+Histogram* LinearHistogram::FactoryGetWithRangeDescription(
+      const std::string& name,
+      Sample minimum,
+      Sample maximum,
+      size_t bucket_count,
+      int32 flags,
+      const DescriptionPair descriptions[]) {
+  bool valid_arguments = Histogram::InspectConstructionArguments(
+      name, &minimum, &maximum, &bucket_count);
+  DCHECK(valid_arguments);
+
+  Histogram* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    BucketRanges* ranges = new BucketRanges(bucket_count + 1);
+    InitializeBucketRanges(minimum, maximum, bucket_count, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    LinearHistogram* tentative_histogram =
+        new LinearHistogram(name, minimum, maximum, bucket_count,
+                            registered_ranges);
+    CheckCorruption(*tentative_histogram, true);
+
+    // Set range descriptions.
+    if (descriptions) {
+      for (int i = 0; descriptions[i].description; ++i) {
+        tentative_histogram->bucket_description_[descriptions[i].sample] =
+            descriptions[i].description;
+      }
+    }
+
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+  // TODO(rtenneti): delete this code after debugging.
+  CheckCorruption(*histogram, false);
+
+  CHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType());
+  CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count));
+  return histogram;
+}
+
+HistogramType LinearHistogram::GetHistogramType() const {
+  return LINEAR_HISTOGRAM;
+}
+
+LinearHistogram::LinearHistogram(const string& name,
+                                 Sample minimum,
+                                 Sample maximum,
+                                 size_t bucket_count,
+                                 const BucketRanges* ranges)
+    : Histogram(name, minimum, maximum, bucket_count, ranges) {
+}
+
+double LinearHistogram::GetBucketSize(Count current, size_t i) const {
+  DCHECK_GT(ranges(i + 1), ranges(i));
+  // Adjacent buckets with different widths would have "surprisingly" many (few)
+  // samples in a histogram if we didn't normalize this way.
+  double denominator = ranges(i + 1) - ranges(i);
+  return current/denominator;
+}
+
+const string LinearHistogram::GetAsciiBucketRange(size_t i) const {
+  int range = ranges(i);
+  BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
+  if (it == bucket_description_.end())
+    return Histogram::GetAsciiBucketRange(i);
+  return it->second;
+}
+
+bool LinearHistogram::PrintEmptyBucket(size_t index) const {
+  return bucket_description_.find(ranges(index)) == bucket_description_.end();
+}
+
+// static
+void LinearHistogram::InitializeBucketRanges(Sample minimum,
+                                             Sample maximum,
+                                             size_t bucket_count,
+                                             BucketRanges* ranges) {
+  DCHECK_EQ(ranges->size(), bucket_count + 1);
+  double min = minimum;
+  double max = maximum;
+  size_t i;
+  for (i = 1; i < bucket_count; ++i) {
+    double linear_range =
+        (min * (bucket_count -1 - i) + max * (i - 1)) / (bucket_count - 2);
+    ranges->set_range(i, static_cast<Sample>(linear_range + 0.5));
+  }
+  ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX);
+  ranges->ResetChecksum();
+}
+
+//------------------------------------------------------------------------------
+// This section provides implementation for BooleanHistogram.
+//------------------------------------------------------------------------------
+
+Histogram* BooleanHistogram::FactoryGet(const string& name, int32 flags) {
+  Histogram* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    BucketRanges* ranges = new BucketRanges(4);
+    LinearHistogram::InitializeBucketRanges(1, 2, 3, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    BooleanHistogram* tentative_histogram =
+        new BooleanHistogram(name, registered_ranges);
+    CheckCorruption(*tentative_histogram, true);
+
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+  // TODO(rtenneti): delete this code after debugging.
+  CheckCorruption(*histogram, false);
+
+  CHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType());
+  return histogram;
+}
+
+HistogramType BooleanHistogram::GetHistogramType() const {
+  return BOOLEAN_HISTOGRAM;
+}
+
+void BooleanHistogram::AddBoolean(bool value) {
+  Add(value ? 1 : 0);
+}
+
+BooleanHistogram::BooleanHistogram(const string& name,
+                                   const BucketRanges* ranges)
+    : LinearHistogram(name, 1, 2, 3, ranges) {}
+
+//------------------------------------------------------------------------------
+// CustomHistogram:
+//------------------------------------------------------------------------------
+
+Histogram* CustomHistogram::FactoryGet(const string& name,
+                                       const vector<Sample>& custom_ranges,
+                                       int32 flags) {
+  CHECK(ValidateCustomRanges(custom_ranges));
+
+  Histogram* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    CustomHistogram* tentative_histogram =
+        new CustomHistogram(name, registered_ranges);
+    CheckCorruption(*tentative_histogram, true);
+
+    tentative_histogram->SetFlags(flags);
+
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+  // TODO(rtenneti): delete this code after debugging.
+  CheckCorruption(*histogram, false);
+
+  CHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM);
+  return histogram;
+}
+
+HistogramType CustomHistogram::GetHistogramType() const {
+  return CUSTOM_HISTOGRAM;
+}
+
+// static
+vector<Sample> CustomHistogram::ArrayToCustomRanges(
+    const Sample* values, size_t num_values) {
+  vector<Sample> all_values;
+  for (size_t i = 0; i < num_values; ++i) {
+    Sample value = values[i];
+    all_values.push_back(value);
+
+    // Ensure that a guard bucket is added. If we end up with duplicate
+    // values, FactoryGet will take care of removing them.
+    all_values.push_back(value + 1);
+  }
+  return all_values;
+}
+
+CustomHistogram::CustomHistogram(const string& name,
+                                 const BucketRanges* ranges)
+    : Histogram(name,
+                ranges->range(1),
+                ranges->range(ranges->size() - 2),
+                ranges->size() - 1,
+                ranges) {}
+
+bool CustomHistogram::SerializeRanges(Pickle* pickle) const {
+  for (size_t i = 0; i < bucket_ranges()->size(); ++i) {
+    if (!pickle->WriteInt(bucket_ranges()->range(i)))
+      return false;
+  }
+  return true;
+}
+
+// static
+bool CustomHistogram::DeserializeRanges(
+    PickleIterator* iter, vector<Sample>* ranges) {
+  for (size_t i = 0; i < ranges->size(); ++i) {
+    if (!iter->ReadInt(&(*ranges)[i]))
+      return false;
+  }
+  return true;
+}
+
+double CustomHistogram::GetBucketSize(Count current, size_t i) const {
+  return 1;
+}
+
+// static
+bool CustomHistogram::ValidateCustomRanges(
+    const vector<Sample>& custom_ranges) {
+  bool has_valid_range = false;
+  for (size_t i = 0; i < custom_ranges.size(); i++) {
+    Sample sample = custom_ranges[i];
+    if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1)
+      return false;
+    if (sample != 0)
+      has_valid_range = true;
+  }
+  return has_valid_range;
+}
+
+// static
+BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges(
+      const vector<Sample>& custom_ranges) {
+  // Remove the duplicates in the custom ranges array.
+  vector<int> ranges = custom_ranges;
+  ranges.push_back(0);  // Ensure we have a zero value.
+  ranges.push_back(HistogramBase::kSampleType_MAX);
+  std::sort(ranges.begin(), ranges.end());
+  ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
+
+  BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
+  for (size_t i = 0; i < ranges.size(); i++) {
+    bucket_ranges->set_range(i, ranges[i]);
+  }
+  bucket_ranges->ResetChecksum();
+  return bucket_ranges;
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
new file mode 100644
index 0000000..24585b7
--- /dev/null
+++ b/base/metrics/histogram.h
@@ -0,0 +1,707 @@
+// Copyright (c) 2012 The Chromium 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 minmal 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. These macros use a
+// pattern involving a function static variable, that is a pointer to a
+// histogram.  This static is explicitly initialized on any thread
+// that detects a uninitialized (NULL) pointer.  The potentially racy
+// initialization is not a problem as it is always set to point to the same
+// value (i.e., the FactoryGet always returns the same value).  FactoryGet
+// is also completely thread safe, which results in a completely thread safe,
+// and relatively fast, set of counters.  To avoid races at shutdown, the static
+// pointer is NOT deleted, and we leak the histograms at process termination.
+
+#ifndef BASE_METRICS_HISTOGRAM_H_
+#define BASE_METRICS_HISTOGRAM_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/time.h"
+
+class Pickle;
+class PickleIterator;
+
+namespace base {
+
+class Lock;
+//------------------------------------------------------------------------------
+// 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
+// initializaion looks like for a histogram (after a macro is expanded).  This
+// sample is an expansion (with comments) of the code for
+// 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 histogrom.
+    base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
+        base::subtle::Acquire_Load(&atomic_histogram_pointer)));
+
+    if (!histogram_pointer) {
+      // This is the slow path, which will construct OR find the matching
+      // histogram.  FactoryGet includes locks on a global histogram name map
+      // and is completely thread safe.
+      histogram_pointer = base::Histogram::FactoryGet(
+          name, min, max, bucket_count, base::HistogramBase::kNoFlags);
+
+      // Use Release_Store to ensure that the histogram data is made available
+      // globally before we make the pointer visible.
+      // Several threads may perform this store, but the same value will be
+      // stored in all cases (for a given named/spec'ed histogram).
+      // We could do this without any barrier, since FactoryGet entered and
+      // exited a lock after construction, but this barrier makes things clear.
+      base::subtle::Release_Store(&atomic_histogram_pointer,
+          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
+    }
+
+    // Ensure calling contract is upheld, and the name does NOT vary.
+    DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);
+
+    histogram_pointer->Add(sample);
+  } while (0);
+*/
+
+// The above pattern is repeated in several macros.  The only elements that
+// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
+// of which FactoryGet method to use.  The different FactoryGet methods have
+// various argument lists, so the function with its argument list is provided as
+// a macro argument here.  The name is only used in a DCHECK, to assure that
+// callers don't try to vary the name of the histogram (which would tend to be
+// ignored by the one-time initialization of the histogtram_pointer).
+#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \
+                                       histogram_add_method_invocation, \
+                                       histogram_factory_get_invocation) \
+  do { \
+    static base::subtle::AtomicWord atomic_histogram_pointer = 0; \
+    base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>( \
+        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)); \
+    } \
+    DCHECK_EQ(histogram_pointer->histogram_name(), \
+              std::string(constant_histogram_name)); \
+    histogram_pointer->histogram_add_method_invocation; \
+  } while (0)
+
+
+//------------------------------------------------------------------------------
+// Provide easy general purpose histogram in a macro, just like stats counters.
+// The first four macros use 50 buckets.
+
+#define HISTOGRAM_TIMES(name, sample) HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromSeconds(10), 50)
+
+#define HISTOGRAM_COUNTS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000000, 50)
+
+#define HISTOGRAM_COUNTS_100(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 100, 50)
+
+#define HISTOGRAM_COUNTS_10000(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 10000, 50)
+
+#define 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))
+
+#define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+    HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+// 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 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))
+
+// 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 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 HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::CustomHistogram::FactoryGet(name, custom_ranges, \
+                                          base::HistogramBase::kNoFlags))
+
+//------------------------------------------------------------------------------
+// Define Debug vs non-debug flavors of macros.
+#ifndef NDEBUG
+
+#define DHISTOGRAM_TIMES(name, sample) HISTOGRAM_TIMES(name, sample)
+#define DHISTOGRAM_COUNTS(name, sample) HISTOGRAM_COUNTS(name, sample)
+#define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) HISTOGRAM_PERCENTAGE(\
+    name, under_one_hundred)
+#define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+    HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count)
+#define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \
+    HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count)
+#define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+    HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count)
+#define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    HISTOGRAM_ENUMERATION(name, sample, boundary_value)
+#define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+    HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges)
+
+#else  // NDEBUG
+// Keep a mention of passed variables to avoid unused variable warnings in
+// release build if these variables are only used in macros.
+#define DISCARD_2_ARGUMENTS(a, b) \
+  while (0) { \
+    static_cast<void>(a); \
+    static_cast<void>(b); \
+ }
+#define DISCARD_3_ARGUMENTS(a, b, c) \
+  while (0) { \
+    static_cast<void>(a); \
+    static_cast<void>(b); \
+    static_cast<void>(c); \
+ }
+#define DISCARD_5_ARGUMENTS(a, b, c, d ,e) \
+  while (0) { \
+    static_cast<void>(a); \
+    static_cast<void>(b); \
+    static_cast<void>(c); \
+    static_cast<void>(d); \
+    static_cast<void>(e); \
+ }
+#define DHISTOGRAM_TIMES(name, sample) \
+    DISCARD_2_ARGUMENTS(name, sample)
+
+#define DHISTOGRAM_COUNTS(name, sample) \
+    DISCARD_2_ARGUMENTS(name, sample)
+
+#define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+    DISCARD_2_ARGUMENTS(name, under_one_hundred)
+
+#define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+    DISCARD_5_ARGUMENTS(name, sample, min, max, bucket_count)
+
+#define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \
+    DISCARD_5_ARGUMENTS(name, sample, min, max, bucket_count)
+
+#define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+    DISCARD_5_ARGUMENTS(name, sample, min, max, bucket_count)
+
+#define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    DISCARD_3_ARGUMENTS(name, sample, boundary_value)
+
+#define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+    DISCARD_3_ARGUMENTS(name, sample, custom_ranges)
+
+#endif  // NDEBUG
+
+//------------------------------------------------------------------------------
+// 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)
+
+#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::Histogram::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000000, 50)
+
+#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 100, 50)
+
+#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 10000, 50)
+
+#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::Histogram::FactoryGet(name, min, max, bucket_count, \
+            base::Histogram::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1000, 500000, 50)
+
+#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000, 50)
+
+#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+    UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+        base::BooleanHistogram::FactoryGet(name, \
+            base::Histogram::kUmaTargetedHistogramFlag))
+
+// The samples should always be strictly less than |boundary_value|.  For more
+// details, see the comment for the |HISTOGRAM_ENUMERATION| macro, above.
+#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
+            boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::CustomHistogram::FactoryGet(name, custom_ranges, \
+            base::Histogram::kUmaTargetedHistogramFlag))
+
+//------------------------------------------------------------------------------
+
+class BucketRanges;
+class SampleVector;
+
+class BooleanHistogram;
+class CustomHistogram;
+class Histogram;
+class LinearHistogram;
+
+class BASE_EXPORT Histogram : public HistogramBase {
+ public:
+  // Initialize maximum number of buckets in histograms as 16,384.
+  static const size_t kBucketCount_MAX;
+
+  typedef std::vector<Count> Counts;
+
+  enum Inconsistencies {
+    NO_INCONSISTENCIES = 0x0,
+    RANGE_CHECKSUM_ERROR = 0x1,
+    BUCKET_ORDER_ERROR = 0x2,
+    COUNT_HIGH_ERROR = 0x4,
+    COUNT_LOW_ERROR = 0x8,
+
+    NEVER_EXCEEDED_VALUE = 0x10
+  };
+
+  struct DescriptionPair {
+    Sample sample;
+    const char* description;  // Null means end of a list of pairs.
+  };
+
+  //----------------------------------------------------------------------------
+  // 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 Histogram* FactoryGet(const std::string& name,
+                               Sample minimum,
+                               Sample maximum,
+                               size_t bucket_count,
+                               int32 flags);
+  static Histogram* FactoryTimeGet(const std::string& name,
+                                   base::TimeDelta minimum,
+                                   base::TimeDelta maximum,
+                                   size_t bucket_count,
+                                   int32 flags);
+
+  // Time call for use with DHISTOGRAM*.
+  // Returns TimeTicks::Now() in debug and TimeTicks() in release build.
+  static TimeTicks DebugNow();
+
+  static void InitializeBucketRanges(Sample minimum,
+                                     Sample maximum,
+                                     size_t bucket_count,
+                                     BucketRanges* ranges);
+
+  // This method is an interface, used only by BooleanHistogram.
+  virtual void AddBoolean(bool value);
+
+  // Accept a TimeDelta to increment.
+  void AddTime(TimeDelta time) {
+    Add(static_cast<int>(time.InMilliseconds()));
+  }
+
+  void AddSamples(const HistogramSamples& samples);
+  bool AddSamplesFromPickle(PickleIterator* iter);
+
+  // Convenience methods for serializing/deserializing the histograms.
+  // Histograms from Renderer process are serialized and sent to the browser.
+  // Browser process reconstructs the histogram from the pickled version
+  // accumulates the browser-side shadow copy of histograms (that mirror
+  // histograms created in the renderer).
+
+  // Serialize the given snapshot of a Histogram into a String. Uses
+  // Pickle class to flatten the object.
+  static std::string SerializeHistogramInfo(const Histogram& histogram,
+                                            const HistogramSamples& snapshot);
+
+  // The following method accepts a list of pickled histograms and
+  // builds a histogram and updates shadow copy of histogram data in the
+  // browser process.
+  static bool DeserializeHistogramInfo(const std::string& histogram_info);
+
+  // 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).
+  virtual Inconsistencies FindCorruption(const HistogramSamples& samples) const;
+
+  //----------------------------------------------------------------------------
+  // Accessors for factory constuction, serialization and testing.
+  //----------------------------------------------------------------------------
+  Sample declared_min() const { return declared_min_; }
+  Sample declared_max() const { return declared_max_; }
+  virtual Sample ranges(size_t i) const;
+  virtual size_t bucket_count() const;
+  const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
+
+  // This function validates histogram construction arguments. It returns false
+  // if some of the arguments are totally bad.
+  // Note. Currently it allow some bad input, e.g. 0 as minimum, but silently
+  // converts it to good input: 1.
+  // TODO(kaiwang): Be more restrict and return false for any bad input, and
+  // make this a readonly validating function.
+  static bool InspectConstructionArguments(const std::string& name,
+                                           Sample* minimum,
+                                           Sample* maximum,
+                                           size_t* bucket_count);
+
+  // HistogramBase implementation:
+  virtual HistogramType GetHistogramType() const OVERRIDE;
+  virtual bool HasConstructionArguments(Sample minimum,
+                                        Sample maximum,
+                                        size_t bucket_count) const OVERRIDE;
+  virtual void Add(Sample value) OVERRIDE;
+  virtual scoped_ptr<HistogramSamples> SnapshotSamples() const OVERRIDE;
+  virtual void WriteHTMLGraph(std::string* output) const OVERRIDE;
+  virtual void WriteAscii(std::string* output) const OVERRIDE;
+
+ protected:
+  // |bucket_count| and |ranges| should contain the underflow and overflow
+  // buckets. See top comments for example.
+  Histogram(const std::string& name,
+            Sample minimum,
+            Sample maximum,
+            size_t bucket_count,
+            const BucketRanges* ranges);
+
+  virtual ~Histogram();
+
+  // Serialize the histogram's ranges to |*pickle|, returning true on success.
+  // Most subclasses can leave this no-op implementation, but some will want to
+  // override it, especially if the ranges cannot be re-derived from other
+  // serialized parameters.
+  virtual bool SerializeRanges(Pickle* pickle) const;
+
+  // Method to override to skip the display of the i'th bucket if it's empty.
+  virtual bool PrintEmptyBucket(size_t index) const;
+
+  // Get normalized size, relative to the ranges(i).
+  virtual double GetBucketSize(Count current, size_t i) const;
+
+  // Return a string description of what goes in a given bucket.
+  // Most commonly this is the numeric value, but in derived classes it may
+  // be a name (or string description) given to the bucket.
+  virtual const std::string GetAsciiBucketRange(size_t it) const;
+
+ private:
+  // Allow tests to corrupt our innards for testing purposes.
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, BoundsTest);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, BucketPlacementTest);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptBucketBounds);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, NameMatchTest);
+
+  friend class StatisticsRecorder;  // To allow it to delete duplicates.
+  friend class StatisticsRecorderTest;
+
+  // Implementation of SnapshotSamples function.
+  scoped_ptr<SampleVector> SnapshotSampleVector() const;
+
+  //----------------------------------------------------------------------------
+  // Helpers for emitting Ascii graphic.  Each method appends data to output.
+
+  void WriteAsciiImpl(bool graph_it,
+                      const std::string& newline,
+                      std::string* output) const;
+
+  // Find out how large (graphically) the largest bucket will appear to be.
+  double GetPeakBucketSize(const SampleVector& samples) const;
+
+  // Write a common header message describing this histogram.
+  void WriteAsciiHeader(const SampleVector& samples,
+                        Count sample_count,
+                        std::string* output) const;
+
+  // Write information about previous, current, and next buckets.
+  // Information such as cumulative percentage, etc.
+  void WriteAsciiBucketContext(const int64 past, const Count current,
+                               const int64 remaining, const size_t i,
+                               std::string* output) const;
+
+  // 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;
+
+  // 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;
+
+  // WriteJSON calls these.
+  virtual void GetParameters(DictionaryValue* params) const OVERRIDE;
+
+  virtual void GetCountAndBucketData(Count* count,
+                                     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 counts_[0]
+  Sample declared_max_;  // Over this goes into counts_[bucket_count_ - 1].
+  size_t bucket_count_;  // Dimension of counts_[].
+
+  // Finally, provide the state that changes with the addition of each new
+  // sample.
+  scoped_ptr<SampleVector> samples_;
+
+  DISALLOW_COPY_AND_ASSIGN(Histogram);
+};
+
+//------------------------------------------------------------------------------
+
+// LinearHistogram is a more traditional histogram, with evenly spaced
+// buckets.
+class BASE_EXPORT LinearHistogram : public Histogram {
+ public:
+  virtual ~LinearHistogram();
+
+  /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
+     default underflow bucket. */
+  static Histogram* FactoryGet(const std::string& name,
+                               Sample minimum,
+                               Sample maximum,
+                               size_t bucket_count,
+                               int32 flags);
+  static Histogram* FactoryTimeGet(const std::string& name,
+                                   TimeDelta minimum,
+                                   TimeDelta maximum,
+                                   size_t bucket_count,
+                                   int32 flags);
+
+  // 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 Histogram* FactoryGetWithRangeDescription(
+      const std::string& name,
+      Sample minimum,
+      Sample maximum,
+      size_t bucket_count,
+      int32 flags,
+      const DescriptionPair descriptions[]);
+
+  static void InitializeBucketRanges(Sample minimum,
+                                     Sample maximum,
+                                     size_t bucket_count,
+                                     BucketRanges* ranges);
+
+  // Overridden from Histogram:
+  virtual HistogramType GetHistogramType() const OVERRIDE;
+
+ protected:
+  LinearHistogram(const std::string& name,
+                  Sample minimum,
+                  Sample maximum,
+                  size_t bucket_count,
+                  const BucketRanges* ranges);
+
+  virtual double GetBucketSize(Count current, size_t i) const OVERRIDE;
+
+  // If we have a description for a bucket, then return that.  Otherwise
+  // let parent class provide a (numeric) description.
+  virtual const std::string GetAsciiBucketRange(size_t i) const OVERRIDE;
+
+  // Skip printing of name for numeric range if we have a name (and if this is
+  // an empty bucket).
+  virtual bool PrintEmptyBucket(size_t index) const OVERRIDE;
+
+ private:
+  // For some ranges, we store a printable description of a bucket range.
+  // If there is no desciption, 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 Histogram* FactoryGet(const std::string& name, int32 flags);
+
+  virtual HistogramType GetHistogramType() const OVERRIDE;
+
+  virtual void AddBoolean(bool value) OVERRIDE;
+
+ private:
+  BooleanHistogram(const std::string& name, const BucketRanges* ranges);
+
+  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 Histogram* FactoryGet(const std::string& name,
+                               const std::vector<Sample>& custom_ranges,
+                               int32 flags);
+
+  // Overridden from Histogram:
+  virtual HistogramType GetHistogramType() const OVERRIDE;
+
+  // Helper method for transforming an array of valid enumeration values
+  // to the std::vector<int> expected by HISTOGRAM_CUSTOM_ENUMERATION.
+  // This function ensures that a guard bucket exists right after any
+  // valid sample value (unless the next higher sample is also a valid value),
+  // so that invalid samples never fall into the same bucket as valid samples.
+  // TODO(kaiwang): Change name to ArrayToCustomEnumRanges.
+  static std::vector<Sample> ArrayToCustomRanges(const Sample* values,
+                                                 size_t num_values);
+
+  // Helper for deserializing CustomHistograms.  |*ranges| should already be
+  // correctly sized before this call.  Return true on success.
+  static bool DeserializeRanges(PickleIterator* iter,
+                                std::vector<Sample>* ranges);
+ protected:
+  CustomHistogram(const std::string& name,
+                  const BucketRanges* ranges);
+
+  virtual bool SerializeRanges(Pickle* pickle) const OVERRIDE;
+
+  virtual double GetBucketSize(Count current, size_t i) const OVERRIDE;
+
+ private:
+  static bool ValidateCustomRanges(const std::vector<Sample>& custom_ranges);
+  static BucketRanges* CreateBucketRangesFromCustomRanges(
+      const std::vector<Sample>& custom_ranges);
+
+  DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_H_
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc
new file mode 100644
index 0000000..bcfb57f
--- /dev/null
+++ b/base/metrics/histogram_base.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/metrics/histogram_base.h"
+
+#include <climits>
+
+#include "base/logging.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+namespace base {
+
+std::string HistogramTypeToString(HistogramType type) {
+  switch(type) {
+    case HISTOGRAM:
+      return "HISTOGRAM";
+    case LINEAR_HISTOGRAM:
+      return "LINEAR_HISTOGRAM";
+    case BOOLEAN_HISTOGRAM:
+      return "BOOLEAN_HISTOGRAM";
+    case CUSTOM_HISTOGRAM:
+      return "CUSTOM_HISTOGRAM";
+    case SPARSE_HISTOGRAM:
+      return "SPARSE_HISTOGRAM";
+    default:
+      NOTREACHED();
+  }
+  return "UNKNOWN";
+}
+
+const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX;
+
+HistogramBase::HistogramBase(const std::string& name)
+    : histogram_name_(name),
+      flags_(kNoFlags) {}
+
+HistogramBase::~HistogramBase() {}
+
+void HistogramBase::SetFlags(int32 flags) {
+  flags_ |= flags;
+}
+
+void HistogramBase::ClearFlags(int32 flags) {
+  flags_ &= ~flags;
+}
+
+void HistogramBase::WriteJSON(std::string* output) const {
+  Count count;
+  scoped_ptr<ListValue> buckets(new ListValue());
+  GetCountAndBucketData(&count, buckets.get());
+  scoped_ptr<DictionaryValue> parameters(new DictionaryValue());
+  GetParameters(parameters.get());
+
+  JSONStringValueSerializer serializer(output);
+  DictionaryValue root;
+  root.SetString("name", histogram_name());
+  root.SetInteger("count", count);
+  root.SetInteger("flags", flags());
+  root.Set("params", parameters.release());
+  root.Set("buckets", buckets.release());
+  serializer.Serialize(root);
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h
new file mode 100644
index 0000000..302795a
--- /dev/null
+++ b/base/metrics/histogram_base.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_METRICS_HISTOGRAM_BASE_H_
+#define BASE_METRICS_HISTOGRAM_BASE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+
+class DictionaryValue;
+class HistogramSamples;
+class ListValue;
+
+////////////////////////////////////////////////////////////////////////////////
+// These enums are used to facilitate deserialization of histograms from other
+// processes into the browser. If you create another class that inherits from
+// HistogramBase, add new histogram types and names below.
+
+enum BASE_EXPORT HistogramType {
+  HISTOGRAM,
+  LINEAR_HISTOGRAM,
+  BOOLEAN_HISTOGRAM,
+  CUSTOM_HISTOGRAM,
+  SPARSE_HISTOGRAM,
+};
+
+std::string HistogramTypeToString(HistogramType type);
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BASE_EXPORT HistogramBase {
+ public:
+  typedef int Sample;  // Used for samples.
+  typedef int Count;   // Used to count samples.
+
+  static const Sample kSampleType_MAX;  // INT_MAX
+
+  enum Flags {
+    kNoFlags = 0,
+    kUmaTargetedHistogramFlag = 0x1,  // Histogram should be UMA uploaded.
+
+    // Indicate that the histogram was pickled to be sent across an IPC Channel.
+    // If we observe this flag on a histogram being aggregated into after IPC,
+    // then we are running in a single process mode, and the aggregation should
+    // not take place (as we would be aggregating back into the source
+    // histogram!).
+    kIPCSerializationSourceFlag = 0x10,
+
+    // Only for Histogram and its sub classes: fancy bucket-naming support.
+    kHexRangePrintingFlag = 0x8000,
+  };
+
+  HistogramBase(const std::string& name);
+  virtual ~HistogramBase();
+
+  std::string histogram_name() const { return histogram_name_; }
+
+  // Operations with Flags enum.
+  int32 flags() const { return flags_; }
+  void SetFlags(int32 flags);
+  void ClearFlags(int32 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 minimum,
+                                        Sample maximum,
+                                        size_t bucket_count) const = 0;
+
+  virtual void Add(Sample value) = 0;
+
+  // Snapshot the current complete set of sample data.
+  // Override with atomic/locked snapshot if needed.
+  virtual scoped_ptr<HistogramSamples> SnapshotSamples() const = 0;
+
+  // The following methods provide graphical histogram displays.
+  virtual void WriteHTMLGraph(std::string* output) const = 0;
+  virtual void WriteAscii(std::string* output) const = 0;
+
+  // Produce a JSON representation of the histogram. This is implemented with
+  // the help of GetParameters and GetCountAndBucketData; overwrite them to
+  // customize the output.
+  void WriteJSON(std::string* output) const;
+
+protected:
+  // 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| and the total sample count to |count|.
+  virtual void GetCountAndBucketData(Count* count,
+                                     ListValue* buckets) const = 0;
+ private:
+  const std::string histogram_name_;
+  int32 flags_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramBase);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_BASE_H_
diff --git a/base/metrics/histogram_flattener.h b/base/metrics/histogram_flattener.h
new file mode 100644
index 0000000..6dd169e
--- /dev/null
+++ b/base/metrics/histogram_flattener.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_METRICS_HISTOGRAM_FLATTENER_H_
+#define BASE_METRICS_HISTOGRAM_FLATTENER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.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 Histogram& histogram,
+                           const HistogramSamples& snapshot) = 0;
+
+  // Will be called each time a type of Inconsistenies is seen on a histogram,
+  // during inspections done internally in HistogramSnapshotManager class.
+  virtual void InconsistencyDetected(Histogram::Inconsistencies problem) = 0;
+
+  // Will be called when a type of Inconsistenies is seen for the first time
+  // on a histogram.
+  virtual void UniqueInconsistencyDetected(
+      Histogram::Inconsistencies problem) = 0;
+
+  // Will be called when the total logged sample count of a histogram
+  // differs from the sum of logged sample count in all the buckets.  The
+  // argument |amount| is the non-zero discrepancy.
+  virtual void InconsistencyDetectedInLoggedCount(int amount) = 0;
+
+ protected:
+  HistogramFlattener() {}
+  virtual ~HistogramFlattener() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HistogramFlattener);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_FLATTENER_H_
diff --git a/base/metrics/histogram_samples.cc b/base/metrics/histogram_samples.cc
new file mode 100644
index 0000000..e375952
--- /dev/null
+++ b/base/metrics/histogram_samples.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 "base/metrics/histogram_samples.h"
+
+#include "base/compiler_specific.h"
+#include "base/pickle.h"
+
+namespace base {
+
+namespace {
+
+class SampleCountPickleIterator : public SampleCountIterator {
+ public:
+  SampleCountPickleIterator(PickleIterator* iter);
+
+  virtual bool Done() const OVERRIDE;
+  virtual void Next() OVERRIDE;
+  virtual void Get(HistogramBase::Sample* min,
+                   HistogramBase::Sample* max,
+                   HistogramBase::Count* count) const OVERRIDE;
+ private:
+  PickleIterator* const iter_;
+
+  HistogramBase::Sample min_;
+  HistogramBase::Sample max_;
+  HistogramBase::Count count_;
+  bool is_done_;
+};
+
+SampleCountPickleIterator::SampleCountPickleIterator(PickleIterator* iter)
+    : iter_(iter),
+      is_done_(false) {
+  Next();
+}
+
+bool SampleCountPickleIterator::Done() const {
+  return is_done_;
+}
+
+void SampleCountPickleIterator::Next() {
+  DCHECK(!Done());
+  if (!iter_->ReadInt(&min_) ||
+      !iter_->ReadInt(&max_) ||
+      !iter_->ReadInt(&count_))
+    is_done_ = true;
+}
+
+void SampleCountPickleIterator::Get(HistogramBase::Sample* min,
+                                    HistogramBase::Sample* max,
+                                    HistogramBase::Count* count) const {
+  DCHECK(!Done());
+  *min = min_;
+  *max = max_;
+  *count = count_;
+}
+
+}  // namespace
+
+HistogramSamples::HistogramSamples() : sum_(0), redundant_count_(0) {}
+
+HistogramSamples::~HistogramSamples() {}
+
+void HistogramSamples::Add(const HistogramSamples& other) {
+  sum_ += other.sum();
+  redundant_count_ += other.redundant_count();
+  bool success = AddSubtractImpl(other.Iterator().get(), ADD);
+  DCHECK(success);
+}
+
+bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
+  int64 sum;
+  HistogramBase::Count redundant_count;
+
+  if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count))
+    return false;
+  sum_ += sum;
+  redundant_count_ += redundant_count;
+
+  SampleCountPickleIterator pickle_iter(iter);
+  return AddSubtractImpl(&pickle_iter, ADD);
+}
+
+void HistogramSamples::Subtract(const HistogramSamples& other) {
+  sum_ -= other.sum();
+  redundant_count_ -= other.redundant_count();
+  bool success = AddSubtractImpl(other.Iterator().get(), SUBTRACT);
+  DCHECK(success);
+}
+
+bool HistogramSamples::Serialize(Pickle* pickle) const {
+  if (!pickle->WriteInt64(sum_) || !pickle->WriteInt(redundant_count_))
+    return false;
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  for (scoped_ptr<SampleCountIterator> it = Iterator();
+       !it->Done();
+       it->Next()) {
+    it->Get(&min, &max, &count);
+    if (!pickle->WriteInt(min) ||
+        !pickle->WriteInt(max) ||
+        !pickle->WriteInt(count))
+      return false;
+  }
+  return true;
+}
+
+void HistogramSamples::IncreaseSum(int64 diff) {
+  sum_ += diff;
+}
+
+void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) {
+  redundant_count_ += diff;
+}
+
+SampleCountIterator::~SampleCountIterator() {}
+
+bool SampleCountIterator::GetBucketIndex(size_t* index) const {
+  DCHECK(!Done());
+  return false;
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h
new file mode 100644
index 0000000..c55b584
--- /dev/null
+++ b/base/metrics/histogram_samples.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_METRICS_HISTOGRAM_SAMPLES_H_
+#define BASE_METRICS_HISTOGRAM_SAMPLES_H_
+
+#include "base/basictypes.h"
+#include "base/metrics/histogram_base.h"
+#include "base/memory/scoped_ptr.h"
+
+class Pickle;
+class PickleIterator;
+
+namespace base {
+
+class SampleCountIterator;
+
+// HistogramSamples is a container storing all samples of a histogram.
+class BASE_EXPORT HistogramSamples {
+ public:
+  HistogramSamples();
+  virtual ~HistogramSamples();
+
+  virtual void Accumulate(HistogramBase::Sample value,
+                          HistogramBase::Count count) = 0;
+  virtual HistogramBase::Count GetCount(HistogramBase::Sample value) const = 0;
+  virtual HistogramBase::Count TotalCount() const = 0;
+
+  virtual void Add(const HistogramSamples& other);
+
+  // Add from serialized samples.
+  virtual bool AddFromPickle(PickleIterator* iter);
+
+  virtual void Subtract(const HistogramSamples& other);
+
+  virtual scoped_ptr<SampleCountIterator> Iterator() const = 0;
+  virtual bool Serialize(Pickle* pickle) const;
+
+  // Accessor fuctions.
+  int64 sum() const { return sum_; }
+  HistogramBase::Count redundant_count() const { return redundant_count_; }
+
+ protected:
+  // Based on |op| type, add or subtract sample counts data from the iterator.
+  enum Operator { ADD, SUBTRACT };
+  virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0;
+
+  void IncreaseSum(int64 diff);
+  void IncreaseRedundantCount(HistogramBase::Count diff);
+
+ private:
+  int64 sum_;
+
+  // |redundant_count_| helps identify memory corruption. It redundantly stores
+  // the total number of samples accumulated in the histogram. We can compare
+  // this count to the sum of the counts (TotalCount() function), and detect
+  // problems. Note, depending on the implementation of different histogram
+  // types, there might be races during histogram accumulation and snapshotting
+  // that we choose to accept. In this case, the tallies might mismatch even
+  // when no memory corruption has happened.
+  HistogramBase::Count redundant_count_;
+};
+
+class BASE_EXPORT SampleCountIterator {
+ public:
+  virtual ~SampleCountIterator();
+
+  virtual bool Done() const = 0;
+  virtual void Next() = 0;
+
+  // Get the sample and count at current position.
+  // |min| |max| and |count| can be NULL if the value is not of interest.
+  // Requires: !Done();
+  virtual void Get(HistogramBase::Sample* min,
+                   HistogramBase::Sample* max,
+                   HistogramBase::Count* count) const = 0;
+
+  // Get the index of current histogram bucket.
+  // For histograms that don't use predefined buckets, it returns false.
+  // Requires: !Done();
+  virtual bool GetBucketIndex(size_t* index) const;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_SAMPLES_H_
diff --git a/base/metrics/histogram_snapshot_manager.cc b/base/metrics/histogram_snapshot_manager.cc
new file mode 100644
index 0000000..ad054b1
--- /dev/null
+++ b/base/metrics/histogram_snapshot_manager.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/metrics/histogram_snapshot_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_flattener.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/stl_util.h"
+
+using std::map;
+using std::string;
+
+namespace base {
+
+HistogramSnapshotManager::HistogramSnapshotManager(
+    HistogramFlattener* histogram_flattener)
+    : histogram_flattener_(histogram_flattener) {
+  DCHECK(histogram_flattener_);
+}
+
+HistogramSnapshotManager::~HistogramSnapshotManager() {
+  STLDeleteValues(&logged_samples_);
+}
+
+void HistogramSnapshotManager::PrepareDeltas(Histogram::Flags flag_to_set,
+                                             bool record_only_uma) {
+  StatisticsRecorder::Histograms histograms;
+  StatisticsRecorder::GetHistograms(&histograms);
+  for (StatisticsRecorder::Histograms::const_iterator it = histograms.begin();
+       histograms.end() != it;
+       ++it) {
+    (*it)->SetFlags(flag_to_set);
+    if (record_only_uma &&
+        0 == ((*it)->flags() & Histogram::kUmaTargetedHistogramFlag))
+      continue;
+    PrepareDelta(**it);
+  }
+}
+
+void HistogramSnapshotManager::PrepareDelta(const Histogram& histogram) {
+  DCHECK(histogram_flattener_);
+
+  // Get up-to-date snapshot of sample stats.
+  scoped_ptr<HistogramSamples> snapshot(histogram.SnapshotSamples());
+  const std::string& histogram_name = histogram.histogram_name();
+
+  int corruption = histogram.FindCorruption(*snapshot);
+
+  // Crash if we detect that our histograms have been overwritten.  This may be
+  // a fair distance from the memory smasher, but we hope to correlate these
+  // crashes with other events, such as plugins, or usage patterns, etc.
+  if (Histogram::BUCKET_ORDER_ERROR & corruption) {
+    // The checksum should have caught this, so crash separately if it didn't.
+    CHECK_NE(0, Histogram::RANGE_CHECKSUM_ERROR & corruption);
+    CHECK(false);  // Crash for the bucket order corruption.
+  }
+  // Checksum corruption might not have caused order corruption.
+  CHECK_EQ(0, Histogram::RANGE_CHECKSUM_ERROR & corruption);
+
+  // Note, at this point corruption can only be COUNT_HIGH_ERROR or
+  // COUNT_LOW_ERROR and they never arise together, so we don't need to extract
+  // bits from corruption.
+  if (corruption) {
+    DLOG(ERROR) << "Histogram: " << histogram_name
+                << " has data corruption: " << corruption;
+    histogram_flattener_->InconsistencyDetected(
+        static_cast<Histogram::Inconsistencies>(corruption));
+    // Don't record corrupt data to metrics services.
+    int old_corruption = inconsistencies_[histogram_name];
+    if (old_corruption == (corruption | old_corruption))
+      return;  // We've already seen this corruption for this histogram.
+    inconsistencies_[histogram_name] |= corruption;
+    histogram_flattener_->UniqueInconsistencyDetected(
+        static_cast<Histogram::Inconsistencies>(corruption));
+    return;
+  }
+
+  HistogramSamples* to_log;
+  map<string, HistogramSamples*>::iterator it =
+      logged_samples_.find(histogram_name);
+  if (it == logged_samples_.end()) {
+    to_log = snapshot.release();
+
+    // This histogram has not been logged before, add a new entry.
+    logged_samples_[histogram_name] = to_log;
+  } else {
+    HistogramSamples* already_logged = it->second;
+    InspectLoggedSamplesInconsistency(*snapshot, already_logged);
+    snapshot->Subtract(*already_logged);
+    already_logged->Add(*snapshot);
+    to_log = snapshot.get();
+  }
+
+  if (to_log->redundant_count() > 0)
+    histogram_flattener_->RecordDelta(histogram, *to_log);
+}
+
+void HistogramSnapshotManager::InspectLoggedSamplesInconsistency(
+      const HistogramSamples& new_snapshot,
+      HistogramSamples* logged_samples) {
+  HistogramBase::Count discrepancy =
+      logged_samples->TotalCount() - logged_samples->redundant_count();
+  if (!discrepancy)
+    return;
+
+  histogram_flattener_->InconsistencyDetectedInLoggedCount(discrepancy);
+  if (discrepancy > Histogram::kCommonRaceBasedCountMismatch) {
+    // Fix logged_samples.
+    logged_samples->Subtract(*logged_samples);
+    logged_samples->Add(new_snapshot);
+  }
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_snapshot_manager.h b/base/metrics/histogram_snapshot_manager.h
new file mode 100644
index 0000000..0ec1ac3
--- /dev/null
+++ b/base/metrics/histogram_snapshot_manager.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
+#define BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/metrics/histogram.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. The arguments allow selecting only a subset of histograms for
+  // recording, or to set a flag in each recorded histogram.
+  void PrepareDeltas(Histogram::Flags flags_to_set, bool record_only_uma);
+
+ private:
+  // Snapshot this histogram, and record the delta.
+  void PrepareDelta(const Histogram& histogram);
+
+  // Try to detect and fix count inconsistency of logged samples.
+  void InspectLoggedSamplesInconsistency(
+      const HistogramSamples& new_snapshot,
+      HistogramSamples* logged_samples);
+
+  // For histograms, track what we've already recorded (as a sample for
+  // each histogram) so that we can record only the delta with the next log.
+  std::map<std::string, HistogramSamples*> logged_samples_;
+
+  // List of histograms found to be corrupt, and their problems.
+  std::map<std::string, int> inconsistencies_;
+
+  // |histogram_flattener_| handles the logistics of recording the histogram
+  // deltas.
+  HistogramFlattener* histogram_flattener_;  // Weak.
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramSnapshotManager);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
new file mode 100644
index 0000000..9fb9422
--- /dev/null
+++ b/base/metrics/histogram_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.
+
+// Test of Histogram class
+
+#include <climits>
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/sample_vector.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::vector;
+
+namespace base {
+
+class HistogramTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+  }
+
+  virtual void TearDown() {
+    UninitializeStatisticsRecorder();
+  }
+
+  void InitializeStatisticsRecorder() {
+    statistics_recorder_ = new StatisticsRecorder();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    delete statistics_recorder_;
+    statistics_recorder_ = NULL;
+  }
+
+  StatisticsRecorder* statistics_recorder_;
+};
+
+// Check for basic syntax and use.
+TEST_F(HistogramTest, BasicTest) {
+  // Try basic construction
+  Histogram* histogram(Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram);
+
+  Histogram* linear_histogram(LinearHistogram::FactoryGet(
+      "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram);
+
+  vector<int> custom_ranges;
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(5);
+  Histogram* custom_histogram(CustomHistogram::FactoryGet(
+      "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram);
+
+  // Use standard macros (but with fixed samples)
+  HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
+  HISTOGRAM_COUNTS("Test3Histogram", 30);
+
+  DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1));
+  DHISTOGRAM_COUNTS("Test5Histogram", 30);
+
+  HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
+}
+
+// Check that the macro correctly matches histograms by name and records their
+// data together.
+TEST_F(HistogramTest, NameMatchTest) {
+  HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
+  HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
+  Histogram* histogram(LinearHistogram::FactoryGet(
+      "DuplicatedHistogram", 1, 101, 102, Histogram::kNoFlags));
+  scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
+  EXPECT_EQ(2, samples->TotalCount());
+  EXPECT_EQ(2, samples->GetCountAtIndex(10));
+}
+
+TEST_F(HistogramTest, ExponentialRangesTest) {
+  // Check that we got a nice exponential when there was enough rooom.
+  BucketRanges ranges(9);
+  Histogram::InitializeBucketRanges(1, 64, 8, &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(Histogram::FactoryGet(
+      "Histogram", 1, 64, 8, Histogram::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, 15, &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(Histogram::FactoryGet(
+      "Histogram2", 1, 32, 15, Histogram::kNoFlags));
+  EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
+}
+
+TEST_F(HistogramTest, LinearRangesTest) {
+  BucketRanges ranges(9);
+  LinearHistogram::InitializeBucketRanges(1, 7, 8, &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(
+      LinearHistogram::FactoryGet("Linear", 1, 7, 8, Histogram::kNoFlags));
+  EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
+
+  // Linear ranges are not divisible.
+  BucketRanges ranges2(6);
+  LinearHistogram::InitializeBucketRanges(1, 6, 5, &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(
+      LinearHistogram::FactoryGet("Linear2", 1, 6, 5, Histogram::kNoFlags));
+  EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
+}
+
+TEST_F(HistogramTest, ArrayToCustomRangesTest) {
+  const HistogramBase::Sample ranges[3] = {5, 10, 20};
+  vector<HistogramBase::Sample> ranges_vec =
+      CustomHistogram::ArrayToCustomRanges(ranges, 3);
+  ASSERT_EQ(6u, ranges_vec.size());
+  EXPECT_EQ(5, ranges_vec[0]);
+  EXPECT_EQ(6, ranges_vec[1]);
+  EXPECT_EQ(10, ranges_vec[2]);
+  EXPECT_EQ(11, ranges_vec[3]);
+  EXPECT_EQ(20, ranges_vec[4]);
+  EXPECT_EQ(21, ranges_vec[5]);
+}
+
+TEST_F(HistogramTest, CustomHistogramTest) {
+  // A well prepared custom ranges.
+  vector<HistogramBase::Sample> custom_ranges;
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(2);
+  Histogram* histogram = CustomHistogram::FactoryGet(
+      "TestCustomHistogram1", custom_ranges, Histogram::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 = CustomHistogram::FactoryGet(
+      "TestCustomHistogram2", custom_ranges, Histogram::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 = CustomHistogram::FactoryGet(
+      "TestCustomHistogram3", custom_ranges, Histogram::kNoFlags);
+  ranges = histogram->bucket_ranges();
+  ASSERT_EQ(4u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));
+  EXPECT_EQ(1, ranges->range(1));
+  EXPECT_EQ(4, ranges->range(2));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));
+}
+
+TEST_F(HistogramTest, CustomHistogramWithOnly2Buckets) {
+  // This test exploits the fact that the CustomHistogram can have 2 buckets,
+  // while the base class Histogram is *supposed* to have at least 3 buckets.
+  // We should probably change the restriction on the base class (or not inherit
+  // the base class!).
+
+  vector<HistogramBase::Sample> custom_ranges;
+  custom_ranges.push_back(4);
+
+  Histogram* histogram = CustomHistogram::FactoryGet(
+      "2BucketsCustomHistogram", custom_ranges, Histogram::kNoFlags);
+  const BucketRanges* ranges = histogram->bucket_ranges();
+  ASSERT_EQ(3u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));
+  EXPECT_EQ(4, ranges->range(1));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
+}
+
+// Make sure histogram handles out-of-bounds data gracefully.
+TEST_F(HistogramTest, BoundsTest) {
+  const size_t kBucketCount = 50;
+  Histogram* histogram(Histogram::FactoryGet(
+      "Bounded", 10, 100, kBucketCount, Histogram::kNoFlags));
+
+  // Put two samples "out of bounds" above and below.
+  histogram->Add(5);
+  histogram->Add(-50);
+
+  histogram->Add(100);
+  histogram->Add(10000);
+
+  // Verify they landed in the underflow, and overflow buckets.
+  scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
+  EXPECT_EQ(2, samples->GetCountAtIndex(0));
+  EXPECT_EQ(0, samples->GetCountAtIndex(1));
+  size_t array_size = histogram->bucket_count();
+  EXPECT_EQ(kBucketCount, array_size);
+  EXPECT_EQ(0, samples->GetCountAtIndex(array_size - 2));
+  EXPECT_EQ(2, samples->GetCountAtIndex(array_size - 1));
+
+  vector<int> custom_ranges;
+  custom_ranges.push_back(10);
+  custom_ranges.push_back(50);
+  custom_ranges.push_back(100);
+  Histogram* test_custom_histogram(CustomHistogram::FactoryGet(
+      "TestCustomRangeBoundedHistogram", custom_ranges, Histogram::kNoFlags));
+
+  // Put two samples "out of bounds" above and below.
+  test_custom_histogram->Add(5);
+  test_custom_histogram->Add(-50);
+  test_custom_histogram->Add(100);
+  test_custom_histogram->Add(1000);
+  test_custom_histogram->Add(INT_MAX);
+
+  // Verify they landed in the underflow, and overflow buckets.
+  scoped_ptr<SampleVector> custom_samples =
+      test_custom_histogram->SnapshotSampleVector();
+  EXPECT_EQ(2, custom_samples->GetCountAtIndex(0));
+  EXPECT_EQ(0, custom_samples->GetCountAtIndex(1));
+  size_t bucket_count = test_custom_histogram->bucket_count();
+  EXPECT_EQ(0, custom_samples->GetCountAtIndex(bucket_count - 2));
+  EXPECT_EQ(3, custom_samples->GetCountAtIndex(bucket_count - 1));
+}
+
+// Check to be sure samples land as expected is "correct" buckets.
+TEST_F(HistogramTest, BucketPlacementTest) {
+  Histogram* histogram(Histogram::FactoryGet(
+      "Histogram", 1, 64, 8, Histogram::kNoFlags));
+
+  // Add i+1 samples to the i'th bucket.
+  histogram->Add(0);
+  int power_of_2 = 1;
+  for (int i = 1; i < 8; i++) {
+    for (int j = 0; j <= i; j++)
+      histogram->Add(power_of_2);
+    power_of_2 *= 2;
+  }
+
+  // Check to see that the bucket counts reflect our additions.
+  scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
+  for (int i = 0; i < 8; i++)
+    EXPECT_EQ(i + 1, samples->GetCountAtIndex(i));
+}
+
+TEST_F(HistogramTest, CorruptSampleCounts) {
+  Histogram* histogram(Histogram::FactoryGet(
+      "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
+
+  // Add some samples.
+  histogram->Add(20);
+  histogram->Add(40);
+
+  scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
+  EXPECT_EQ(Histogram::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(Histogram::COUNT_LOW_ERROR,
+            histogram->FindCorruption(*snapshot));
+  snapshot->counts_[2] -= 200;
+  EXPECT_EQ(Histogram::COUNT_HIGH_ERROR,
+            histogram->FindCorruption(*snapshot));
+
+  // But we can't spot a corruption if it is compensated for.
+  snapshot->counts_[1] += 100;
+  EXPECT_EQ(Histogram::NO_INCONSISTENCIES,
+            histogram->FindCorruption(*snapshot));
+}
+
+TEST_F(HistogramTest, CorruptBucketBounds) {
+  Histogram* histogram(Histogram::FactoryGet(
+      "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
+
+  scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
+  EXPECT_EQ(Histogram::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(Histogram::BUCKET_ORDER_ERROR | Histogram::RANGE_CHECKSUM_ERROR,
+            histogram->FindCorruption(*snapshot));
+
+  bucket_ranges->set_range(2, bucket_ranges->range(1));
+  bucket_ranges->set_range(1, tmp);
+  EXPECT_EQ(0, histogram->FindCorruption(*snapshot));
+
+  // Show that two simple changes don't offset each other
+  bucket_ranges->set_range(3, bucket_ranges->range(3) + 1);
+  EXPECT_EQ(Histogram::RANGE_CHECKSUM_ERROR,
+            histogram->FindCorruption(*snapshot));
+
+  bucket_ranges->set_range(4, bucket_ranges->range(4) - 1);
+  EXPECT_EQ(Histogram::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);
+}
+
+#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) {
+  Histogram* histogram = Histogram::FactoryGet(
+      "BadRanges", 0, HistogramBase::kSampleType_MAX, 8, Histogram::kNoFlags);
+  EXPECT_EQ(1, histogram->declared_min());
+  EXPECT_EQ(HistogramBase::kSampleType_MAX - 1, histogram->declared_max());
+
+  Histogram* linear_histogram = LinearHistogram::FactoryGet(
+      "BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8,
+      Histogram::kNoFlags);
+  EXPECT_EQ(1, linear_histogram->declared_min());
+  EXPECT_EQ(HistogramBase::kSampleType_MAX - 1,
+            linear_histogram->declared_max());
+
+  vector<int> custom_ranges;
+  custom_ranges.push_back(0);
+  custom_ranges.push_back(5);
+  Histogram* custom_histogram1 = CustomHistogram::FactoryGet(
+      "BadRangesCustom", custom_ranges, Histogram::kNoFlags);
+  const BucketRanges* ranges = custom_histogram1->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,
+                                           Histogram::kNoFlags),
+               "");
+
+  // CustomHistogram needs at least 1 valid range.
+  custom_ranges.clear();
+  custom_ranges.push_back(0);
+  EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges,
+                                           Histogram::kNoFlags),
+               "");
+}
+#endif
+
+}  // namespace base
diff --git a/base/metrics/sample_map.cc b/base/metrics/sample_map.cc
new file mode 100644
index 0000000..9bd78e7
--- /dev/null
+++ b/base/metrics/sample_map.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/sample_map.h"
+
+#include "base/logging.h"
+
+using std::map;
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+SampleMap::SampleMap() {}
+
+SampleMap::~SampleMap() {}
+
+void SampleMap::Accumulate(Sample value, Count count) {
+  sample_counts_[value] += count;
+  IncreaseSum(count * value);
+  IncreaseRedundantCount(count);
+}
+
+Count SampleMap::GetCount(Sample value) const {
+  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 (map<Sample, Count>::const_iterator it = sample_counts_.begin();
+       it != sample_counts_.end();
+       ++it) {
+    count += it->second;
+  }
+  return count;
+}
+
+scoped_ptr<SampleCountIterator> SampleMap::Iterator() const {
+  return scoped_ptr<SampleCountIterator>(new SampleMapIterator(sample_counts_));
+}
+
+void SampleMap::ResetRedundantCount(Count count) {
+  IncreaseRedundantCount(-redundant_count());
+  IncreaseRedundantCount(count);
+}
+
+bool SampleMap::AddSubtractImpl(SampleCountIterator* iter,
+                                HistogramSamples::Operator op) {
+  Sample min;
+  Sample max;
+  Count count;
+  for (; !iter->Done(); iter->Next()) {
+    iter->Get(&min, &max, &count);
+    if (min + 1 != max)
+      return false;  // SparseHistogram only supports bucket with size 1.
+    sample_counts_[min] += (op ==  HistogramSamples::ADD) ? count : -count;
+  }
+  return true;
+}
+
+SampleMapIterator::SampleMapIterator(const SampleToCountMap& sample_counts)
+    : iter_(sample_counts.begin()),
+      end_(sample_counts.end()) {}
+
+SampleMapIterator::~SampleMapIterator() {}
+
+bool SampleMapIterator::Done() const {
+  return iter_ == end_;
+}
+
+void SampleMapIterator::Next() {
+  DCHECK(!Done());
+  iter_++;
+}
+
+void SampleMapIterator::Get(Sample* min, Sample* max, Count* count) const {
+  DCHECK(!Done());
+  if (min != NULL)
+    *min = iter_->first;
+  if (max != NULL)
+    *max = iter_->first + 1;
+  if (count != NULL)
+    *count = iter_->second;
+}
+
+}  // namespace base
diff --git a/base/metrics/sample_map.h b/base/metrics/sample_map.h
new file mode 100644
index 0000000..65a31f1
--- /dev/null
+++ b/base/metrics/sample_map.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// SampleMap implements HistogramSamples interface. It is used by the
+// SparseHistogram class to store samples.
+
+#ifndef BASE_METRICS_SAMPLE_MAP_H_
+#define BASE_METRICS_SAMPLE_MAP_H_
+
+#include <map>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+
+namespace base {
+
+class BASE_EXPORT_PRIVATE SampleMap : public HistogramSamples {
+ public:
+  SampleMap();
+  virtual ~SampleMap();
+
+  // HistogramSamples implementation:
+  virtual void Accumulate(HistogramBase::Sample value,
+                          HistogramBase::Count count) OVERRIDE;
+  virtual HistogramBase::Count GetCount(
+      HistogramBase::Sample value) const OVERRIDE;
+  virtual HistogramBase::Count TotalCount() const OVERRIDE;
+  virtual scoped_ptr<SampleCountIterator> Iterator() const OVERRIDE;
+
+  void ResetRedundantCount(HistogramBase::Count count);
+
+ protected:
+  virtual bool AddSubtractImpl(
+      SampleCountIterator* iter,
+      HistogramSamples::Operator op) OVERRIDE;  // |op| is ADD or SUBTRACT.
+
+ private:
+  std::map<HistogramBase::Sample, HistogramBase::Count> sample_counts_;
+
+  DISALLOW_COPY_AND_ASSIGN(SampleMap);
+};
+
+class BASE_EXPORT_PRIVATE SampleMapIterator : public SampleCountIterator {
+ public:
+  typedef std::map<HistogramBase::Sample, HistogramBase::Count>
+      SampleToCountMap;
+
+  SampleMapIterator(const SampleToCountMap& sample_counts);
+  virtual ~SampleMapIterator();
+
+  // SampleCountIterator implementation:
+  virtual bool Done() const OVERRIDE;
+  virtual void Next() OVERRIDE;
+  virtual void Get(HistogramBase::Sample* min,
+                   HistogramBase::Sample* max,
+                   HistogramBase::Count* count) const OVERRIDE;
+ private:
+  SampleToCountMap::const_iterator iter_;
+  const SampleToCountMap::const_iterator end_;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SAMPLE_MAP_H_
diff --git a/base/metrics/sample_map_unittest.cc b/base/metrics/sample_map_unittest.cc
new file mode 100644
index 0000000..1a53ee7
--- /dev/null
+++ b/base/metrics/sample_map_unittest.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/memory/scoped_ptr.h"
+#include "base/metrics/sample_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(SampleMapTest, AccumulateTest) {
+  SampleMap samples;
+
+  samples.Accumulate(1, 100);
+  samples.Accumulate(2, 200);
+  samples.Accumulate(1, -200);
+  EXPECT_EQ(-100, samples.GetCount(1));
+  EXPECT_EQ(200, samples.GetCount(2));
+
+  EXPECT_EQ(300, samples.sum());
+  EXPECT_EQ(100, samples.TotalCount());
+  EXPECT_EQ(samples.redundant_count(), samples.TotalCount());
+}
+
+TEST(SampleMapTest, AddSubtractTest) {
+  SampleMap samples1;
+  SampleMap samples2;
+
+  samples1.Accumulate(1, 100);
+  samples1.Accumulate(2, 100);
+  samples1.Accumulate(3, 100);
+
+  samples2.Accumulate(1, 200);
+  samples2.Accumulate(2, 200);
+  samples2.Accumulate(4, 200);
+
+  samples1.Add(samples2);
+  EXPECT_EQ(300, samples1.GetCount(1));
+  EXPECT_EQ(300, samples1.GetCount(2));
+  EXPECT_EQ(100, samples1.GetCount(3));
+  EXPECT_EQ(200, samples1.GetCount(4));
+  EXPECT_EQ(2000, samples1.sum());
+  EXPECT_EQ(900, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+
+  samples1.Subtract(samples2);
+  EXPECT_EQ(100, samples1.GetCount(1));
+  EXPECT_EQ(100, samples1.GetCount(2));
+  EXPECT_EQ(100, samples1.GetCount(3));
+  EXPECT_EQ(0, samples1.GetCount(4));
+  EXPECT_EQ(600, samples1.sum());
+  EXPECT_EQ(300, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+}
+
+TEST(SampleMapIteratorTest, IterateTest) {
+  SampleMap samples;
+  samples.Accumulate(1, 100);
+  samples.Accumulate(2, 200);
+  samples.Accumulate(4, -300);
+  samples.Accumulate(5, 0);
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(1, min);
+  EXPECT_EQ(2, max);
+  EXPECT_EQ(100, count);
+  EXPECT_FALSE(it->GetBucketIndex(NULL));
+
+  it->Next();
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(2, min);
+  EXPECT_EQ(3, max);
+  EXPECT_EQ(200, count);
+
+  it->Next();
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(4, min);
+  EXPECT_EQ(5, max);
+  EXPECT_EQ(-300, count);
+
+  it->Next();
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(5, min);
+  EXPECT_EQ(6, max);
+  EXPECT_EQ(0, count);
+
+  it->Next();
+  EXPECT_TRUE(it->Done());
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(SampleMapIteratorDeathTest, IterateDoneTest) {
+  SampleMap samples;
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+
+  EXPECT_TRUE(it->Done());
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  EXPECT_DEATH(it->Get(&min, &max, &count), "");
+
+  EXPECT_DEATH(it->Next(), "");
+
+  samples.Accumulate(1, 100);
+  it = samples.Iterator();
+  EXPECT_FALSE(it->Done());
+}
+
+#endif
+// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+}  // namespace
+}  // namespace base
diff --git a/base/metrics/sample_vector.cc b/base/metrics/sample_vector.cc
new file mode 100644
index 0000000..f90d80b
--- /dev/null
+++ b/base/metrics/sample_vector.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/sample_vector.h"
+
+#include "base/logging.h"
+#include "base/metrics/bucket_ranges.h"
+
+using std::vector;
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+SampleVector::SampleVector(const BucketRanges* bucket_ranges)
+    : counts_(bucket_ranges->size() - 1),
+      bucket_ranges_(bucket_ranges) {
+  CHECK_GE(bucket_ranges_->size(), 2u);
+}
+
+SampleVector::~SampleVector() {}
+
+void SampleVector::Accumulate(Sample value, Count count) {
+  size_t bucket_index = GetBucketIndex(value);
+  counts_[bucket_index] += count;
+  IncreaseSum(count * value);
+  IncreaseRedundantCount(count);
+}
+
+Count SampleVector::GetCount(Sample value) const {
+  size_t bucket_index = GetBucketIndex(value);
+  return counts_[bucket_index];
+}
+
+Count SampleVector::TotalCount() const {
+  Count count = 0;
+  for (size_t i = 0; i < counts_.size(); i++) {
+    count += counts_[i];
+  }
+  return count;
+}
+
+Count SampleVector::GetCountAtIndex(size_t bucket_index) const {
+  DCHECK(bucket_index >= 0 && bucket_index < counts_.size());
+  return counts_[bucket_index];
+}
+
+scoped_ptr<SampleCountIterator> SampleVector::Iterator() const {
+  return scoped_ptr<SampleCountIterator>(
+      new SampleVectorIterator(&counts_, bucket_ranges_));
+}
+
+bool SampleVector::AddSubtractImpl(SampleCountIterator* iter,
+                                   HistogramSamples::Operator op) {
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+
+  // Go through the iterator and add the counts into correct bucket.
+  size_t index = 0;
+  while (index < counts_.size() && !iter->Done()) {
+    iter->Get(&min, &max, &count);
+    if (min == bucket_ranges_->range(index) &&
+        max == bucket_ranges_->range(index + 1)) {
+      // Sample matches this bucket!
+      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_->size() - 1;
+  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 vector<Count>* counts,
+                                           const BucketRanges* bucket_ranges)
+    : counts_(counts),
+      bucket_ranges_(bucket_ranges),
+      index_(0) {
+  CHECK_GT(bucket_ranges_->size(), 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 = (*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 ((*counts_)[index_] != 0)
+      return;
+    index_++;
+  }
+}
+
+}  // namespace base
diff --git a/base/metrics/sample_vector.h b/base/metrics/sample_vector.h
new file mode 100644
index 0000000..67c344a
--- /dev/null
+++ b/base/metrics/sample_vector.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// SampleVector implements HistogramSamples interface. It is used by all
+// Histogram based classes to store samples.
+
+#ifndef BASE_METRICS_SAMPLE_VECTOR_H_
+#define BASE_METRICS_SAMPLE_VECTOR_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+
+namespace base {
+
+class BucketRanges;
+
+class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
+ public:
+  explicit SampleVector(const BucketRanges* bucket_ranges);
+  virtual ~SampleVector();
+
+  // HistogramSamples implementation:
+  virtual void Accumulate(HistogramBase::Sample value,
+                          HistogramBase::Count count) OVERRIDE;
+  virtual HistogramBase::Count GetCount(
+      HistogramBase::Sample value) const OVERRIDE;
+  virtual HistogramBase::Count TotalCount() const OVERRIDE;
+  virtual scoped_ptr<SampleCountIterator> Iterator() const OVERRIDE;
+
+  // Get count of a specific bucket.
+  HistogramBase::Count GetCountAtIndex(size_t bucket_index) const;
+
+ protected:
+  virtual bool AddSubtractImpl(
+      SampleCountIterator* iter,
+      HistogramSamples::Operator op) OVERRIDE;  // |op| is ADD or SUBTRACT.
+
+  virtual size_t GetBucketIndex(HistogramBase::Sample value) const;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
+
+  std::vector<HistogramBase::Count> counts_;
+
+  // Shares the same BucketRanges with Histogram object.
+  const BucketRanges* const bucket_ranges_;
+
+  DISALLOW_COPY_AND_ASSIGN(SampleVector);
+};
+
+class BASE_EXPORT_PRIVATE SampleVectorIterator : public SampleCountIterator {
+ public:
+  SampleVectorIterator(const std::vector<HistogramBase::Count>* counts,
+                       const BucketRanges* bucket_ranges);
+  virtual ~SampleVectorIterator();
+
+  // SampleCountIterator implementation:
+  virtual bool Done() const OVERRIDE;
+  virtual void Next() OVERRIDE;
+  virtual void Get(HistogramBase::Sample* min,
+                   HistogramBase::Sample* max,
+                   HistogramBase::Count* count) const OVERRIDE;
+
+  // SampleVector uses predefined buckets, so iterator can return bucket index.
+  virtual bool GetBucketIndex(size_t* index) const OVERRIDE;
+
+ private:
+  void SkipEmptyBuckets();
+
+  const std::vector<HistogramBase::Count>* counts_;
+  const BucketRanges* bucket_ranges_;
+
+  size_t index_;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SAMPLE_VECTOR_H_
diff --git a/base/metrics/sample_vector_unittest.cc b/base/metrics/sample_vector_unittest.cc
new file mode 100644
index 0000000..dbbbd15
--- /dev/null
+++ b/base/metrics/sample_vector_unittest.cc
@@ -0,0 +1,265 @@
+// Copyright (c) 2012 The Chromium Authors. 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/memory/scoped_ptr.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/sample_vector.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::vector;
+
+namespace base {
+namespace {
+
+TEST(SampleVectorTest, AccumulateTest) {
+  // Custom buckets: [1, 5) [5, 10)
+  BucketRanges ranges(3);
+  ranges.set_range(0, 1);
+  ranges.set_range(1, 5);
+  ranges.set_range(2, 10);
+  SampleVector samples(&ranges);
+
+  samples.Accumulate(1, 200);
+  samples.Accumulate(2, -300);
+  EXPECT_EQ(-100, samples.GetCountAtIndex(0));
+
+  samples.Accumulate(5, 200);
+  EXPECT_EQ(200, samples.GetCountAtIndex(1));
+
+  EXPECT_EQ(600, samples.sum());
+  EXPECT_EQ(100, samples.redundant_count());
+  EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
+
+  samples.Accumulate(5, -100);
+  EXPECT_EQ(100, samples.GetCountAtIndex(1));
+
+  EXPECT_EQ(100, samples.sum());
+  EXPECT_EQ(0, samples.redundant_count());
+  EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
+}
+
+TEST(SampleVectorTest, AddSubtractTest) {
+  // Custom buckets: [0, 1) [1, 2) [2, 3) [3, INT_MAX)
+  BucketRanges ranges(5);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+  ranges.set_range(3, 3);
+  ranges.set_range(4, INT_MAX);
+
+  SampleVector samples1(&ranges);
+  samples1.Accumulate(0, 100);
+  samples1.Accumulate(2, 100);
+  samples1.Accumulate(4, 100);
+  EXPECT_EQ(600, samples1.sum());
+  EXPECT_EQ(300, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+
+  SampleVector samples2(&ranges);
+  samples2.Accumulate(1, 200);
+  samples2.Accumulate(2, 200);
+  samples2.Accumulate(4, 200);
+  EXPECT_EQ(1400, samples2.sum());
+  EXPECT_EQ(600, samples2.TotalCount());
+  EXPECT_EQ(samples2.redundant_count(), samples2.TotalCount());
+
+  samples1.Add(samples2);
+  EXPECT_EQ(100, samples1.GetCountAtIndex(0));
+  EXPECT_EQ(200, samples1.GetCountAtIndex(1));
+  EXPECT_EQ(300, samples1.GetCountAtIndex(2));
+  EXPECT_EQ(300, samples1.GetCountAtIndex(3));
+  EXPECT_EQ(2000, samples1.sum());
+  EXPECT_EQ(900, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+
+  samples1.Subtract(samples2);
+  EXPECT_EQ(100, samples1.GetCountAtIndex(0));
+  EXPECT_EQ(0, samples1.GetCountAtIndex(1));
+  EXPECT_EQ(100, samples1.GetCountAtIndex(2));
+  EXPECT_EQ(100, samples1.GetCountAtIndex(3));
+  EXPECT_EQ(600, samples1.sum());
+  EXPECT_EQ(300, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+TEST(SampleVectorDeathTest, BucketIndexTest) {
+  // 8 buckets with exponential layout:
+  // [0, 1) [1, 2) [2, 4) [4, 8) [8, 16) [16, 32) [32, 64) [64, INT_MAX)
+  BucketRanges ranges(9);
+  Histogram::InitializeBucketRanges(1, 64, 8, &ranges);
+  SampleVector samples(&ranges);
+
+  // Normal case
+  samples.Accumulate(0, 1);
+  samples.Accumulate(3, 2);
+  samples.Accumulate(64, 3);
+  EXPECT_EQ(1, samples.GetCount(0));
+  EXPECT_EQ(2, samples.GetCount(2));
+  EXPECT_EQ(3, samples.GetCount(65));
+
+  // Extreme case.
+  EXPECT_DEATH(samples.Accumulate(INT_MIN, 100), "");
+  EXPECT_DEATH(samples.Accumulate(-1, 100), "");
+  EXPECT_DEATH(samples.Accumulate(INT_MAX, 100), "");
+
+  // Custom buckets: [1, 5) [5, 10)
+  // Note, this is not a valid BucketRanges for Histogram because it does not
+  // have overflow buckets.
+  BucketRanges ranges2(3);
+  ranges2.set_range(0, 1);
+  ranges2.set_range(1, 5);
+  ranges2.set_range(2, 10);
+  SampleVector samples2(&ranges2);
+
+  // Normal case.
+  samples2.Accumulate(1, 1);
+  samples2.Accumulate(4, 1);
+  samples2.Accumulate(5, 2);
+  samples2.Accumulate(9, 2);
+  EXPECT_EQ(2, samples2.GetCount(1));
+  EXPECT_EQ(4, samples2.GetCount(5));
+
+  // Extreme case.
+  EXPECT_DEATH(samples2.Accumulate(0, 100), "");
+  EXPECT_DEATH(samples2.Accumulate(10, 100), "");
+}
+
+TEST(SampleVectorDeathTest, AddSubtractBucketNotMatchTest) {
+  // Custom buckets 1: [1, 3) [3, 5)
+  BucketRanges ranges1(3);
+  ranges1.set_range(0, 1);
+  ranges1.set_range(1, 3);
+  ranges1.set_range(2, 5);
+  SampleVector samples1(&ranges1);
+
+  // Custom buckets 2: [0, 1) [1, 3) [3, 6) [6, 7)
+  BucketRanges ranges2(5);
+  ranges2.set_range(0, 0);
+  ranges2.set_range(1, 1);
+  ranges2.set_range(2, 3);
+  ranges2.set_range(3, 6);
+  ranges2.set_range(4, 7);
+  SampleVector samples2(&ranges2);
+
+  samples2.Accumulate(1, 100);
+  samples1.Add(samples2);
+  EXPECT_EQ(100, samples1.GetCountAtIndex(0));
+
+  // Extra bucket in the beginning.
+  samples2.Accumulate(0, 100);
+  EXPECT_DEATH(samples1.Add(samples2), "");
+  EXPECT_DEATH(samples1.Subtract(samples2), "");
+
+  // Extra bucket in the end.
+  samples2.Accumulate(0, -100);
+  samples2.Accumulate(6, 100);
+  EXPECT_DEATH(samples1.Add(samples2), "");
+  EXPECT_DEATH(samples1.Subtract(samples2), "");
+
+  // Bucket not match: [3, 5) VS [3, 6)
+  samples2.Accumulate(6, -100);
+  samples2.Accumulate(3, 100);
+  EXPECT_DEATH(samples1.Add(samples2), "");
+  EXPECT_DEATH(samples1.Subtract(samples2), "");
+}
+
+#endif
+// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(SampleVectorIteratorTest, IterateTest) {
+  BucketRanges ranges(5);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+  ranges.set_range(3, 3);
+  ranges.set_range(4, 4);
+
+  vector<HistogramBase::Count> counts(3);
+  counts[0] = 1;
+  counts[1] = 0;  // Iterator will bypass this empty bucket.
+  counts[2] = 2;
+
+  // BucketRanges can have larger size than counts.
+  SampleVectorIterator it(&counts, &ranges);
+  size_t index;
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  it.Get(&min, &max, &count);
+  EXPECT_EQ(0, min);
+  EXPECT_EQ(1, max);
+  EXPECT_EQ(1, count);
+  EXPECT_TRUE(it.GetBucketIndex(&index));
+  EXPECT_EQ(0u, index);
+
+  it.Next();
+  it.Get(&min, &max, &count);
+  EXPECT_EQ(2, min);
+  EXPECT_EQ(3, max);
+  EXPECT_EQ(2, count);
+  EXPECT_TRUE(it.GetBucketIndex(&index));
+  EXPECT_EQ(2u, index);
+
+  it.Next();
+  EXPECT_TRUE(it.Done());
+
+  // Create iterator from SampleVector.
+  SampleVector samples(&ranges);
+  samples.Accumulate(0, 0);
+  samples.Accumulate(1, 1);
+  samples.Accumulate(2, 2);
+  samples.Accumulate(3, 3);
+  scoped_ptr<SampleCountIterator> it2 = samples.Iterator();
+
+  int i;
+  for (i = 1; !it2->Done(); i++, it2->Next()) {
+    it2->Get(&min, &max, &count);
+    EXPECT_EQ(i, min);
+    EXPECT_EQ(i + 1, max);
+    EXPECT_EQ(i, count);
+
+    size_t index;
+    EXPECT_TRUE(it2->GetBucketIndex(&index));
+    EXPECT_EQ(static_cast<size_t>(i), index);
+  }
+  EXPECT_EQ(4, i);
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(SampleVectorIteratorDeathTest, IterateDoneTest) {
+  BucketRanges ranges(5);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+  ranges.set_range(3, 3);
+  ranges.set_range(4, INT_MAX);
+  SampleVector samples(&ranges);
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+
+  EXPECT_TRUE(it->Done());
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  EXPECT_DEATH(it->Get(&min, &max, &count), "");
+
+  EXPECT_DEATH(it->Next(), "");
+
+  samples.Accumulate(2, 100);
+  it = samples.Iterator();
+  EXPECT_FALSE(it->Done());
+}
+
+#endif
+// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+}  // namespace
+}  // namespace base
diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc
new file mode 100644
index 0000000..169037d
--- /dev/null
+++ b/base/metrics/sparse_histogram.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/sparse_histogram.h"
+
+#include "base/metrics/sample_map.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/synchronization/lock.h"
+
+using std::map;
+using std::string;
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+// static
+HistogramBase* SparseHistogram::FactoryGet(const string& name, int32 flags) {
+  // TODO(kaiwang): Register and get SparseHistogram with StatisticsRecorder.
+  HistogramBase* histogram = new SparseHistogram(name);
+  histogram->SetFlags(flags);
+  return histogram;
+}
+
+SparseHistogram::~SparseHistogram() {}
+
+HistogramType SparseHistogram::GetHistogramType() const {
+  return SPARSE_HISTOGRAM;
+}
+
+bool SparseHistogram::HasConstructionArguments(Sample minimum,
+                                               Sample maximum,
+                                               size_t bucket_count) const {
+  // SparseHistogram never has min/max/bucket_count limit.
+  return false;
+}
+
+void SparseHistogram::Add(Sample value) {
+  base::AutoLock auto_lock(lock_);
+  sample_counts_[value]++;
+  redundant_count_ += 1;
+}
+
+scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
+  scoped_ptr<SampleMap> snapshot(new SampleMap());
+
+  base::AutoLock auto_lock(lock_);
+  for(map<Sample, Count>::const_iterator it = sample_counts_.begin();
+      it != sample_counts_.end();
+      ++it) {
+    snapshot->Accumulate(it->first, it->second);
+  }
+  snapshot->ResetRedundantCount(redundant_count_);
+  return snapshot.PassAs<HistogramSamples>();
+}
+
+void SparseHistogram::WriteHTMLGraph(string* output) const {
+  // TODO(kaiwang): Implement.
+}
+
+void SparseHistogram::WriteAscii(string* output) const {
+  // TODO(kaiwang): Implement.
+}
+
+SparseHistogram::SparseHistogram(const string& name)
+    : HistogramBase(name),
+      redundant_count_(0) {}
+
+void SparseHistogram::GetParameters(DictionaryValue* params) const {
+  // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
+}
+
+void SparseHistogram::GetCountAndBucketData(Count* count,
+                                            ListValue* buckets) const {
+  // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
+}
+
+}  // namespace base
diff --git a/base/metrics/sparse_histogram.h b/base/metrics/sparse_histogram.h
new file mode 100644
index 0000000..a7c5695
--- /dev/null
+++ b/base/metrics/sparse_histogram.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_METRICS_SPARSE_HISTOGRAM_H_
+#define BASE_METRICS_SPARSE_HISTOGRAM_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+class HistogramSamples;
+
+class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase {
+ public:
+  // If there's one with same name, return the existing one. If not, create a
+  // new one.
+  static HistogramBase* FactoryGet(const std::string& name, int32 flags);
+
+  virtual ~SparseHistogram();
+
+  // HistogramBase implementation:
+  virtual HistogramType GetHistogramType() const OVERRIDE;
+  virtual bool HasConstructionArguments(Sample minimum,
+                                        Sample maximum,
+                                        size_t bucket_count) const OVERRIDE;
+  virtual void Add(Sample value) OVERRIDE;
+  virtual void WriteHTMLGraph(std::string* output) const OVERRIDE;
+  virtual void WriteAscii(std::string* output) const OVERRIDE;
+  virtual scoped_ptr<HistogramSamples> SnapshotSamples() const OVERRIDE;
+
+ private:
+  // Clients should always use FactoryGet to create SparseHistogram.
+  SparseHistogram(const std::string& name);
+
+  virtual void GetParameters(DictionaryValue* params) const OVERRIDE;
+  virtual void GetCountAndBucketData(Count* count,
+                                     ListValue* buckets) const OVERRIDE;
+
+  friend class SparseHistogramTest;  // For constuctor calling.
+
+  // Protects access to |sample_counts_| and |redundant_count_|.
+  mutable base::Lock lock_;
+  std::map<HistogramBase::Sample, HistogramBase::Count> sample_counts_;
+  HistogramBase::Count redundant_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(SparseHistogram);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SPARSE_HISTOGRAM_H_
diff --git a/base/metrics/sparse_histogram_unittest.cc b/base/metrics/sparse_histogram_unittest.cc
new file mode 100644
index 0000000..b4eb8fd
--- /dev/null
+++ b/base/metrics/sparse_histogram_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 <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/sample_map.h"
+#include "base/metrics/sparse_histogram.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class SparseHistogramTest : public testing::Test {
+ protected:
+  scoped_ptr<SparseHistogram> NewSparseHistogram(const std::string& name) {
+    return scoped_ptr<SparseHistogram>(new SparseHistogram(name));
+  }
+};
+
+TEST_F(SparseHistogramTest, BasicTest) {
+  scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse1"));
+  scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+  EXPECT_EQ(0, snapshot->TotalCount());
+  EXPECT_EQ(0, snapshot->sum());
+
+  histogram->Add(100);
+  scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
+  EXPECT_EQ(1, snapshot1->TotalCount());
+  EXPECT_EQ(1, snapshot1->GetCount(100));
+
+  histogram->Add(100);
+  histogram->Add(101);
+  scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+  EXPECT_EQ(3, snapshot2->TotalCount());
+  EXPECT_EQ(2, snapshot2->GetCount(100));
+  EXPECT_EQ(1, snapshot2->GetCount(101));
+}
+
+}  // namespace base
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
new file mode 100644
index 0000000..c1111c3
--- /dev/null
+++ b/base/metrics/statistics_recorder.cc
@@ -0,0 +1,340 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/statistics_recorder.h"
+
+#include "base/debug/leak_annotations.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/lock.h"
+
+using std::list;
+using std::string;
+
+namespace {
+// Initialize histogram statistics gathering system.
+base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ =
+    LAZY_INSTANCE_INITIALIZER;
+}  // namespace
+
+namespace base {
+
+// Collect the number of histograms created.
+static uint32 number_of_histograms_ = 0;
+// Collect the number of vectors saved because of caching ranges.
+static uint32 number_of_vectors_saved_ = 0;
+// Collect the number of ranges_ elements saved because of caching ranges.
+static size_t saved_ranges_size_ = 0;
+
+// 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
+Histogram* StatisticsRecorder::RegisterOrDeleteDuplicate(Histogram* 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;
+  }
+
+  Histogram* histogram_to_delete = NULL;
+  Histogram* histogram_to_return = NULL;
+  {
+    base::AutoLock auto_lock(*lock_);
+    if (histograms_ == NULL) {
+      ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
+      histogram_to_return = histogram;
+    } else {
+      const string& name = histogram->histogram_name();
+      HistogramMap::iterator it = histograms_->find(name);
+      if (histograms_->end() == it) {
+        (*histograms_)[name] = histogram;
+        ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
+        ++number_of_histograms_;
+        histogram_to_return = histogram;
+      } else if (histogram == it->second) {
+        // The histogram was registered before.
+        histogram_to_return = histogram;
+      } else {
+        // We already have one histogram with this name.
+        histogram_to_return = it->second;
+        histogram_to_delete = histogram;
+      }
+    }
+  }
+  delete histogram_to_delete;
+  return histogram_to_return;
+}
+
+// static
+const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
+    const BucketRanges* ranges) {
+  DCHECK(ranges->HasValidChecksum());
+  scoped_ptr<const BucketRanges> ranges_deleter;
+
+  if (lock_ == NULL) {
+    ANNOTATE_LEAKING_OBJECT_PTR(ranges);
+    return ranges;
+  }
+
+  base::AutoLock auto_lock(*lock_);
+  if (ranges_ == NULL) {
+    ANNOTATE_LEAKING_OBJECT_PTR(ranges);
+    return ranges;
+  }
+
+  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 list<const BucketRanges*>();
+    ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list);
+    (*ranges_)[ranges->checksum()] = checksum_matching_list;
+  } else {
+    checksum_matching_list = ranges_it->second;
+  }
+
+  list<const BucketRanges*>::iterator checksum_matching_list_it;
+  for (checksum_matching_list_it = checksum_matching_list->begin();
+       checksum_matching_list_it != checksum_matching_list->end();
+       ++checksum_matching_list_it) {
+    const BucketRanges* existing_ranges = *checksum_matching_list_it;
+    if (existing_ranges->Equals(ranges)) {
+      if (existing_ranges == ranges) {
+        return ranges;
+      } else {
+        ++number_of_vectors_saved_;
+        saved_ranges_size_ += ranges->size();
+        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::CollectHistogramStats(const std::string& suffix) {
+  static int uma_upload_attempt = 0;
+  ++uma_upload_attempt;
+  if (uma_upload_attempt == 1) {
+    UMA_HISTOGRAM_COUNTS_10000(
+        "Histogram.SharedRange.Count.FirstUpload." + suffix,
+        number_of_histograms_);
+    UMA_HISTOGRAM_COUNTS_10000(
+        "Histogram.SharedRange.RangesSaved.FirstUpload." + suffix,
+        number_of_vectors_saved_);
+    UMA_HISTOGRAM_COUNTS(
+        "Histogram.SharedRange.ElementsSaved.FirstUpload." + suffix,
+        static_cast<int>(saved_ranges_size_));
+    number_of_histograms_ = 0;
+    number_of_vectors_saved_ = 0;
+    saved_ranges_size_ = 0;
+    return;
+  }
+  if (uma_upload_attempt == 2) {
+    UMA_HISTOGRAM_COUNTS_10000(
+        "Histogram.SharedRange.Count.SecondUpload." + suffix,
+        number_of_histograms_);
+    UMA_HISTOGRAM_COUNTS_10000(
+        "Histogram.SharedRange.RangesSaved.SecondUpload." + suffix,
+        number_of_vectors_saved_);
+    UMA_HISTOGRAM_COUNTS(
+        "Histogram.SharedRange.ElementsSaved.SecondUpload." + suffix,
+        static_cast<int>(saved_ranges_size_));
+    number_of_histograms_ = 0;
+    number_of_vectors_saved_ = 0;
+    saved_ranges_size_ = 0;
+    return;
+  }
+  UMA_HISTOGRAM_COUNTS_10000(
+      "Histogram.SharedRange.Count.RestOfUploads." + suffix,
+      number_of_histograms_);
+  UMA_HISTOGRAM_COUNTS_10000(
+      "Histogram.SharedRange.RangesSaved.RestOfUploads." + suffix,
+      number_of_vectors_saved_);
+  UMA_HISTOGRAM_COUNTS(
+      "Histogram.SharedRange.ElementsSaved.RestOfUploads." + suffix,
+      static_cast<int>(saved_ranges_size_));
+}
+
+// static
+void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
+                                        std::string* output) {
+  if (!IsActive())
+    return;
+
+  Histograms snapshot;
+  GetSnapshot(query, &snapshot);
+  for (Histograms::iterator it = snapshot.begin();
+       it != snapshot.end();
+       ++it) {
+    (*it)->WriteHTMLGraph(output);
+    output->append("<br><hr><br>");
+  }
+}
+
+// static
+void StatisticsRecorder::WriteGraph(const std::string& query,
+                                    std::string* output) {
+  if (!IsActive())
+    return;
+  if (query.length())
+    StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
+  else
+    output->append("Collections of all histograms\n");
+
+  Histograms snapshot;
+  GetSnapshot(query, &snapshot);
+  for (Histograms::iterator it = snapshot.begin();
+       it != snapshot.end();
+       ++it) {
+    (*it)->WriteAscii(output);
+    output->append("\n");
+  }
+}
+
+// static
+void StatisticsRecorder::GetHistograms(Histograms* output) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return;
+
+  for (HistogramMap::iterator it = histograms_->begin();
+       histograms_->end() != it;
+       ++it) {
+    DCHECK_EQ(it->first, it->second->histogram_name());
+    output->push_back(it->second);
+  }
+}
+
+// static
+void StatisticsRecorder::GetBucketRanges(
+    std::vector<const BucketRanges*>* output) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (ranges_ == NULL)
+    return;
+
+  for (RangesMap::iterator it = ranges_->begin();
+       ranges_->end() != it;
+       ++it) {
+    list<const BucketRanges*>* ranges_list = it->second;
+    list<const BucketRanges*>::iterator ranges_list_it;
+    for (ranges_list_it = ranges_list->begin();
+         ranges_list_it != ranges_list->end();
+         ++ranges_list_it) {
+      output->push_back(*ranges_list_it);
+    }
+  }
+}
+
+// static
+Histogram* StatisticsRecorder::FindHistogram(const std::string& name) {
+  if (lock_ == NULL)
+    return NULL;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return NULL;
+
+  HistogramMap::iterator it = histograms_->find(name);
+  if (histograms_->end() == it)
+    return NULL;
+  return it->second;
+}
+
+// private static
+void StatisticsRecorder::GetSnapshot(const std::string& query,
+                                     Histograms* snapshot) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return;
+
+  for (HistogramMap::iterator it = histograms_->begin();
+       histograms_->end() != it;
+       ++it) {
+    if (it->first.find(query) != std::string::npos)
+      snapshot->push_back(it->second);
+  }
+}
+
+// This singleton instance should be started during the single threaded portion
+// of main(), and hence it is not thread safe.  It initializes globals to
+// provide support for all future calls.
+StatisticsRecorder::StatisticsRecorder() {
+  DCHECK(!histograms_);
+  if (lock_ == NULL) {
+    // This will leak on purpose. It's the only way to make sure we won't race
+    // against the static uninitialization of the module while one of our
+    // static methods relying on the lock get called at an inappropriate time
+    // during the termination phase. Since it's a static data member, we will
+    // leak one per process, which would be similar to the instance allocated
+    // during static initialization and released only on  process termination.
+    lock_ = new base::Lock;
+  }
+  base::AutoLock auto_lock(*lock_);
+  histograms_ = new HistogramMap;
+  ranges_ = new RangesMap;
+}
+
+StatisticsRecorder::~StatisticsRecorder() {
+  DCHECK(histograms_ && ranges_ && lock_);
+  if (dump_on_exit_) {
+    string output;
+    WriteGraph("", &output);
+    DLOG(INFO) << output;
+  }
+
+  // Clean up.
+  scoped_ptr<HistogramMap> histograms_deleter;
+  scoped_ptr<RangesMap> ranges_deleter;
+  // We don't delete lock_ on purpose to avoid having to properly protect
+  // against it going away after we checked for NULL in the static methods.
+  {
+    base::AutoLock auto_lock(*lock_);
+    histograms_deleter.reset(histograms_);
+    ranges_deleter.reset(ranges_);
+    histograms_ = NULL;
+    ranges_ = NULL;
+  }
+  // We are going to leak the histograms and the ranges.
+}
+
+
+// static
+StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
+// static
+StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
+// static
+base::Lock* StatisticsRecorder::lock_ = NULL;
+// static
+bool StatisticsRecorder::dump_on_exit_ = false;
+
+}  // namespace base
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
new file mode 100644
index 0000000..5345735
--- /dev/null
+++ b/base/metrics/statistics_recorder.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// StatisticsRecorder holds all Histograms and BucketRanges that are used by
+// Histograms in the system. It provides a general place for
+// Histograms/BucketRanges to register, and supports a global API for accessing
+// (i.e., dumping, or graphing) the data.
+
+#ifndef BASE_METRICS_STATISTICS_RECORDER_H_
+#define BASE_METRICS_STATISTICS_RECORDER_H_
+
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/lazy_instance.h"
+
+namespace base {
+
+class BucketRanges;
+class Histogram;
+class Lock;
+
+class BASE_EXPORT StatisticsRecorder {
+ public:
+  typedef std::vector<Histogram*> Histograms;
+
+  // Initializes the StatisticsRecorder system.
+  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 Histogram* RegisterOrDeleteDuplicate(Histogram* 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);
+
+  // Method for collecting stats about histograms created in browser and
+  // renderer processes. |suffix| is appended to histogram names. |suffix| could
+  // be either browser or renderer.
+  static void CollectHistogramStats(const std::string& suffix);
+
+  // Methods for printing histograms.  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);
+
+  // 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 Histogram* FindHistogram(const std::string& name);
+
+  static bool dump_on_exit() { return dump_on_exit_; }
+
+  static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; }
+
+  // GetSnapshot copies some of the pointers to registered histograms into the
+  // caller supplied vector (Histograms).  Only histograms with names matching
+  // query are returned. The query must be a substring of histogram name for its
+  // pointer to be copied.
+  static void GetSnapshot(const std::string& query, Histograms* snapshot);
+
+ private:
+  // We keep all registered histograms in a map, from name to histogram.
+  typedef std::map<std::string, Histogram*> HistogramMap;
+
+  // We keep all |bucket_ranges_| in a map, from checksum to a list of
+  // |bucket_ranges_|.  Checksum is calculated from the |ranges_| in
+  // |bucket_ranges_|.
+  typedef std::map<uint32, std::list<const BucketRanges*>*> RangesMap;
+
+  friend struct DefaultLazyInstanceTraits<StatisticsRecorder>;
+  friend class HistogramTest;
+  friend class StatisticsRecorderTest;
+
+  // The constructor just initializes static members. Usually client code should
+  // use Initialize to do this. But in test code, you can friend this class and
+  // call destructor/constructor to get a clean StatisticsRecorder.
+  StatisticsRecorder();
+  ~StatisticsRecorder();
+
+  static HistogramMap* histograms_;
+  static RangesMap* ranges_;
+
+  // Lock protects access to above maps.
+  static base::Lock* lock_;
+
+  // Dump all known histograms to log.
+  static bool dump_on_exit_;
+
+  DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_STATISTICS_RECORDER_H_
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc
new file mode 100644
index 0000000..95759c1
--- /dev/null
+++ b/base/metrics/statistics_recorder_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 <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class StatisticsRecorderTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+  }
+
+  virtual void TearDown() {
+    UninitializeStatisticsRecorder();
+  }
+
+  void InitializeStatisticsRecorder() {
+    statistics_recorder_ = new StatisticsRecorder();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    delete statistics_recorder_;
+    statistics_recorder_ = NULL;
+  }
+
+  void DeleteHistogram(Histogram* histogram) {
+    delete histogram;
+  }
+
+  StatisticsRecorder* statistics_recorder_;
+};
+
+TEST_F(StatisticsRecorderTest, NotInitialized) {
+  UninitializeStatisticsRecorder();
+
+  ASSERT_FALSE(StatisticsRecorder::IsActive());
+
+  StatisticsRecorder::Histograms registered_histograms;
+  std::vector<const BucketRanges*> registered_ranges;
+
+  // We can still create histograms, but it's not registered.
+  // TODO(kaiwang): Do not depend on Histogram FactoryGet implementation.
+  Histogram* histogram(
+      Histogram::FactoryGet("StatisticsRecorderTest_NotInitialized",
+                            1, 1000, 10, Histogram::kNoFlags));
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(0u, registered_histograms.size());
+
+  // 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());
+
+  DeleteHistogram(histogram);
+}
+
+TEST_F(StatisticsRecorderTest, RegisterBucketRanges) {
+  std::vector<const BucketRanges*> registered_ranges;
+
+  BucketRanges* ranges1 = new BucketRanges(3);;
+  ranges1->ResetChecksum();
+  BucketRanges* ranges2 = new BucketRanges(4);;
+  ranges2->ResetChecksum();
+
+  // Register new ranges.
+  EXPECT_EQ(ranges1,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
+  EXPECT_EQ(ranges2,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges2));
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  ASSERT_EQ(2u, registered_ranges.size());
+
+  // Register some ranges again.
+  EXPECT_EQ(ranges1,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
+  registered_ranges.clear();
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  ASSERT_EQ(2u, registered_ranges.size());
+  // Make sure the ranges is still the one we know.
+  ASSERT_EQ(3u, ranges1->size());
+  EXPECT_EQ(0, ranges1->range(0));
+  EXPECT_EQ(0, ranges1->range(1));
+  EXPECT_EQ(0, ranges1->range(2));
+
+  // Register ranges with same values.
+  BucketRanges* ranges3 = new BucketRanges(3);;
+  ranges3->ResetChecksum();
+  EXPECT_EQ(ranges1,  // returning ranges1
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges3));
+  registered_ranges.clear();
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  ASSERT_EQ(2u, registered_ranges.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterHistogram) {
+  // Create a Histogram that was not registered.
+  // TODO(kaiwang): Do not depend on Histogram FactoryGet implementation.
+  UninitializeStatisticsRecorder();
+  Histogram* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, Histogram::kNoFlags);
+
+  // Clean StatisticsRecorder.
+  InitializeStatisticsRecorder();
+  StatisticsRecorder::Histograms registered_histograms;
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(0u, registered_histograms.size());
+
+  // Register the Histogram.
+  EXPECT_EQ(histogram,
+            StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+
+  // Register the same Histogram again.
+  EXPECT_EQ(histogram,
+            StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+}
+
+TEST_F(StatisticsRecorderTest, FindHistogram) {
+  Histogram* histogram1 = Histogram::FactoryGet(
+      "TestHistogram1", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram* histogram2 = Histogram::FactoryGet(
+      "TestHistogram2", 1, 1000, 10, Histogram::kNoFlags);
+
+  EXPECT_EQ(histogram1, StatisticsRecorder::FindHistogram("TestHistogram1"));
+  EXPECT_EQ(histogram2, StatisticsRecorder::FindHistogram("TestHistogram2"));
+  EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram") == NULL);
+}
+
+TEST_F(StatisticsRecorderTest, GetSnapshot) {
+  Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram::FactoryGet("TestHistogram3", 1, 1000, 10, Histogram::kNoFlags);
+
+  StatisticsRecorder::Histograms snapshot;
+  StatisticsRecorder::GetSnapshot("Test", &snapshot);
+  EXPECT_EQ(3u, snapshot.size());
+
+  snapshot.clear();
+  StatisticsRecorder::GetSnapshot("1", &snapshot);
+  EXPECT_EQ(1u, snapshot.size());
+
+  snapshot.clear();
+  StatisticsRecorder::GetSnapshot("hello", &snapshot);
+  EXPECT_EQ(0u, snapshot.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) {
+  StatisticsRecorder::Histograms registered_histograms;
+
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  ASSERT_EQ(0u, registered_histograms.size());
+
+  // Create a Histogram.
+  Histogram* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, Histogram::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+
+  // Get an existing histogram.
+  Histogram* histogram2 = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, Histogram::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, Histogram::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(2u, registered_histograms.size());
+
+  // Create a BooleanHistogram.
+  histogram = BooleanHistogram::FactoryGet(
+      "TestBooleanHistogram", Histogram::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, Histogram::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(4u, registered_histograms.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterHistogramWithMacros) {
+  StatisticsRecorder::Histograms registered_histograms;
+
+  Histogram* histogram = Histogram::FactoryGet(
+      "TestHistogramCounts", 1, 1000000, 50, Histogram::kNoFlags);
+
+  // The histogram we got from macro is the same as from FactoryGet.
+  HISTOGRAM_COUNTS("TestHistogramCounts", 30);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  ASSERT_EQ(1u, registered_histograms.size());
+  EXPECT_EQ(histogram, registered_histograms[0]);
+
+  HISTOGRAM_TIMES("TestHistogramTimes", TimeDelta::FromDays(1));
+  HISTOGRAM_ENUMERATION("TestHistogramEnumeration", 20, 200);
+
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(3u, registered_histograms.size());
+
+  // Debugging only macros.
+  DHISTOGRAM_TIMES("TestHistogramDebugTimes", TimeDelta::FromDays(1));
+  DHISTOGRAM_COUNTS("TestHistogramDebugCounts", 30);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+#ifndef NDEBUG
+  EXPECT_EQ(5u, registered_histograms.size());
+#else
+  EXPECT_EQ(3u, registered_histograms.size());
+#endif
+}
+
+TEST_F(StatisticsRecorderTest, BucketRangesSharing) {
+  Histogram* histogram1(Histogram::FactoryGet(
+      "Histogram", 1, 64, 8, Histogram::kNoFlags));
+  Histogram* histogram2(Histogram::FactoryGet(
+      "Histogram2", 1, 64, 8, Histogram::kNoFlags));
+  Histogram* histogram3(Histogram::FactoryGet(
+      "Histogram3", 1, 64, 16, Histogram::kNoFlags));
+
+  const BucketRanges* bucket_ranges1 = histogram1->bucket_ranges();
+  const BucketRanges* bucket_ranges2 = histogram2->bucket_ranges();
+  const BucketRanges* bucket_ranges3 = histogram3->bucket_ranges();
+  EXPECT_EQ(bucket_ranges1, bucket_ranges2);
+  EXPECT_FALSE(bucket_ranges1->Equals(bucket_ranges3));
+}
+
+}  // namespace base
diff --git a/base/metrics/stats_counters.cc b/base/metrics/stats_counters.cc
new file mode 100644
index 0000000..f763220
--- /dev/null
+++ b/base/metrics/stats_counters.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/stats_counters.h"
+
+namespace base {
+
+StatsCounter::StatsCounter(const std::string& name)
+    : counter_id_(-1) {
+  // We prepend the name with 'c:' to indicate that it is a counter.
+  if (StatsTable::current()) {
+    // TODO(mbelshe): name_ construction is racy and it may corrupt memory for
+    // static.
+    name_ = "c:";
+    name_.append(name);
+  }
+}
+
+StatsCounter::~StatsCounter() {
+}
+
+void StatsCounter::Set(int value) {
+  int* loc = GetPtr();
+  if (loc)
+    *loc = value;
+}
+
+void StatsCounter::Add(int value) {
+  int* loc = GetPtr();
+  if (loc)
+    (*loc) += value;
+}
+
+StatsCounter::StatsCounter()
+    : counter_id_(-1) {
+}
+
+int* StatsCounter::GetPtr() {
+  StatsTable* table = StatsTable::current();
+  if (!table)
+    return NULL;
+
+  // If counter_id_ is -1, then we haven't looked it up yet.
+  if (counter_id_ == -1) {
+    counter_id_ = table->FindCounter(name_);
+    if (table->GetSlot() == 0) {
+      if (!table->RegisterThread("")) {
+        // There is no room for this thread.  This thread
+        // cannot use counters.
+        counter_id_ = 0;
+        return NULL;
+      }
+    }
+  }
+
+  // If counter_id_ is > 0, then we have a valid counter.
+  if (counter_id_ > 0)
+    return table->GetLocation(counter_id_, table->GetSlot());
+
+  // counter_id_ was zero, which means the table is full.
+  return NULL;
+}
+
+
+StatsCounterTimer::StatsCounterTimer(const std::string& name) {
+  // we prepend the name with 't:' to indicate that it is a timer.
+  if (StatsTable::current()) {
+    // TODO(mbelshe): name_ construction is racy and it may corrupt memory for
+    // static.
+    name_ = "t:";
+    name_.append(name);
+  }
+}
+
+StatsCounterTimer::~StatsCounterTimer() {
+}
+
+void StatsCounterTimer::Start() {
+  if (!Enabled())
+    return;
+  start_time_ = TimeTicks::Now();
+  stop_time_ = TimeTicks();
+}
+
+// Stop the timer and record the results.
+void StatsCounterTimer::Stop() {
+  if (!Enabled() || !Running())
+    return;
+  stop_time_ = TimeTicks::Now();
+  Record();
+}
+
+// Returns true if the timer is running.
+bool StatsCounterTimer::Running() {
+  return Enabled() && !start_time_.is_null() && stop_time_.is_null();
+}
+
+// Accept a TimeDelta to increment.
+void StatsCounterTimer::AddTime(TimeDelta time) {
+  Add(static_cast<int>(time.InMilliseconds()));
+}
+
+void StatsCounterTimer::Record() {
+  AddTime(stop_time_ - start_time_);
+}
+
+
+StatsRate::StatsRate(const std::string& name)
+    : StatsCounterTimer(name),
+      counter_(name),
+      largest_add_(std::string(" ").append(name).append("MAX")) {
+}
+
+StatsRate::~StatsRate() {
+}
+
+void StatsRate::Add(int value) {
+  counter_.Increment();
+  StatsCounterTimer::Add(value);
+  if (value > largest_add_.value())
+    largest_add_.Set(value);
+}
+
+}  // namespace base
diff --git a/base/metrics/stats_counters.h b/base/metrics/stats_counters.h
new file mode 100644
index 0000000..ccc73ba
--- /dev/null
+++ b/base/metrics/stats_counters.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2011 The Chromium Authors. All 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_STATS_COUNTERS_H_
+#define BASE_METRICS_STATS_COUNTERS_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/metrics/stats_table.h"
+#include "base/time.h"
+
+namespace base {
+
+// StatsCounters are dynamically created values which can be tracked in
+// the StatsTable.  They are designed to be lightweight to create and
+// easy to use.
+//
+// Since StatsCounters can be created dynamically by name, there is
+// a hash table lookup to find the counter in the table.  A StatsCounter
+// object can be created once and used across multiple threads safely.
+//
+// Example usage:
+//    {
+//      StatsCounter request_count("RequestCount");
+//      request_count.Increment();
+//    }
+//
+// Note that creating counters on the stack does work, however creating
+// the counter object requires a hash table lookup.  For inner loops, it
+// may be better to create the counter either as a member of another object
+// (or otherwise outside of the loop) for maximum performance.
+//
+// Internally, a counter represents a value in a row of a StatsTable.
+// The row has a 32bit value for each process/thread in the table and also
+// a name (stored in the table metadata).
+//
+// NOTE: In order to make stats_counters usable in lots of different code,
+// avoid any dependencies inside this header file.
+//
+
+//------------------------------------------------------------------------------
+// Define macros for ease of use. They also allow us to change definitions
+// as the implementation varies, or depending on compile options.
+//------------------------------------------------------------------------------
+// First provide generic macros, which exist in production as well as debug.
+#define STATS_COUNTER(name, delta) do { \
+  base::StatsCounter counter(name); \
+  counter.Add(delta); \
+} while (0)
+
+#define SIMPLE_STATS_COUNTER(name) STATS_COUNTER(name, 1)
+
+#define RATE_COUNTER(name, duration) do { \
+  base::StatsRate hit_count(name); \
+  hit_count.AddTime(duration); \
+} while (0)
+
+// Define Debug vs non-debug flavors of macros.
+#ifndef NDEBUG
+
+#define DSTATS_COUNTER(name, delta) STATS_COUNTER(name, delta)
+#define DSIMPLE_STATS_COUNTER(name) SIMPLE_STATS_COUNTER(name)
+#define DRATE_COUNTER(name, duration) RATE_COUNTER(name, duration)
+
+#else  // NDEBUG
+
+#define DSTATS_COUNTER(name, delta) do {} while (0)
+#define DSIMPLE_STATS_COUNTER(name) do {} while (0)
+#define DRATE_COUNTER(name, duration) do {} while (0)
+
+#endif  // NDEBUG
+
+//------------------------------------------------------------------------------
+// StatsCounter represents a counter in the StatsTable class.
+class BASE_EXPORT StatsCounter {
+ public:
+  // Create a StatsCounter object.
+  explicit StatsCounter(const std::string& name);
+  virtual ~StatsCounter();
+
+  // Sets the counter to a specific value.
+  void Set(int value);
+
+  // Increments the counter.
+  void Increment() {
+    Add(1);
+  }
+
+  virtual void Add(int value);
+
+  // Decrements the counter.
+  void Decrement() {
+    Add(-1);
+  }
+
+  void Subtract(int value) {
+    Add(-value);
+  }
+
+  // Is this counter enabled?
+  // Returns false if table is full.
+  bool Enabled() {
+    return GetPtr() != NULL;
+  }
+
+  int value() {
+    int* loc = GetPtr();
+    if (loc) return *loc;
+    return 0;
+  }
+
+ protected:
+  StatsCounter();
+
+  // Returns the cached address of this counter location.
+  int* GetPtr();
+
+  std::string name_;
+  // The counter id in the table.  We initialize to -1 (an invalid value)
+  // and then cache it once it has been looked up.  The counter_id is
+  // valid across all threads and processes.
+  int32 counter_id_;
+};
+
+
+// A StatsCounterTimer is a StatsCounter which keeps a timer during
+// the scope of the StatsCounterTimer.  On destruction, it will record
+// its time measurement.
+class BASE_EXPORT StatsCounterTimer : protected StatsCounter {
+ public:
+  // Constructs and starts the timer.
+  explicit StatsCounterTimer(const std::string& name);
+  virtual ~StatsCounterTimer();
+
+  // Start the timer.
+  void Start();
+
+  // Stop the timer and record the results.
+  void Stop();
+
+  // Returns true if the timer is running.
+  bool Running();
+
+  // Accept a TimeDelta to increment.
+  virtual void AddTime(TimeDelta time);
+
+ protected:
+  // Compute the delta between start and stop, in milliseconds.
+  void Record();
+
+  TimeTicks start_time_;
+  TimeTicks stop_time_;
+};
+
+// A StatsRate is a timer that keeps a count of the number of intervals added so
+// that several statistics can be produced:
+//    min, max, avg, count, total
+class BASE_EXPORT StatsRate : public StatsCounterTimer {
+ public:
+  // Constructs and starts the timer.
+  explicit StatsRate(const std::string& name);
+  virtual ~StatsRate();
+
+  virtual void Add(int value) OVERRIDE;
+
+ private:
+  StatsCounter counter_;
+  StatsCounter largest_add_;
+};
+
+
+// Helper class for scoping a timer or rate.
+template<class T> class StatsScope {
+ public:
+  explicit StatsScope<T>(T& timer)
+      : timer_(timer) {
+    timer_.Start();
+  }
+
+  ~StatsScope() {
+    timer_.Stop();
+  }
+
+  void Stop() {
+    timer_.Stop();
+  }
+
+ private:
+  T& timer_;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_STATS_COUNTERS_H_
diff --git a/base/metrics/stats_table.cc b/base/metrics/stats_table.cc
new file mode 100644
index 0000000..2bccc90
--- /dev/null
+++ b/base/metrics/stats_table.cc
@@ -0,0 +1,560 @@
+// Copyright (c) 2011 The Chromium Authors. All 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/stats_table.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process_util.h"
+#include "base/shared_memory.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/utf_string_conversions.h"
+
+#if defined(OS_POSIX)
+#include "errno.h"
+#endif
+
+namespace base {
+
+// The StatsTable uses a shared memory segment that is laid out as follows
+//
+// +-------------------------------------------+
+// | Version | Size | MaxCounters | MaxThreads |
+// +-------------------------------------------+
+// | Thread names table                        |
+// +-------------------------------------------+
+// | Thread TID table                          |
+// +-------------------------------------------+
+// | Thread PID table                          |
+// +-------------------------------------------+
+// | Counter names table                       |
+// +-------------------------------------------+
+// | Data                                      |
+// +-------------------------------------------+
+//
+// The data layout is a grid, where the columns are the thread_ids and the
+// rows are the counter_ids.
+//
+// If the first character of the thread_name is '\0', then that column is
+// empty.
+// If the first character of the counter_name is '\0', then that row is
+// empty.
+//
+// About Locking:
+// This class is designed to be both multi-thread and multi-process safe.
+// Aside from initialization, this is done by partitioning the data which
+// each thread uses so that no locking is required.  However, to allocate
+// the rows and columns of the table to particular threads, locking is
+// required.
+//
+// At the shared-memory level, we have a lock.  This lock protects the
+// shared-memory table only, and is used when we create new counters (e.g.
+// use rows) or when we register new threads (e.g. use columns).  Reading
+// data from the table does not require any locking at the shared memory
+// level.
+//
+// Each process which accesses the table will create a StatsTable object.
+// The StatsTable maintains a hash table of the existing counters in the
+// table for faster lookup.  Since the hash table is process specific,
+// each process maintains its own cache.  We avoid complexity here by never
+// de-allocating from the hash table.  (Counters are dynamically added,
+// but not dynamically removed).
+
+// In order for external viewers to be able to read our shared memory,
+// we all need to use the same size ints.
+COMPILE_ASSERT(sizeof(int)==4, expect_4_byte_ints);
+
+namespace {
+
+// An internal version in case we ever change the format of this
+// file, and so that we can identify our table.
+const int kTableVersion = 0x13131313;
+
+// The name for un-named counters and threads in the table.
+const char kUnknownName[] = "<unknown>";
+
+// Calculates delta to align an offset to the size of an int
+inline int AlignOffset(int offset) {
+  return (sizeof(int) - (offset % sizeof(int))) % sizeof(int);
+}
+
+inline int AlignedSize(int size) {
+  return size + AlignOffset(size);
+}
+
+}  // namespace
+
+// The StatsTable::Private maintains convenience pointers into the
+// shared memory segment.  Use this class to keep the data structure
+// clean and accessible.
+class StatsTable::Private {
+ public:
+  // Various header information contained in the memory mapped segment.
+  struct TableHeader {
+    int version;
+    int size;
+    int max_counters;
+    int max_threads;
+  };
+
+  // Construct a new Private based on expected size parameters, or
+  // return NULL on failure.
+  static Private* New(const std::string& name, int size,
+                                int max_threads, int max_counters);
+
+  SharedMemory* shared_memory() { return &shared_memory_; }
+
+  // Accessors for our header pointers
+  TableHeader* table_header() const { return table_header_; }
+  int version() const { return table_header_->version; }
+  int size() const { return table_header_->size; }
+  int max_counters() const { return table_header_->max_counters; }
+  int max_threads() const { return table_header_->max_threads; }
+
+  // Accessors for our tables
+  char* thread_name(int slot_id) const {
+    return &thread_names_table_[
+      (slot_id-1) * (StatsTable::kMaxThreadNameLength)];
+  }
+  PlatformThreadId* thread_tid(int slot_id) const {
+    return &(thread_tid_table_[slot_id-1]);
+  }
+  int* thread_pid(int slot_id) const {
+    return &(thread_pid_table_[slot_id-1]);
+  }
+  char* counter_name(int counter_id) const {
+    return &counter_names_table_[
+      (counter_id-1) * (StatsTable::kMaxCounterNameLength)];
+  }
+  int* row(int counter_id) const {
+    return &data_table_[(counter_id-1) * max_threads()];
+  }
+
+ private:
+  // Constructor is private because you should use New() instead.
+  Private()
+      : table_header_(NULL),
+        thread_names_table_(NULL),
+        thread_tid_table_(NULL),
+        thread_pid_table_(NULL),
+        counter_names_table_(NULL),
+        data_table_(NULL) {
+  }
+
+  // Initializes the table on first access.  Sets header values
+  // appropriately and zeroes all counters.
+  void InitializeTable(void* memory, int size, int max_counters,
+                       int max_threads);
+
+  // Initializes our in-memory pointers into a pre-created StatsTable.
+  void ComputeMappedPointers(void* memory);
+
+  SharedMemory shared_memory_;
+  TableHeader* table_header_;
+  char* thread_names_table_;
+  PlatformThreadId* thread_tid_table_;
+  int* thread_pid_table_;
+  char* counter_names_table_;
+  int* data_table_;
+};
+
+// static
+StatsTable::Private* StatsTable::Private::New(const std::string& name,
+                                              int size,
+                                              int max_threads,
+                                              int max_counters) {
+  scoped_ptr<Private> priv(new Private());
+  if (!priv->shared_memory_.CreateNamed(name, true, size))
+    return NULL;
+  if (!priv->shared_memory_.Map(size))
+    return NULL;
+  void* memory = priv->shared_memory_.memory();
+
+  TableHeader* header = static_cast<TableHeader*>(memory);
+
+  // If the version does not match, then assume the table needs
+  // to be initialized.
+  if (header->version != kTableVersion)
+    priv->InitializeTable(memory, size, max_counters, max_threads);
+
+  // We have a valid table, so compute our pointers.
+  priv->ComputeMappedPointers(memory);
+
+  return priv.release();
+}
+
+void StatsTable::Private::InitializeTable(void* memory, int size,
+                                          int max_counters,
+                                          int max_threads) {
+  // Zero everything.
+  memset(memory, 0, size);
+
+  // Initialize the header.
+  TableHeader* header = static_cast<TableHeader*>(memory);
+  header->version = kTableVersion;
+  header->size = size;
+  header->max_counters = max_counters;
+  header->max_threads = max_threads;
+}
+
+void StatsTable::Private::ComputeMappedPointers(void* memory) {
+  char* data = static_cast<char*>(memory);
+  int offset = 0;
+
+  table_header_ = reinterpret_cast<TableHeader*>(data);
+  offset += sizeof(*table_header_);
+  offset += AlignOffset(offset);
+
+  // Verify we're looking at a valid StatsTable.
+  DCHECK_EQ(table_header_->version, kTableVersion);
+
+  thread_names_table_ = reinterpret_cast<char*>(data + offset);
+  offset += sizeof(char) *
+            max_threads() * StatsTable::kMaxThreadNameLength;
+  offset += AlignOffset(offset);
+
+  thread_tid_table_ = reinterpret_cast<PlatformThreadId*>(data + offset);
+  offset += sizeof(int) * max_threads();
+  offset += AlignOffset(offset);
+
+  thread_pid_table_ = reinterpret_cast<int*>(data + offset);
+  offset += sizeof(int) * max_threads();
+  offset += AlignOffset(offset);
+
+  counter_names_table_ = reinterpret_cast<char*>(data + offset);
+  offset += sizeof(char) *
+            max_counters() * StatsTable::kMaxCounterNameLength;
+  offset += AlignOffset(offset);
+
+  data_table_ = reinterpret_cast<int*>(data + offset);
+  offset += sizeof(int) * max_threads() * max_counters();
+
+  DCHECK_EQ(offset, size());
+}
+
+// TLSData carries the data stored in the TLS slots for the
+// StatsTable.  This is used so that we can properly cleanup when the
+// thread exits and return the table slot.
+//
+// Each thread that calls RegisterThread in the StatsTable will have
+// a TLSData stored in its TLS.
+struct StatsTable::TLSData {
+  StatsTable* table;
+  int slot;
+};
+
+// We keep a singleton table which can be easily accessed.
+StatsTable* StatsTable::global_table_ = NULL;
+
+StatsTable::StatsTable(const std::string& name, int max_threads,
+                       int max_counters)
+    : impl_(NULL),
+      tls_index_(SlotReturnFunction) {
+  int table_size =
+    AlignedSize(sizeof(Private::TableHeader)) +
+    AlignedSize((max_counters * sizeof(char) * kMaxCounterNameLength)) +
+    AlignedSize((max_threads * sizeof(char) * kMaxThreadNameLength)) +
+    AlignedSize(max_threads * sizeof(int)) +
+    AlignedSize(max_threads * sizeof(int)) +
+    AlignedSize((sizeof(int) * (max_counters * max_threads)));
+
+  impl_ = Private::New(name, table_size, max_threads, max_counters);
+
+  if (!impl_)
+    DPLOG(ERROR) << "StatsTable did not initialize";
+}
+
+StatsTable::~StatsTable() {
+  // Before we tear down our copy of the table, be sure to
+  // unregister our thread.
+  UnregisterThread();
+
+  // Return ThreadLocalStorage.  At this point, if any registered threads
+  // still exist, they cannot Unregister.
+  tls_index_.Free();
+
+  // Cleanup our shared memory.
+  delete impl_;
+
+  // If we are the global table, unregister ourselves.
+  if (global_table_ == this)
+    global_table_ = NULL;
+}
+
+int StatsTable::GetSlot() const {
+  TLSData* data = GetTLSData();
+  if (!data)
+    return 0;
+  return data->slot;
+}
+
+int StatsTable::RegisterThread(const std::string& name) {
+  int slot = 0;
+  if (!impl_)
+    return 0;
+
+  // Registering a thread requires that we lock the shared memory
+  // so that two threads don't grab the same slot.  Fortunately,
+  // thread creation shouldn't happen in inner loops.
+  {
+    SharedMemoryAutoLock lock(impl_->shared_memory());
+    slot = FindEmptyThread();
+    if (!slot) {
+      return 0;
+    }
+
+    // We have space, so consume a column in the table.
+    std::string thread_name = name;
+    if (name.empty())
+      thread_name = kUnknownName;
+    strlcpy(impl_->thread_name(slot), thread_name.c_str(),
+            kMaxThreadNameLength);
+    *(impl_->thread_tid(slot)) = PlatformThread::CurrentId();
+    *(impl_->thread_pid(slot)) = GetCurrentProcId();
+  }
+
+  // Set our thread local storage.
+  TLSData* data = new TLSData;
+  data->table = this;
+  data->slot = slot;
+  tls_index_.Set(data);
+  return slot;
+}
+
+int StatsTable::CountThreadsRegistered() const {
+  if (!impl_)
+    return 0;
+
+  // Loop through the shared memory and count the threads that are active.
+  // We intentionally do not lock the table during the operation.
+  int count = 0;
+  for (int index = 1; index <= impl_->max_threads(); index++) {
+    char* name = impl_->thread_name(index);
+    if (*name != '\0')
+      count++;
+  }
+  return count;
+}
+
+int StatsTable::FindCounter(const std::string& name) {
+  // Note: the API returns counters numbered from 1..N, although
+  // internally, the array is 0..N-1.  This is so that we can return
+  // zero as "not found".
+  if (!impl_)
+    return 0;
+
+  // Create a scope for our auto-lock.
+  {
+    AutoLock scoped_lock(counters_lock_);
+
+    // Attempt to find the counter.
+    CountersMap::const_iterator iter;
+    iter = counters_.find(name);
+    if (iter != counters_.end())
+      return iter->second;
+  }
+
+  // Counter does not exist, so add it.
+  return AddCounter(name);
+}
+
+int* StatsTable::GetLocation(int counter_id, int slot_id) const {
+  if (!impl_)
+    return NULL;
+  if (slot_id > impl_->max_threads())
+    return NULL;
+
+  int* row = impl_->row(counter_id);
+  return &(row[slot_id-1]);
+}
+
+const char* StatsTable::GetRowName(int index) const {
+  if (!impl_)
+    return NULL;
+
+  return impl_->counter_name(index);
+}
+
+int StatsTable::GetRowValue(int index) const {
+  return GetRowValue(index, 0);
+}
+
+int StatsTable::GetRowValue(int index, int pid) const {
+  if (!impl_)
+    return 0;
+
+  int rv = 0;
+  int* row = impl_->row(index);
+  for (int slot_id = 0; slot_id < impl_->max_threads(); slot_id++) {
+    if (pid == 0 || *impl_->thread_pid(slot_id) == pid)
+      rv += row[slot_id];
+  }
+  return rv;
+}
+
+int StatsTable::GetCounterValue(const std::string& name) {
+  return GetCounterValue(name, 0);
+}
+
+int StatsTable::GetCounterValue(const std::string& name, int pid) {
+  if (!impl_)
+    return 0;
+
+  int row = FindCounter(name);
+  if (!row)
+    return 0;
+  return GetRowValue(row, pid);
+}
+
+int StatsTable::GetMaxCounters() const {
+  if (!impl_)
+    return 0;
+  return impl_->max_counters();
+}
+
+int StatsTable::GetMaxThreads() const {
+  if (!impl_)
+    return 0;
+  return impl_->max_threads();
+}
+
+int* StatsTable::FindLocation(const char* name) {
+  // Get the static StatsTable
+  StatsTable *table = StatsTable::current();
+  if (!table)
+    return NULL;
+
+  // Get the slot for this thread.  Try to register
+  // it if none exists.
+  int slot = table->GetSlot();
+  if (!slot && !(slot = table->RegisterThread("")))
+      return NULL;
+
+  // Find the counter id for the counter.
+  std::string str_name(name);
+  int counter = table->FindCounter(str_name);
+
+  // Now we can find the location in the table.
+  return table->GetLocation(counter, slot);
+}
+
+void StatsTable::UnregisterThread() {
+  UnregisterThread(GetTLSData());
+}
+
+void StatsTable::UnregisterThread(TLSData* data) {
+  if (!data)
+    return;
+  DCHECK(impl_);
+
+  // Mark the slot free by zeroing out the thread name.
+  char* name = impl_->thread_name(data->slot);
+  *name = '\0';
+
+  // Remove the calling thread's TLS so that it cannot use the slot.
+  tls_index_.Set(NULL);
+  delete data;
+}
+
+void StatsTable::SlotReturnFunction(void* data) {
+  // This is called by the TLS destructor, which on some platforms has
+  // already cleared the TLS info, so use the tls_data argument
+  // rather than trying to fetch it ourselves.
+  TLSData* tls_data = static_cast<TLSData*>(data);
+  if (tls_data) {
+    DCHECK(tls_data->table);
+    tls_data->table->UnregisterThread(tls_data);
+  }
+}
+
+int StatsTable::FindEmptyThread() const {
+  // Note: the API returns slots numbered from 1..N, although
+  // internally, the array is 0..N-1.  This is so that we can return
+  // zero as "not found".
+  //
+  // The reason for doing this is because the thread 'slot' is stored
+  // in TLS, which is always initialized to zero, not -1.  If 0 were
+  // returned as a valid slot number, it would be confused with the
+  // uninitialized state.
+  if (!impl_)
+    return 0;
+
+  int index = 1;
+  for (; index <= impl_->max_threads(); index++) {
+    char* name = impl_->thread_name(index);
+    if (!*name)
+      break;
+  }
+  if (index > impl_->max_threads())
+    return 0;  // The table is full.
+  return index;
+}
+
+int StatsTable::FindCounterOrEmptyRow(const std::string& name) const {
+  // Note: the API returns slots numbered from 1..N, although
+  // internally, the array is 0..N-1.  This is so that we can return
+  // zero as "not found".
+  //
+  // There isn't much reason for this other than to be consistent
+  // with the way we track columns for thread slots.  (See comments
+  // in FindEmptyThread for why it is done this way).
+  if (!impl_)
+    return 0;
+
+  int free_slot = 0;
+  for (int index = 1; index <= impl_->max_counters(); index++) {
+    char* row_name = impl_->counter_name(index);
+    if (!*row_name && !free_slot)
+      free_slot = index;  // save that we found a free slot
+    else if (!strncmp(row_name, name.c_str(), kMaxCounterNameLength))
+      return index;
+  }
+  return free_slot;
+}
+
+int StatsTable::AddCounter(const std::string& name) {
+  if (!impl_)
+    return 0;
+
+  int counter_id = 0;
+  {
+    // To add a counter to the shared memory, we need the
+    // shared memory lock.
+    SharedMemoryAutoLock lock(impl_->shared_memory());
+
+    // We have space, so create a new counter.
+    counter_id = FindCounterOrEmptyRow(name);
+    if (!counter_id)
+      return 0;
+
+    std::string counter_name = name;
+    if (name.empty())
+      counter_name = kUnknownName;
+    strlcpy(impl_->counter_name(counter_id), counter_name.c_str(),
+            kMaxCounterNameLength);
+  }
+
+  // now add to our in-memory cache
+  {
+    AutoLock lock(counters_lock_);
+    counters_[name] = counter_id;
+  }
+  return counter_id;
+}
+
+StatsTable::TLSData* StatsTable::GetTLSData() const {
+  TLSData* data =
+    static_cast<TLSData*>(tls_index_.Get());
+  if (!data)
+    return NULL;
+
+  DCHECK(data->slot);
+  DCHECK_EQ(data->table, this);
+  return data;
+}
+
+}  // namespace base
diff --git a/base/metrics/stats_table.h b/base/metrics/stats_table.h
new file mode 100644
index 0000000..d972e7c
--- /dev/null
+++ b/base/metrics/stats_table.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.
+//
+// A StatsTable is a table of statistics.  It can be used across multiple
+// processes and threads, maintaining cheap statistics counters without
+// locking.
+//
+// The goal is to make it very cheap and easy for developers to add
+// counters to code, without having to build one-off utilities or mechanisms
+// to track the counters, and also to allow a single "view" to display
+// the contents of all counters.
+//
+// To achieve this, StatsTable creates a shared memory segment to store
+// the data for the counters.  Upon creation, it has a specific size
+// which governs the maximum number of counters and concurrent
+// threads/processes which can use it.
+//
+
+#ifndef BASE_METRICS_STATS_TABLE_H_
+#define BASE_METRICS_STATS_TABLE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_local_storage.h"
+
+namespace base {
+
+class BASE_EXPORT StatsTable {
+ public:
+  // Create a new StatsTable.
+  // If a StatsTable already exists with the specified name, this StatsTable
+  // will use the same shared memory segment as the original.  Otherwise,
+  // a new StatsTable is created and all counters are zeroed.
+  //
+  // name is the name of the StatsTable to use.
+  //
+  // max_threads is the maximum number of threads the table will support.
+  // If the StatsTable already exists, this number is ignored.
+  //
+  // max_counters is the maximum number of counters the table will support.
+  // If the StatsTable already exists, this number is ignored.
+  StatsTable(const std::string& name, int max_threads, int max_counters);
+
+  // Destroys the StatsTable.  When the last StatsTable is destroyed
+  // (across all processes), the StatsTable is removed from disk.
+  ~StatsTable();
+
+  // For convenience, we create a static table.  This is generally
+  // used automatically by the counters.
+  static StatsTable* current() { return global_table_; }
+
+  // Set the global table for use in this process.
+  static void set_current(StatsTable* value) { global_table_ = value; }
+
+  // Get the slot id for the calling thread. Returns 0 if no
+  // slot is assigned.
+  int GetSlot() const;
+
+  // All threads that contribute data to the table must register with the
+  // table first.  This function will set thread local storage for the
+  // thread containing the location in the table where this thread will
+  // write its counter data.
+  //
+  // name is just a debugging tag to label the thread, and it does not
+  // need to be unique.  It will be truncated to kMaxThreadNameLength-1
+  // characters.
+  //
+  // On success, returns the slot id for this thread.  On failure,
+  // returns 0.
+  int RegisterThread(const std::string& name);
+
+  // Returns the number of threads currently registered.  This is really not
+  // useful except for diagnostics and debugging.
+  int CountThreadsRegistered() const;
+
+  // Find a counter in the StatsTable.
+  //
+  // Returns an id for the counter which can be used to call GetLocation().
+  // If the counter does not exist, attempts to create a row for the new
+  // counter.  If there is no space in the table for the new counter,
+  // returns 0.
+  int FindCounter(const std::string& name);
+
+  // TODO(mbelshe): implement RemoveCounter.
+
+  // Gets the location of a particular value in the table based on
+  // the counter id and slot id.
+  int* GetLocation(int counter_id, int slot_id) const;
+
+  // Gets the counter name at a particular row.  If the row is empty,
+  // returns NULL.
+  const char* GetRowName(int index) const;
+
+  // Gets the sum of the values for a particular row.
+  int GetRowValue(int index) const;
+
+  // Gets the sum of the values for a particular row for a given pid.
+  int GetRowValue(int index, int pid) const;
+
+  // Gets the sum of the values for a particular counter.  If the counter
+  // does not exist, creates the counter.
+  int GetCounterValue(const std::string& name);
+
+  // Gets the sum of the values for a particular counter for a given pid.
+  // If the counter does not exist, creates the counter.
+  int GetCounterValue(const std::string& name, int pid);
+
+  // The maxinum number of counters/rows in the table.
+  int GetMaxCounters() const;
+
+  // The maxinum number of threads/columns in the table.
+  int GetMaxThreads() const;
+
+  // The maximum length (in characters) of a Thread's name including
+  // null terminator, as stored in the shared memory.
+  static const int kMaxThreadNameLength = 32;
+
+  // The maximum length (in characters) of a Counter's name including
+  // null terminator, as stored in the shared memory.
+  static const int kMaxCounterNameLength = 64;
+
+  // Convenience function to lookup a counter location for a
+  // counter by name for the calling thread.  Will register
+  // the thread if it is not already registered.
+  static int* FindLocation(const char *name);
+
+ private:
+  class Private;
+  struct TLSData;
+  typedef hash_map<std::string, int> CountersMap;
+
+  // Returns the space occupied by a thread in the table.  Generally used
+  // if a thread terminates but the process continues.  This function
+  // does not zero out the thread's counters.
+  // Cannot be used inside a posix tls destructor.
+  void UnregisterThread();
+
+  // This variant expects the tls data to be passed in, so it is safe to
+  // call from inside a posix tls destructor (see doc for pthread_key_create).
+  void UnregisterThread(TLSData* tls_data);
+
+  // The SlotReturnFunction is called at thread exit for each thread
+  // which used the StatsTable.
+  static void SlotReturnFunction(void* data);
+
+  // Locates a free slot in the table.  Returns a number > 0 on success,
+  // or 0 on failure.  The caller must hold the shared_memory lock when
+  // calling this function.
+  int FindEmptyThread() const;
+
+  // Locates a counter in the table or finds an empty row.  Returns a
+  // number > 0 on success, or 0 on failure.  The caller must hold the
+  // shared_memory_lock when calling this function.
+  int FindCounterOrEmptyRow(const std::string& name) const;
+
+  // Internal function to add a counter to the StatsTable.  Assumes that
+  // the counter does not already exist in the table.
+  //
+  // name is a unique identifier for this counter, and will be truncated
+  // to kMaxCounterNameLength-1 characters.
+  //
+  // On success, returns the counter_id for the newly added counter.
+  // On failure, returns 0.
+  int AddCounter(const std::string& name);
+
+  // Get the TLS data for the calling thread.  Returns NULL if none is
+  // initialized.
+  TLSData* GetTLSData() const;
+
+  Private* impl_;
+
+  // The counters_lock_ protects the counters_ hash table.
+  base::Lock counters_lock_;
+
+  // The counters_ hash map is an in-memory hash of the counters.
+  // It is used for quick lookup of counters, but is cannot be used
+  // as a substitute for what is in the shared memory.  Even though
+  // we don't have a counter in our hash table, another process may
+  // have created it.
+  CountersMap counters_;
+  ThreadLocalStorage::Slot tls_index_;
+
+  static StatsTable* global_table_;
+
+  DISALLOW_COPY_AND_ASSIGN(StatsTable);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_STATS_TABLE_H_
diff --git a/base/metrics/stats_table_unittest.cc b/base/metrics/stats_table_unittest.cc
new file mode 100644
index 0000000..579bab7
--- /dev/null
+++ b/base/metrics/stats_table_unittest.cc
@@ -0,0 +1,423 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/stats_counters.h"
+#include "base/metrics/stats_table.h"
+#include "base/shared_memory.h"
+#include "base/stringprintf.h"
+#include "base/string_piece.h"
+#include "base/test/multiprocess_test.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/simple_thread.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+
+class StatsTableTest : public MultiProcessTest {
+ public:
+  void DeleteShmem(const std::string& name) {
+    SharedMemory mem;
+    mem.Delete(name);
+  }
+};
+
+// Open a StatsTable and verify that we can write to each of the
+// locations in the table.
+TEST_F(StatsTableTest, VerifySlots) {
+  const std::string kTableName = "VerifySlotsStatTable";
+  const int kMaxThreads = 1;
+  const int kMaxCounter = 5;
+  DeleteShmem(kTableName);
+  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+
+  // Register a single thread.
+  std::string thread_name = "mainThread";
+  int slot_id = table.RegisterThread(thread_name);
+  EXPECT_NE(slot_id, 0);
+
+  // Fill up the table with counters.
+  std::string counter_base_name = "counter";
+  for (int index = 0; index < kMaxCounter; index++) {
+    std::string counter_name = counter_base_name;
+    base::StringAppendF(&counter_name, "counter.ctr%d", index);
+    int counter_id = table.FindCounter(counter_name);
+    EXPECT_GT(counter_id, 0);
+  }
+
+  // Try to allocate an additional thread.  Verify it fails.
+  slot_id = table.RegisterThread("too many threads");
+  EXPECT_EQ(slot_id, 0);
+
+  // Try to allocate an additional counter.  Verify it fails.
+  int counter_id = table.FindCounter(counter_base_name);
+  EXPECT_EQ(counter_id, 0);
+
+  DeleteShmem(kTableName);
+}
+
+// CounterZero will continually be set to 0.
+const std::string kCounterZero = "CounterZero";
+// Counter1313 will continually be set to 1313.
+const std::string kCounter1313 = "Counter1313";
+// CounterIncrement will be incremented each time.
+const std::string kCounterIncrement = "CounterIncrement";
+// CounterDecrement will be decremented each time.
+const std::string kCounterDecrement = "CounterDecrement";
+// CounterMixed will be incremented by odd numbered threads and
+// decremented by even threads.
+const std::string kCounterMixed = "CounterMixed";
+// The number of thread loops that we will do.
+const int kThreadLoops = 100;
+
+class StatsTableThread : public SimpleThread {
+ public:
+  StatsTableThread(std::string name, int id)
+      : SimpleThread(name),
+        id_(id) {}
+
+  virtual void Run() OVERRIDE;
+
+ private:
+  int id_;
+};
+
+void StatsTableThread::Run() {
+  // Each thread will open the shared memory and set counters
+  // concurrently in a loop.  We'll use some pauses to
+  // mixup the thread scheduling.
+
+  StatsCounter zero_counter(kCounterZero);
+  StatsCounter lucky13_counter(kCounter1313);
+  StatsCounter increment_counter(kCounterIncrement);
+  StatsCounter decrement_counter(kCounterDecrement);
+  for (int index = 0; index < kThreadLoops; index++) {
+    StatsCounter mixed_counter(kCounterMixed);  // create this one in the loop
+    zero_counter.Set(0);
+    lucky13_counter.Set(1313);
+    increment_counter.Increment();
+    decrement_counter.Decrement();
+    if (id_ % 2)
+      mixed_counter.Decrement();
+    else
+      mixed_counter.Increment();
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10));
+  }
+}
+
+// Create a few threads and have them poke on their counters.
+// See http://crbug.com/10611 for more information.
+#if defined(OS_MACOSX)
+#define MAYBE_MultipleThreads DISABLED_MultipleThreads
+#else
+#define MAYBE_MultipleThreads MultipleThreads
+#endif
+TEST_F(StatsTableTest, MAYBE_MultipleThreads) {
+  // Create a stats table.
+  const std::string kTableName = "MultipleThreadStatTable";
+  const int kMaxThreads = 20;
+  const int kMaxCounter = 5;
+  DeleteShmem(kTableName);
+  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+  StatsTable::set_current(&table);
+
+  EXPECT_EQ(0, table.CountThreadsRegistered());
+
+  // Spin up a set of threads to go bang on the various counters.
+  // After we join the threads, we'll make sure the counters
+  // contain the values we expected.
+  StatsTableThread* threads[kMaxThreads];
+
+  // Spawn the threads.
+  for (int index = 0; index < kMaxThreads; index++) {
+    threads[index] = new StatsTableThread("MultipleThreadsTest", index);
+    threads[index]->Start();
+  }
+
+  // Wait for the threads to finish.
+  for (int index = 0; index < kMaxThreads; index++) {
+    threads[index]->Join();
+    delete threads[index];
+  }
+
+  StatsCounter zero_counter(kCounterZero);
+  StatsCounter lucky13_counter(kCounter1313);
+  StatsCounter increment_counter(kCounterIncrement);
+  StatsCounter decrement_counter(kCounterDecrement);
+  StatsCounter mixed_counter(kCounterMixed);
+
+  // Verify the various counters are correct.
+  std::string name;
+  name = "c:" + kCounterZero;
+  EXPECT_EQ(0, table.GetCounterValue(name));
+  name = "c:" + kCounter1313;
+  EXPECT_EQ(1313 * kMaxThreads,
+      table.GetCounterValue(name));
+  name = "c:" + kCounterIncrement;
+  EXPECT_EQ(kMaxThreads * kThreadLoops,
+      table.GetCounterValue(name));
+  name = "c:" + kCounterDecrement;
+  EXPECT_EQ(-kMaxThreads * kThreadLoops,
+      table.GetCounterValue(name));
+  name = "c:" + kCounterMixed;
+  EXPECT_EQ((kMaxThreads % 2) * kThreadLoops,
+      table.GetCounterValue(name));
+  EXPECT_EQ(0, table.CountThreadsRegistered());
+
+  DeleteShmem(kTableName);
+}
+
+const std::string kMPTableName = "MultipleProcessStatTable";
+
+MULTIPROCESS_TEST_MAIN(StatsTableMultipleProcessMain) {
+  // Each process will open the shared memory and set counters
+  // concurrently in a loop.  We'll use some pauses to
+  // mixup the scheduling.
+
+  StatsTable table(kMPTableName, 0, 0);
+  StatsTable::set_current(&table);
+  StatsCounter zero_counter(kCounterZero);
+  StatsCounter lucky13_counter(kCounter1313);
+  StatsCounter increment_counter(kCounterIncrement);
+  StatsCounter decrement_counter(kCounterDecrement);
+  for (int index = 0; index < kThreadLoops; index++) {
+    zero_counter.Set(0);
+    lucky13_counter.Set(1313);
+    increment_counter.Increment();
+    decrement_counter.Decrement();
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10));
+  }
+  return 0;
+}
+
+// Create a few processes and have them poke on their counters.
+// This test is slow and flaky http://crbug.com/10611
+TEST_F(StatsTableTest, DISABLED_MultipleProcesses) {
+  // Create a stats table.
+  const int kMaxProcs = 20;
+  const int kMaxCounter = 5;
+  DeleteShmem(kMPTableName);
+  StatsTable table(kMPTableName, kMaxProcs, kMaxCounter);
+  StatsTable::set_current(&table);
+  EXPECT_EQ(0, table.CountThreadsRegistered());
+
+  // Spin up a set of processes to go bang on the various counters.
+  // After we join the processes, we'll make sure the counters
+  // contain the values we expected.
+  ProcessHandle procs[kMaxProcs];
+
+  // Spawn the processes.
+  for (int16 index = 0; index < kMaxProcs; index++) {
+    procs[index] = this->SpawnChild("StatsTableMultipleProcessMain", false);
+    EXPECT_NE(kNullProcessHandle, procs[index]);
+  }
+
+  // Wait for the processes to finish.
+  for (int index = 0; index < kMaxProcs; index++) {
+    EXPECT_TRUE(WaitForSingleProcess(
+        procs[index], base::TimeDelta::FromMinutes(1)));
+    CloseProcessHandle(procs[index]);
+  }
+
+  StatsCounter zero_counter(kCounterZero);
+  StatsCounter lucky13_counter(kCounter1313);
+  StatsCounter increment_counter(kCounterIncrement);
+  StatsCounter decrement_counter(kCounterDecrement);
+
+  // Verify the various counters are correct.
+  std::string name;
+  name = "c:" + kCounterZero;
+  EXPECT_EQ(0, table.GetCounterValue(name));
+  name = "c:" + kCounter1313;
+  EXPECT_EQ(1313 * kMaxProcs,
+      table.GetCounterValue(name));
+  name = "c:" + kCounterIncrement;
+  EXPECT_EQ(kMaxProcs * kThreadLoops,
+      table.GetCounterValue(name));
+  name = "c:" + kCounterDecrement;
+  EXPECT_EQ(-kMaxProcs * kThreadLoops,
+      table.GetCounterValue(name));
+  EXPECT_EQ(0, table.CountThreadsRegistered());
+
+  DeleteShmem(kMPTableName);
+}
+
+class MockStatsCounter : public StatsCounter {
+ public:
+  explicit MockStatsCounter(const std::string& name)
+      : StatsCounter(name) {}
+  int* Pointer() { return GetPtr(); }
+};
+
+// Test some basic StatsCounter operations
+TEST_F(StatsTableTest, StatsCounter) {
+  // Create a stats table.
+  const std::string kTableName = "StatTable";
+  const int kMaxThreads = 20;
+  const int kMaxCounter = 5;
+  DeleteShmem(kTableName);
+  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+  StatsTable::set_current(&table);
+
+  MockStatsCounter foo("foo");
+
+  // Test initial state.
+  EXPECT_TRUE(foo.Enabled());
+  ASSERT_NE(foo.Pointer(), static_cast<int*>(0));
+  EXPECT_EQ(0, *(foo.Pointer()));
+  EXPECT_EQ(0, table.GetCounterValue("c:foo"));
+
+  // Test Increment.
+  while (*(foo.Pointer()) < 123) foo.Increment();
+  EXPECT_EQ(123, table.GetCounterValue("c:foo"));
+  foo.Add(0);
+  EXPECT_EQ(123, table.GetCounterValue("c:foo"));
+  foo.Add(-1);
+  EXPECT_EQ(122, table.GetCounterValue("c:foo"));
+
+  // Test Set.
+  foo.Set(0);
+  EXPECT_EQ(0, table.GetCounterValue("c:foo"));
+  foo.Set(100);
+  EXPECT_EQ(100, table.GetCounterValue("c:foo"));
+  foo.Set(-1);
+  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
+  foo.Set(0);
+  EXPECT_EQ(0, table.GetCounterValue("c:foo"));
+
+  // Test Decrement.
+  foo.Subtract(1);
+  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
+  foo.Subtract(0);
+  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
+  foo.Subtract(-1);
+  EXPECT_EQ(0, table.GetCounterValue("c:foo"));
+
+  DeleteShmem(kTableName);
+}
+
+class MockStatsCounterTimer : public StatsCounterTimer {
+ public:
+  explicit MockStatsCounterTimer(const std::string& name)
+      : StatsCounterTimer(name) {}
+
+  TimeTicks start_time() { return start_time_; }
+  TimeTicks stop_time() { return stop_time_; }
+};
+
+// Test some basic StatsCounterTimer operations
+TEST_F(StatsTableTest, StatsCounterTimer) {
+  // Create a stats table.
+  const std::string kTableName = "StatTable";
+  const int kMaxThreads = 20;
+  const int kMaxCounter = 5;
+  DeleteShmem(kTableName);
+  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+  StatsTable::set_current(&table);
+
+  MockStatsCounterTimer bar("bar");
+
+  // Test initial state.
+  EXPECT_FALSE(bar.Running());
+  EXPECT_TRUE(bar.start_time().is_null());
+  EXPECT_TRUE(bar.stop_time().is_null());
+
+  const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);
+
+  // Do some timing.
+  bar.Start();
+  PlatformThread::Sleep(kDuration);
+  bar.Stop();
+  EXPECT_GT(table.GetCounterValue("t:bar"), 0);
+  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar"));
+
+  // Verify that timing again is additive.
+  bar.Start();
+  PlatformThread::Sleep(kDuration);
+  bar.Stop();
+  EXPECT_GT(table.GetCounterValue("t:bar"), 0);
+  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar"));
+  DeleteShmem(kTableName);
+}
+
+// Test some basic StatsRate operations
+TEST_F(StatsTableTest, StatsRate) {
+  // Create a stats table.
+  const std::string kTableName = "StatTable";
+  const int kMaxThreads = 20;
+  const int kMaxCounter = 5;
+  DeleteShmem(kTableName);
+  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+  StatsTable::set_current(&table);
+
+  StatsRate baz("baz");
+
+  // Test initial state.
+  EXPECT_FALSE(baz.Running());
+  EXPECT_EQ(0, table.GetCounterValue("c:baz"));
+  EXPECT_EQ(0, table.GetCounterValue("t:baz"));
+
+  const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);
+
+  // Do some timing.
+  baz.Start();
+  PlatformThread::Sleep(kDuration);
+  baz.Stop();
+  EXPECT_EQ(1, table.GetCounterValue("c:baz"));
+  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:baz"));
+
+  // Verify that timing again is additive.
+  baz.Start();
+  PlatformThread::Sleep(kDuration);
+  baz.Stop();
+  EXPECT_EQ(2, table.GetCounterValue("c:baz"));
+  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:baz"));
+  DeleteShmem(kTableName);
+}
+
+// Test some basic StatsScope operations
+TEST_F(StatsTableTest, StatsScope) {
+  // Create a stats table.
+  const std::string kTableName = "StatTable";
+  const int kMaxThreads = 20;
+  const int kMaxCounter = 5;
+  DeleteShmem(kTableName);
+  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
+  StatsTable::set_current(&table);
+
+  StatsCounterTimer foo("foo");
+  StatsRate bar("bar");
+
+  // Test initial state.
+  EXPECT_EQ(0, table.GetCounterValue("t:foo"));
+  EXPECT_EQ(0, table.GetCounterValue("t:bar"));
+  EXPECT_EQ(0, table.GetCounterValue("c:bar"));
+
+  const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);
+
+  // Try a scope.
+  {
+    StatsScope<StatsCounterTimer> timer(foo);
+    StatsScope<StatsRate> timer2(bar);
+    PlatformThread::Sleep(kDuration);
+  }
+  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:foo"));
+  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar"));
+  EXPECT_EQ(1, table.GetCounterValue("c:bar"));
+
+  // Try a second scope.
+  {
+    StatsScope<StatsCounterTimer> timer(foo);
+    StatsScope<StatsRate> timer2(bar);
+    PlatformThread::Sleep(kDuration);
+  }
+  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:foo"));
+  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar"));
+  EXPECT_EQ(2, table.GetCounterValue("c:bar"));
+
+  DeleteShmem(kTableName);
+}
+
+}  // namespace base
diff --git a/base/move.h b/base/move.h
new file mode 100644
index 0000000..7fcb8dd
--- /dev/null
+++ b/base/move.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MOVE_H_
+#define BASE_MOVE_H_
+
+// Macro with the boilerplate that makes a type move-only in C++03.
+//
+// USAGE
+//
+// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create
+// a "move-only" type.  Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be
+// the first line in a class declaration.
+//
+// A class using this macro must call .Pass() (or somehow be an r-value already)
+// before it can be:
+//
+//   * Passed as a function argument
+//   * Used as the right-hand side of an assignment
+//   * Returned from a function
+//
+// Each class will still need to define their own "move constructor" and "move
+// operator=" to make this useful.  Here's an example of the macro, the move
+// constructor, and the move operator= from the scoped_ptr class:
+//
+//  template <typename T>
+//  class scoped_ptr {
+//     MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+//   public:
+//    scoped_ptr(RValue& other) : ptr_(other.release()) { }
+//    scoped_ptr& operator=(RValue& other) {
+//      swap(other);
+//      return *this;
+//    }
+//  };
+//
+// Note that the constructor must NOT be marked explicit.
+//
+// For consistency, the second parameter to the macro should always be RValue
+// unless you have a strong reason to do otherwise.  It is only exposed as a
+// macro parameter so that the move constructor and move operator= don't look
+// like they're using a phantom type.
+//
+//
+// HOW THIS WORKS
+//
+// For a thorough explanation of this technique, see:
+//
+//   http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
+//
+// The summary is that we take advantage of 2 properties:
+//
+//   1) non-const references will not bind to r-values.
+//   2) C++ can apply one user-defined conversion when initializing a
+//      variable.
+//
+// The first lets us disable the copy constructor and assignment operator
+// by declaring private version of them with a non-const reference parameter.
+//
+// For l-values, direct initialization still fails like in
+// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment
+// operators are private.
+//
+// For r-values, the situation is different. The copy constructor and
+// assignment operator are not viable due to (1), so we are trying to call
+// a non-existent constructor and non-existing operator= rather than a private
+// one.  Since we have not committed an error quite yet, we can provide an
+// alternate conversion sequence and a constructor.  We add
+//
+//   * a private struct named "RValue"
+//   * a user-defined conversion "operator RValue()"
+//   * a "move constructor" and "move operator=" that take the RValue& as
+//     their sole parameter.
+//
+// Only r-values will trigger this sequence and execute our "move constructor"
+// or "move operator=."  L-values will match the private copy constructor and
+// operator= first giving a "private in this context" error.  This combination
+// gives us a move-only type.
+//
+// For signaling a destructive transfer of data from an l-value, we provide a
+// method named Pass() which creates an r-value for the current instance
+// triggering the move constructor or move operator=.
+//
+// Other ways to get r-values is to use the result of an expression like a
+// function call.
+//
+// Here's an example with comments explaining what gets triggered where:
+//
+//    class Foo {
+//      MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue);
+//
+//     public:
+//       ... API ...
+//       Foo(RValue other);           // Move constructor.
+//       Foo& operator=(RValue rhs);  // Move operator=
+//    };
+//
+//    Foo MakeFoo();  // Function that returns a Foo.
+//
+//    Foo f;
+//    Foo f_copy(f);  // ERROR: Foo(Foo&) is private in this context.
+//    Foo f_assign;
+//    f_assign = f;   // ERROR: operator=(Foo&) is private in this context.
+//
+//
+//    Foo f(MakeFoo());      // R-value so alternate conversion executed.
+//    Foo f_copy(f.Pass());  // R-value so alternate conversion executed.
+//    f = f_copy.Pass();     // R-value so alternate conversion executed.
+//
+//
+// IMPLEMENTATION SUBTLETIES WITH RValue
+//
+// The RValue struct is just a container for a pointer back to the original
+// object. It should only ever be created as a temporary, and no external
+// class should ever declare it or use it in a parameter.
+//
+// It is tempting to want to use the RValue type in function parameters, but
+// excluding the limited usage here for the move constructor and move
+// operator=, doing so would mean that the function could take both r-values
+// and l-values equially which is unexpected.  See COMPARED To Boost.Move for
+// more details.
+//
+// An alternate, and incorrect, implementation of the RValue class used by
+// Boost.Move makes RValue a fieldless child of the move-only type. RValue&
+// is then used in place of RValue in the various operators.  The RValue& is
+// "created" by doing *reinterpret_cast<RValue*>(this).  This has the appeal
+// of never creating a temproary RValue struct even with optimizations
+// disabled.  Also, by virtue of inheritance you can treat the RValue
+// reference as if it were the move-only type itself.  Unfortuantely,
+// using the result of this reinterpret_cast<> is actually undefined behavior
+// due to C++98 5.2.10.7. In certain compilers (eg., NaCl) the optimizer
+// will generate non-working code.
+//
+// In optimized builds, both implementations generate the same assembly so we
+// choose the one that adheres to the standard. ☃
+//
+//
+// COMPARED TO C++11
+//
+// In C++11, you would implement this functionality using an r-value reference
+// and our .Pass() method would be replaced with a call to std::move().
+//
+// This emulation also has a deficiency where it uses up the single
+// user-defined conversion allowed by C++ during initialization.  This can
+// cause problems in some API edge cases.  For instance, in scoped_ptr, it is
+// impossible to make an function "void Foo(scoped_ptr<Parent> p)" accept a
+// value of type scoped_ptr<Child> even if you add a constructor to
+// scoped_ptr<> that would make it look like it should work.  C++11 does not
+// have this deficiency.
+//
+//
+// COMPARED TO Boost.Move
+//
+// Our implementation similar to Boost.Move, but we keep the RValue struct
+// private to the move-only type, and we don't use the reinterpret_cast<> hack.
+//
+// In Boost.Move, RValue is the boost::rv<> template.  This type can be used
+// when writing APIs like:
+//
+//   void MyFunc(boost::rv<Foo>& f)
+//
+// that can take advantage of rv<> to avoid extra copies of a type.  However you
+// would still be able to call this version of MyFunc with an l-value:
+//
+//   Foo f;
+//   MyFunc(f);  // Uh oh, we probably just destroyed |f| w/o calling Pass().
+//
+// unless someone is very careful to also declare a parallel override like:
+//
+//   void MyFunc(const Foo& f)
+//
+// that would catch the l-values first.  This was declared unsafe in C++11 and
+// a C++11 compiler will explicitly fail MyFunc(f).  Unfortunately, we cannot
+// ensure this in C++03.
+//
+// Since we have no need for writing such APIs yet, our implementation keeps
+// RValue private and uses a .Pass() method to do the conversion instead of
+// trying to write a version of "std::move()." Writing an API like std::move()
+// would require the RValue structs to be public.
+//
+//
+// CAVEATS
+//
+// If you include a move-only type as a field inside a class that does not
+// explicitly declare a copy constructor, the containing class's implicit
+// copy constructor will change from Containing(const Containing&) to
+// Containing(Containing&).  This can cause some unexpected errors.
+//
+//   http://llvm.org/bugs/show_bug.cgi?id=11528
+//
+// The workaround is to explicitly declare your copy constructor.
+//
+#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
+ private: \
+  struct rvalue_type { \
+    rvalue_type(type* object) : object(object) {} \
+    type* object; \
+  }; \
+  type(type&); \
+  void operator=(type&); \
+ public: \
+  operator rvalue_type() { return rvalue_type(this); } \
+  type Pass() { return type(rvalue_type(this)); } \
+ private:
+
+#endif  // BASE_MOVE_H_
diff --git a/base/native_library.h b/base/native_library.h
new file mode 100644
index 0000000..845989d
--- /dev/null
+++ b/base/native_library.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2011 The Chromium Authors. All 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 "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX)
+#import <CoreFoundation/CoreFoundation.h>
+#endif  // OS_*
+
+#include "base/string16.h"
+
+// Macro useful for writing cross-platform function pointers.
+#if defined(OS_WIN) && !defined(CDECL)
+#define CDECL __cdecl
+#else
+#define CDECL
+#endif
+
+class FilePath;
+
+namespace base {
+
+#if defined(OS_WIN)
+typedef HMODULE NativeLibrary;
+#elif defined(OS_MACOSX)
+enum NativeLibraryType {
+  BUNDLE,
+  DYNAMIC_LIB
+};
+struct NativeLibraryStruct {
+  NativeLibraryType type;
+  CFBundleRefNum bundle_resource_ref;
+  union {
+    CFBundleRef bundle;
+    void* dylib;
+  };
+};
+typedef NativeLibraryStruct* NativeLibrary;
+#elif defined(OS_POSIX)
+typedef void* NativeLibrary;
+#endif  // OS_*
+
+// Loads a native library from disk.  Release it with UnloadNativeLibrary when
+// you're done.  Returns NULL on failure.
+// If |err| is not NULL, it may be filled in with an error message on
+// error.
+BASE_EXPORT NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                            std::string* error);
+
+#if defined(OS_WIN)
+// Loads a native library from disk.  Release it with UnloadNativeLibrary when
+// you're done.
+// This function retrieves the LoadLibrary function exported from kernel32.dll
+// and calls it instead of directly calling the LoadLibrary function via the
+// import table.
+BASE_EXPORT NativeLibrary LoadNativeLibraryDynamically(
+    const FilePath& library_path);
+#endif  // OS_WIN
+
+// Unloads a native library.
+BASE_EXPORT void UnloadNativeLibrary(NativeLibrary library);
+
+// Gets a function pointer from a native library.
+BASE_EXPORT void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                                      const char* name);
+
+// Returns the full platform specific name for a native library.
+// For example:
+// "mylib" returns "mylib.dll" on Windows, "libmylib.so" on Linux,
+// "mylib.dylib" on Mac.
+BASE_EXPORT string16 GetNativeLibraryName(const string16& name);
+
+}  // namespace base
+
+#endif  // BASE_NATIVE_LIBRARY_H_
diff --git a/base/native_library_mac.mm b/base/native_library_mac.mm
new file mode 100644
index 0000000..9f7a967
--- /dev/null
+++ b/base/native_library_mac.mm
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/native_library.h"
+
+#include <dlfcn.h>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+// static
+NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                std::string* error) {
+  // dlopen() etc. open the file off disk.
+  if (library_path.Extension() == "dylib" ||
+      !file_util::DirectoryExists(library_path)) {
+    void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY);
+    if (!dylib)
+      return NULL;
+    NativeLibrary native_lib = new NativeLibraryStruct();
+    native_lib->type = DYNAMIC_LIB;
+    native_lib->dylib = dylib;
+    return native_lib;
+  }
+  base::mac::ScopedCFTypeRef<CFURLRef> url(
+      CFURLCreateFromFileSystemRepresentation(
+          kCFAllocatorDefault,
+          (const UInt8*)library_path.value().c_str(),
+          library_path.value().length(),
+          true));
+  if (!url)
+    return NULL;
+  CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get());
+  if (!bundle)
+    return NULL;
+
+  NativeLibrary native_lib = new NativeLibraryStruct();
+  native_lib->type = BUNDLE;
+  native_lib->bundle = bundle;
+  native_lib->bundle_resource_ref = CFBundleOpenBundleResourceMap(bundle);
+  return native_lib;
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  if (library->type == BUNDLE) {
+    CFBundleCloseBundleResourceMap(library->bundle,
+                                   library->bundle_resource_ref);
+    CFRelease(library->bundle);
+  } else {
+    dlclose(library->dylib);
+  }
+  delete library;
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  if (library->type == BUNDLE) {
+    base::mac::ScopedCFTypeRef<CFStringRef> symbol_name(
+        CFStringCreateWithCString(kCFAllocatorDefault, name,
+                                  kCFStringEncodingUTF8));
+    return CFBundleGetFunctionPointerForName(library->bundle, symbol_name);
+  }
+  return dlsym(library->dylib, name);
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return name + ASCIIToUTF16(".dylib");
+}
+
+}  // namespace base
diff --git a/base/native_library_posix.cc b/base/native_library_posix.cc
new file mode 100644
index 0000000..4b82ff4
--- /dev/null
+++ b/base/native_library_posix.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/native_library.h"
+
+#include <dlfcn.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+// static
+NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                std::string* error) {
+  // dlopen() opens the file off disk.
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // We deliberately do not use RTLD_DEEPBIND.  For the history why, please
+  // refer to the bug tracker.  Some useful bug reports to read include:
+  // http://crbug.com/17943, http://crbug.com/17557, http://crbug.com/36892,
+  // and http://crbug.com/40794.
+  void* dl = dlopen(library_path.value().c_str(), RTLD_LAZY);
+  if (!dl && error)
+    *error = dlerror();
+
+  return dl;
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  int ret = dlclose(library);
+  if (ret < 0) {
+    DLOG(ERROR) << "dlclose failed: " << dlerror();
+    NOTREACHED();
+  }
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  return dlsym(library, name);
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return ASCIIToUTF16("lib") + name + ASCIIToUTF16(".so");
+}
+
+}  // namespace base
diff --git a/base/native_library_win.cc b/base/native_library_win.cc
new file mode 100644
index 0000000..af00cd1
--- /dev/null
+++ b/base/native_library_win.cc
@@ -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.
+
+#include "base/native_library.h"
+
+#include <windows.h>
+
+#include "base/file_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
+
+NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
+                                      LoadLibraryFunction load_library_api) {
+  // LoadLibrary() opens the file off disk.
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // Switch the current directory to the library directory as the library
+  // may have dependencies on DLLs in this directory.
+  bool restore_directory = false;
+  FilePath current_directory;
+  if (file_util::GetCurrentDirectory(&current_directory)) {
+    FilePath plugin_path = library_path.DirName();
+    if (!plugin_path.empty()) {
+      file_util::SetCurrentDirectory(plugin_path);
+      restore_directory = true;
+    }
+  }
+
+  HMODULE module = (*load_library_api)(library_path.value().c_str());
+  if (restore_directory)
+    file_util::SetCurrentDirectory(current_directory);
+
+  return module;
+}
+
+// static
+NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                std::string* error) {
+  return LoadNativeLibraryHelper(library_path, LoadLibraryW);
+}
+
+NativeLibrary LoadNativeLibraryDynamically(const FilePath& library_path) {
+  typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
+
+  LoadLibraryFunction load_library;
+  load_library = reinterpret_cast<LoadLibraryFunction>(
+      GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"));
+
+  return LoadNativeLibraryHelper(library_path, load_library);
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  FreeLibrary(library);
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  return GetProcAddress(library, name);
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return name + ASCIIToUTF16(".dll");
+}
+
+}  // namespace base
diff --git a/base/nix/mime_util_xdg.cc b/base/nix/mime_util_xdg.cc
new file mode 100644
index 0000000..e58e03d
--- /dev/null
+++ b/base/nix/mime_util_xdg.cc
@@ -0,0 +1,678 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/nix/mime_util_xdg.h"
+
+#include <cstdlib>
+#include <list>
+#include <map>
+#include <vector>
+
+#include "base/environment.h"
+#include "base/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/nix/xdg_util.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "base/synchronization/lock.h"
+#include "base/third_party/xdg_mime/xdgmime.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time.h"
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>  // NOLINT
+
+#include "base/message_loop.h"
+#endif
+
+namespace {
+
+class IconTheme;
+
+// None of the XDG stuff is thread-safe, so serialize all access under
+// this lock.
+base::LazyInstance<base::Lock>::Leaky
+    g_mime_util_xdg_lock = LAZY_INSTANCE_INITIALIZER;
+
+class MimeUtilConstants {
+ public:
+  typedef std::map<std::string, IconTheme*> IconThemeMap;
+  typedef std::map<FilePath, base::Time> IconDirMtimeMap;
+  typedef std::vector<std::string> IconFormats;
+
+  // Specified by XDG icon theme specs.
+  static const int kUpdateIntervalInSeconds = 5;
+
+  static const size_t kDefaultThemeNum = 4;
+
+  static MimeUtilConstants* GetInstance() {
+    return Singleton<MimeUtilConstants>::get();
+  }
+
+  // Store icon directories and their mtimes.
+  IconDirMtimeMap icon_dirs_;
+
+  // Store icon formats.
+  IconFormats icon_formats_;
+
+  // Store loaded icon_theme.
+  IconThemeMap icon_themes_;
+
+  // The default theme.
+  IconTheme* default_themes_[kDefaultThemeNum];
+
+  base::TimeTicks last_check_time_;
+
+#if defined(TOOLKIT_GTK)
+  // This is set by DetectGtkTheme(). We cache it so that we can access the
+  // theme name from threads that aren't allowed to call
+  // gtk_settings_get_default().
+  std::string gtk_theme_name_;
+#endif
+
+ private:
+  MimeUtilConstants() {
+    icon_formats_.push_back(".png");
+    icon_formats_.push_back(".svg");
+    icon_formats_.push_back(".xpm");
+
+    for (size_t i = 0; i < kDefaultThemeNum; ++i)
+      default_themes_[i] = NULL;
+  }
+  ~MimeUtilConstants();
+
+  friend struct DefaultSingletonTraits<MimeUtilConstants>;
+
+  DISALLOW_COPY_AND_ASSIGN(MimeUtilConstants);
+};
+
+// IconTheme represents an icon theme as defined by the xdg icon theme spec.
+// Example themes on GNOME include 'Human' and 'Mist'.
+// Example themes on KDE include 'crystalsvg' and 'kdeclassic'.
+class IconTheme {
+ public:
+  // A theme consists of multiple sub-directories, like '32x32' and 'scalable'.
+  class SubDirInfo {
+   public:
+    // See spec for details.
+    enum Type {
+      Fixed,
+      Scalable,
+      Threshold
+    };
+    SubDirInfo()
+        : size(0),
+          type(Threshold),
+          max_size(0),
+          min_size(0),
+          threshold(2) {
+    }
+    size_t size;  // Nominal size of the icons in this directory.
+    Type type;  // Type of the icon size.
+    size_t max_size;  // Maximum size that the icons can be scaled to.
+    size_t min_size;  // Minimum size that the icons can be scaled to.
+    size_t threshold;  // Maximum difference from desired size. 2 by default.
+  };
+
+  explicit IconTheme(const std::string& name);
+
+  ~IconTheme() {}
+
+  // Returns the path to an icon with the name |icon_name| and a size of |size|
+  // pixels. If the icon does not exist, but |inherits| is true, then look for
+  // the icon in the parent theme.
+  FilePath GetIconPath(const std::string& icon_name, int size, bool inherits);
+
+  // Load a theme with the name |theme_name| into memory. Returns null if theme
+  // is invalid.
+  static IconTheme* LoadTheme(const std::string& theme_name);
+
+ private:
+  // Returns the path to an icon with the name |icon_name| in |subdir|.
+  FilePath GetIconPathUnderSubdir(const std::string& icon_name,
+                                  const std::string& subdir);
+
+  // Whether the theme loaded properly.
+  bool IsValid() {
+    return index_theme_loaded_;
+  }
+
+  // Read and parse |file| which is usually named 'index.theme' per theme spec.
+  bool LoadIndexTheme(const FilePath& file);
+
+  // Checks to see if the icons in |info| matches |size| (in pixels). Returns
+  // 0 if they match, or the size difference in pixels.
+  size_t MatchesSize(SubDirInfo* info, size_t size);
+
+  // Yet another function to read a line.
+  std::string ReadLine(FILE* fp);
+
+  // Set directories to search for icons to the comma-separated list |dirs|.
+  bool SetDirectories(const std::string& dirs);
+
+  bool index_theme_loaded_;  // True if an instance is properly loaded.
+  // store the scattered directories of this theme.
+  std::list<FilePath> dirs_;
+
+  // store the subdirs of this theme and array index of |info_array_|.
+  std::map<std::string, int> subdirs_;
+  scoped_array<SubDirInfo> info_array_;  // List of sub-directories.
+  std::string inherits_;  // Name of the theme this one inherits from.
+};
+
+IconTheme::IconTheme(const std::string& name)
+  : index_theme_loaded_(false),
+    info_array_(NULL) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  // Iterate on all icon directories to find directories of the specified
+  // theme and load the first encountered index.theme.
+  MimeUtilConstants::IconDirMtimeMap::iterator iter;
+  FilePath theme_path;
+  MimeUtilConstants::IconDirMtimeMap* icon_dirs =
+      &MimeUtilConstants::GetInstance()->icon_dirs_;
+  for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) {
+    theme_path = iter->first.Append(name);
+    if (!file_util::DirectoryExists(theme_path))
+      continue;
+    FilePath theme_index = theme_path.Append("index.theme");
+    if (!index_theme_loaded_ && file_util::PathExists(theme_index)) {
+      if (!LoadIndexTheme(theme_index))
+        return;
+      index_theme_loaded_ = true;
+    }
+    dirs_.push_back(theme_path);
+  }
+}
+
+FilePath IconTheme::GetIconPath(const std::string& icon_name, int size,
+                                bool inherits) {
+  std::map<std::string, int>::iterator subdir_iter;
+  FilePath icon_path;
+
+  for (subdir_iter = subdirs_.begin();
+       subdir_iter != subdirs_.end();
+       ++subdir_iter) {
+    SubDirInfo* info = &info_array_[subdir_iter->second];
+    if (MatchesSize(info, size) == 0) {
+      icon_path = GetIconPathUnderSubdir(icon_name, subdir_iter->first);
+      if (!icon_path.empty())
+        return icon_path;
+    }
+  }
+  // Now looking for the mostly matched.
+  size_t min_delta_seen = 9999;
+
+  for (subdir_iter = subdirs_.begin();
+       subdir_iter != subdirs_.end();
+       ++subdir_iter) {
+    SubDirInfo* info = &info_array_[subdir_iter->second];
+    size_t delta = MatchesSize(info, size);
+    if (delta < min_delta_seen) {
+      FilePath path = GetIconPathUnderSubdir(icon_name, subdir_iter->first);
+      if (!path.empty()) {
+        min_delta_seen = delta;
+        icon_path = path;
+      }
+    }
+  }
+
+  if (!icon_path.empty() || !inherits || inherits_ == "")
+    return icon_path;
+
+  IconTheme* theme = LoadTheme(inherits_);
+  // Inheriting from itself means the theme is buggy but we shouldn't crash.
+  if (theme && theme != this)
+    return theme->GetIconPath(icon_name, size, inherits);
+  else
+    return FilePath();
+}
+
+IconTheme* IconTheme::LoadTheme(const std::string& theme_name) {
+  scoped_ptr<IconTheme> theme;
+  MimeUtilConstants::IconThemeMap* icon_themes =
+      &MimeUtilConstants::GetInstance()->icon_themes_;
+  if (icon_themes->find(theme_name) != icon_themes->end()) {
+    theme.reset((*icon_themes)[theme_name]);
+  } else {
+    theme.reset(new IconTheme(theme_name));
+    if (!theme->IsValid())
+      theme.reset();
+    (*icon_themes)[theme_name] = theme.get();
+  }
+  return theme.release();
+}
+
+FilePath IconTheme::GetIconPathUnderSubdir(const std::string& icon_name,
+                                           const std::string& subdir) {
+  FilePath icon_path;
+  std::list<FilePath>::iterator dir_iter;
+  MimeUtilConstants::IconFormats* icon_formats =
+      &MimeUtilConstants::GetInstance()->icon_formats_;
+  for (dir_iter = dirs_.begin(); dir_iter != dirs_.end(); ++dir_iter) {
+    for (size_t i = 0; i < icon_formats->size(); ++i) {
+      icon_path = dir_iter->Append(subdir);
+      icon_path = icon_path.Append(icon_name + (*icon_formats)[i]);
+      if (file_util::PathExists(icon_path))
+        return icon_path;
+    }
+  }
+  return FilePath();
+}
+
+bool IconTheme::LoadIndexTheme(const FilePath& file) {
+  FILE* fp = file_util::OpenFile(file, "r");
+  SubDirInfo* current_info = NULL;
+  if (!fp)
+    return false;
+
+  // Read entries.
+  while (!feof(fp) && !ferror(fp)) {
+    std::string buf = ReadLine(fp);
+    if (buf == "")
+      break;
+
+    std::string entry;
+    TrimWhitespaceASCII(buf, TRIM_ALL, &entry);
+    if (entry.length() == 0 || entry[0] == '#') {
+      // Blank line or Comment.
+      continue;
+    } else if (entry[0] == '[' && info_array_.get()) {
+      current_info = NULL;
+      std::string subdir = entry.substr(1, entry.length() - 2);
+      if (subdirs_.find(subdir) != subdirs_.end())
+        current_info = &info_array_[subdirs_[subdir]];
+    }
+
+    std::string key, value;
+    std::vector<std::string> r;
+    base::SplitStringDontTrim(entry, '=', &r);
+    if (r.size() < 2)
+      continue;
+
+    TrimWhitespaceASCII(r[0], TRIM_ALL, &key);
+    for (size_t i = 1; i < r.size(); i++)
+      value.append(r[i]);
+    TrimWhitespaceASCII(value, TRIM_ALL, &value);
+
+    if (current_info) {
+      if (key == "Size") {
+        current_info->size = atoi(value.c_str());
+      } else if (key == "Type") {
+        if (value == "Fixed")
+          current_info->type = SubDirInfo::Fixed;
+        else if (value == "Scalable")
+          current_info->type = SubDirInfo::Scalable;
+        else if (value == "Threshold")
+          current_info->type = SubDirInfo::Threshold;
+      } else if (key == "MaxSize") {
+        current_info->max_size = atoi(value.c_str());
+      } else if (key == "MinSize") {
+        current_info->min_size = atoi(value.c_str());
+      } else if (key == "Threshold") {
+        current_info->threshold = atoi(value.c_str());
+      }
+    } else {
+      if (key.compare("Directories") == 0 && !info_array_.get()) {
+        if (!SetDirectories(value)) break;
+      } else if (key.compare("Inherits") == 0) {
+        if (value != "hicolor")
+          inherits_ = value;
+      }
+    }
+  }
+
+  file_util::CloseFile(fp);
+  return info_array_.get() != NULL;
+}
+
+size_t IconTheme::MatchesSize(SubDirInfo* info, size_t size) {
+  if (info->type == SubDirInfo::Fixed) {
+    if (size > info->size)
+      return size - info->size;
+    else
+      return info->size - size;
+  } else if (info->type == SubDirInfo::Scalable) {
+    if (size < info->min_size)
+      return info->min_size - size;
+    if (size > info->max_size)
+      return size - info->max_size;
+    return 0;
+  } else {
+    if (size + info->threshold < info->size)
+      return info->size - size - info->threshold;
+    if (size > info->size + info->threshold)
+      return size - info->size - info->threshold;
+    return 0;
+  }
+}
+
+std::string IconTheme::ReadLine(FILE* fp) {
+  if (!fp)
+    return "";
+
+  std::string result = "";
+  const size_t kBufferSize = 100;
+  char buffer[kBufferSize];
+  while ((fgets(buffer, kBufferSize - 1, fp)) != NULL) {
+    result += buffer;
+    size_t len = result.length();
+    if (len == 0)
+      break;
+    char end = result[len - 1];
+    if (end == '\n' || end == '\0')
+      break;
+  }
+
+  return result;
+}
+
+bool IconTheme::SetDirectories(const std::string& dirs) {
+  int num = 0;
+  std::string::size_type pos = 0, epos;
+  std::string dir;
+  while ((epos = dirs.find(',', pos)) != std::string::npos) {
+    TrimWhitespaceASCII(dirs.substr(pos, epos - pos), TRIM_ALL, &dir);
+    if (dir.length() == 0) {
+      DLOG(WARNING) << "Invalid index.theme: blank subdir";
+      return false;
+    }
+    subdirs_[dir] = num++;
+    pos = epos + 1;
+  }
+  TrimWhitespaceASCII(dirs.substr(pos), TRIM_ALL, &dir);
+  if (dir.length() == 0) {
+    DLOG(WARNING) << "Invalid index.theme: blank subdir";
+    return false;
+  }
+  subdirs_[dir] = num++;
+  info_array_.reset(new SubDirInfo[num]);
+  return true;
+}
+
+bool CheckDirExistsAndGetMtime(const FilePath& dir,
+                               base::Time* last_modified) {
+  if (!file_util::DirectoryExists(dir))
+    return false;
+  base::PlatformFileInfo file_info;
+  if (!file_util::GetFileInfo(dir, &file_info))
+    return false;
+  *last_modified = file_info.last_modified;
+  return true;
+}
+
+// Make sure |dir| exists and add it to the list of icon directories.
+void TryAddIconDir(const FilePath& dir) {
+  base::Time last_modified;
+  if (!CheckDirExistsAndGetMtime(dir, &last_modified))
+    return;
+  MimeUtilConstants::GetInstance()->icon_dirs_[dir] = last_modified;
+}
+
+// For a xdg directory |dir|, add the appropriate icon sub-directories.
+void AddXDGDataDir(const FilePath& dir) {
+  if (!file_util::DirectoryExists(dir))
+    return;
+  TryAddIconDir(dir.Append("icons"));
+  TryAddIconDir(dir.Append("pixmaps"));
+}
+
+// Add all the xdg icon directories.
+void InitIconDir() {
+  FilePath home = file_util::GetHomeDir();
+  if (!home.empty()) {
+      FilePath legacy_data_dir(home);
+      legacy_data_dir = legacy_data_dir.AppendASCII(".icons");
+      if (file_util::DirectoryExists(legacy_data_dir))
+        TryAddIconDir(legacy_data_dir);
+  }
+  const char* env = getenv("XDG_DATA_HOME");
+  if (env) {
+    AddXDGDataDir(FilePath(env));
+  } else if (!home.empty()) {
+    FilePath local_data_dir(home);
+    local_data_dir = local_data_dir.AppendASCII(".local");
+    local_data_dir = local_data_dir.AppendASCII("share");
+    AddXDGDataDir(local_data_dir);
+  }
+
+  env = getenv("XDG_DATA_DIRS");
+  if (!env) {
+    AddXDGDataDir(FilePath("/usr/local/share"));
+    AddXDGDataDir(FilePath("/usr/share"));
+  } else {
+    std::string xdg_data_dirs = env;
+    std::string::size_type pos = 0, epos;
+    while ((epos = xdg_data_dirs.find(':', pos)) != std::string::npos) {
+      AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos, epos - pos)));
+      pos = epos + 1;
+    }
+    AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos)));
+  }
+}
+
+void EnsureUpdated() {
+  MimeUtilConstants* constants = MimeUtilConstants::GetInstance();
+  if (constants->last_check_time_.is_null()) {
+    constants->last_check_time_ = base::TimeTicks::Now();
+    InitIconDir();
+    return;
+  }
+
+  // Per xdg theme spec, we should check the icon directories every so often
+  // for newly added icons.
+  base::TimeDelta time_since_last_check =
+      base::TimeTicks::Now() - constants->last_check_time_;
+  if (time_since_last_check.InSeconds() > constants->kUpdateIntervalInSeconds) {
+    constants->last_check_time_ += time_since_last_check;
+
+    bool rescan_icon_dirs = false;
+    MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_;
+    MimeUtilConstants::IconDirMtimeMap::iterator iter;
+    for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) {
+      base::Time last_modified;
+      if (!CheckDirExistsAndGetMtime(iter->first, &last_modified) ||
+          last_modified != iter->second) {
+        rescan_icon_dirs = true;
+        break;
+      }
+    }
+
+    if (rescan_icon_dirs) {
+      constants->icon_dirs_.clear();
+      constants->icon_themes_.clear();
+      InitIconDir();
+    }
+  }
+}
+
+// Find a fallback icon if we cannot find it in the default theme.
+FilePath LookupFallbackIcon(const std::string& icon_name) {
+  MimeUtilConstants* constants = MimeUtilConstants::GetInstance();
+  MimeUtilConstants::IconDirMtimeMap::iterator iter;
+  MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_;
+  MimeUtilConstants::IconFormats* icon_formats = &constants->icon_formats_;
+  for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) {
+    for (size_t i = 0; i < icon_formats->size(); ++i) {
+      FilePath icon = iter->first.Append(icon_name + (*icon_formats)[i]);
+      if (file_util::PathExists(icon))
+        return icon;
+    }
+  }
+  return FilePath();
+}
+
+// Initialize the list of default themes.
+void InitDefaultThemes() {
+  IconTheme** default_themes =
+      MimeUtilConstants::GetInstance()->default_themes_;
+
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  base::nix::DesktopEnvironment desktop_env =
+      base::nix::GetDesktopEnvironment(env.get());
+  if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE3 ||
+      desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE4) {
+    // KDE
+    std::string kde_default_theme;
+    std::string kde_fallback_theme;
+
+    // TODO(thestig): Figure out how to get the current icon theme on KDE.
+    // Setting stored in ~/.kde/share/config/kdeglobals under Icons -> Theme.
+    default_themes[0] = NULL;
+
+    // Try some reasonable defaults for KDE.
+    if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE3) {
+      // KDE 3
+      kde_default_theme = "default.kde";
+      kde_fallback_theme = "crystalsvg";
+    } else {
+      // KDE 4
+      kde_default_theme = "default.kde4";
+      kde_fallback_theme = "oxygen";
+    }
+    default_themes[1] = IconTheme::LoadTheme(kde_default_theme);
+    default_themes[2] = IconTheme::LoadTheme(kde_fallback_theme);
+  } else {
+#if defined(TOOLKIT_GTK)
+    // Assume it's Gnome and use GTK to figure out the theme.
+    default_themes[1] = IconTheme::LoadTheme(
+        MimeUtilConstants::GetInstance()->gtk_theme_name_);
+    default_themes[2] = IconTheme::LoadTheme("gnome");
+#endif
+  }
+  // hicolor needs to be last per icon theme spec.
+  default_themes[3] = IconTheme::LoadTheme("hicolor");
+
+  for (size_t i = 0; i < MimeUtilConstants::kDefaultThemeNum; i++) {
+    if (default_themes[i] == NULL)
+      continue;
+    // NULL out duplicate pointers.
+    for (size_t j = i + 1; j < MimeUtilConstants::kDefaultThemeNum; j++) {
+      if (default_themes[j] == default_themes[i])
+        default_themes[j] = NULL;
+    }
+  }
+}
+
+// Try to find an icon with the name |icon_name| that's |size| pixels.
+FilePath LookupIconInDefaultTheme(const std::string& icon_name, int size) {
+  EnsureUpdated();
+  MimeUtilConstants* constants = MimeUtilConstants::GetInstance();
+  MimeUtilConstants::IconThemeMap* icon_themes = &constants->icon_themes_;
+  if (icon_themes->empty())
+    InitDefaultThemes();
+
+  FilePath icon_path;
+  IconTheme** default_themes = constants->default_themes_;
+  for (size_t i = 0; i < MimeUtilConstants::kDefaultThemeNum; i++) {
+    if (default_themes[i]) {
+      icon_path = default_themes[i]->GetIconPath(icon_name, size, true);
+      if (!icon_path.empty())
+        return icon_path;
+    }
+  }
+  return LookupFallbackIcon(icon_name);
+}
+
+MimeUtilConstants::~MimeUtilConstants() {
+  for (size_t i = 0; i < kDefaultThemeNum; i++)
+    delete default_themes_[i];
+}
+
+}  // namespace
+
+namespace base {
+namespace nix {
+
+std::string GetFileMimeType(const FilePath& filepath) {
+  if (filepath.empty())
+    return std::string();
+  base::ThreadRestrictions::AssertIOAllowed();
+  base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
+  return xdg_mime_get_mime_type_from_file_name(filepath.value().c_str());
+}
+
+std::string GetDataMimeType(const std::string& data) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
+  return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL);
+}
+
+#if defined(TOOLKIT_GTK)
+void DetectGtkTheme() {
+  // If the theme name is already loaded, do nothing. Chrome doesn't respond
+  // to changes in the system theme, so we never need to set this more than
+  // once.
+  if (!MimeUtilConstants::GetInstance()->gtk_theme_name_.empty())
+    return;
+
+  // We should only be called on the UI thread.
+  DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
+
+  gchar* gtk_theme_name;
+  g_object_get(gtk_settings_get_default(),
+               "gtk-icon-theme-name",
+               &gtk_theme_name, NULL);
+  MimeUtilConstants::GetInstance()->gtk_theme_name_.assign(gtk_theme_name);
+  g_free(gtk_theme_name);
+}
+#endif
+
+FilePath GetMimeIcon(const std::string& mime_type, size_t size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  std::vector<std::string> icon_names;
+  std::string icon_name;
+  FilePath icon_file;
+
+  if (!mime_type.empty()) {
+    base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
+    const char *icon = xdg_mime_get_icon(mime_type.c_str());
+    icon_name = std::string(icon ? icon : "");
+  }
+
+  if (icon_name.length())
+    icon_names.push_back(icon_name);
+
+  // For text/plain, try text-plain.
+  icon_name = mime_type;
+  for (size_t i = icon_name.find('/', 0); i != std::string::npos;
+       i = icon_name.find('/', i + 1)) {
+    icon_name[i] = '-';
+  }
+  icon_names.push_back(icon_name);
+  // Also try gnome-mime-text-plain.
+  icon_names.push_back("gnome-mime-" + icon_name);
+
+  // Try "deb" for "application/x-deb" in KDE 3.
+  size_t x_substr_pos = mime_type.find("/x-");
+  if (x_substr_pos != std::string::npos) {
+    icon_name = mime_type.substr(x_substr_pos + 3);
+    icon_names.push_back(icon_name);
+  }
+
+  // Try generic name like text-x-generic.
+  icon_name = mime_type.substr(0, mime_type.find('/')) + "-x-generic";
+  icon_names.push_back(icon_name);
+
+  // Last resort
+  icon_names.push_back("unknown");
+
+  for (size_t i = 0; i < icon_names.size(); i++) {
+    if (icon_names[i][0] == '/') {
+      icon_file = FilePath(icon_names[i]);
+      if (file_util::PathExists(icon_file))
+        return icon_file;
+    } else {
+      icon_file = LookupIconInDefaultTheme(icon_names[i], size);
+      if (!icon_file.empty())
+        return icon_file;
+    }
+  }
+  return FilePath();
+}
+
+}  // namespace nix
+}  // namespace base
diff --git a/base/nix/mime_util_xdg.h b/base/nix/mime_util_xdg.h
new file mode 100644
index 0000000..444ce4f
--- /dev/null
+++ b/base/nix/mime_util_xdg.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_NIX_MIME_UTIL_XDG_H_
+#define BASE_NIX_MIME_UTIL_XDG_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+class FilePath;
+
+namespace base {
+namespace nix {
+
+// Gets the mime type for a file based on its filename. The file path does not
+// have to exist. Please note because it doesn't touch the disk, this does not
+// work for directories.
+// If the mime type is unknown, this will return application/octet-stream.
+BASE_EXPORT std::string GetFileMimeType(const FilePath& filepath);
+
+// Get the mime type for a byte vector.
+BASE_EXPORT std::string GetDataMimeType(const std::string& data);
+
+#if defined(TOOLKIT_GTK)
+// This detects the current GTK theme by calling gtk_settings_get_default().
+// It should only be executed on the UI thread and must be called before
+// GetMimeIcon().
+BASE_EXPORT void DetectGtkTheme();
+#endif
+
+// Gets the file name for an icon given the mime type and icon pixel size.
+// Where an icon is a square image of |size| x |size|.
+// This will try to find the closest matching icon. If that's not available,
+// then a generic icon, and finally an empty FilePath if all else fails.
+BASE_EXPORT FilePath GetMimeIcon(const std::string& mime_type, size_t size);
+
+}  // namespace nix
+}  // namespace base
+
+#endif  // BASE_NIX_MIME_UTIL_XDG_H_
diff --git a/base/nix/xdg_util.cc b/base/nix/xdg_util.cc
new file mode 100644
index 0000000..10cbcaa
--- /dev/null
+++ b/base/nix/xdg_util.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/nix/xdg_util.h"
+
+#include <string>
+
+#include "base/environment.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h"
+
+namespace {
+
+// The KDE session version environment variable used in KDE 4.
+const char kKDE4SessionEnvVar[] = "KDE_SESSION_VERSION";
+
+}  // namespace
+
+namespace base {
+namespace nix {
+
+const char kDotConfigDir[] = ".config";
+const char kXdgConfigHomeEnvVar[] = "XDG_CONFIG_HOME";
+
+FilePath GetXDGDirectory(Environment* env, const char* env_name,
+                         const char* fallback_dir) {
+  FilePath path;
+  std::string env_value;
+  if (env->GetVar(env_name, &env_value) && !env_value.empty())
+    path = FilePath(env_value);
+  else
+    path = file_util::GetHomeDir().Append(fallback_dir);
+  return path.StripTrailingSeparators();
+}
+
+FilePath GetXDGUserDirectory(const char* dir_name, const char* fallback_dir) {
+  FilePath path;
+  char* xdg_dir = xdg_user_dir_lookup(dir_name);
+  if (xdg_dir) {
+    path = FilePath(xdg_dir);
+    free(xdg_dir);
+  } else {
+    path = file_util::GetHomeDir().Append(fallback_dir);
+  }
+  return path.StripTrailingSeparators();
+}
+
+DesktopEnvironment GetDesktopEnvironment(Environment* env) {
+  // XDG_CURRENT_DESKTOP is the newest standard circa 2012.
+  std::string xdg_current_desktop;
+  if (env->GetVar("XDG_CURRENT_DESKTOP", &xdg_current_desktop)) {
+    // Not all desktop environments set this env var as of this writing.
+    if (xdg_current_desktop == "Unity")
+      return DESKTOP_ENVIRONMENT_UNITY;
+    else if (xdg_current_desktop == "GNOME")
+      return DESKTOP_ENVIRONMENT_GNOME;
+  }
+
+  // DESKTOP_SESSION was what everyone used in 2010.
+  std::string desktop_session;
+  if (env->GetVar("DESKTOP_SESSION", &desktop_session)) {
+    if (desktop_session == "gnome") {
+      return DESKTOP_ENVIRONMENT_GNOME;
+    } else if (desktop_session == "kde4") {
+      return DESKTOP_ENVIRONMENT_KDE4;
+    } else if (desktop_session == "kde") {
+      // This may mean KDE4 on newer systems, so we have to check.
+      if (env->HasVar(kKDE4SessionEnvVar))
+        return DESKTOP_ENVIRONMENT_KDE4;
+      return DESKTOP_ENVIRONMENT_KDE3;
+    } else if (desktop_session.find("xfce") != std::string::npos ||
+               desktop_session == "xubuntu") {
+      return DESKTOP_ENVIRONMENT_XFCE;
+    }
+  }
+
+  // Fall back on some older environment variables.
+  // Useful particularly in the DESKTOP_SESSION=default case.
+  if (env->HasVar("GNOME_DESKTOP_SESSION_ID")) {
+    return DESKTOP_ENVIRONMENT_GNOME;
+  } else if (env->HasVar("KDE_FULL_SESSION")) {
+    if (env->HasVar(kKDE4SessionEnvVar))
+      return DESKTOP_ENVIRONMENT_KDE4;
+    return DESKTOP_ENVIRONMENT_KDE3;
+  }
+
+  return DESKTOP_ENVIRONMENT_OTHER;
+}
+
+const char* GetDesktopEnvironmentName(DesktopEnvironment env) {
+  switch (env) {
+    case DESKTOP_ENVIRONMENT_OTHER:
+      return NULL;
+    case DESKTOP_ENVIRONMENT_GNOME:
+      return "GNOME";
+    case DESKTOP_ENVIRONMENT_KDE3:
+      return "KDE3";
+    case DESKTOP_ENVIRONMENT_KDE4:
+      return "KDE4";
+    case DESKTOP_ENVIRONMENT_UNITY:
+      return "UNITY";
+    case DESKTOP_ENVIRONMENT_XFCE:
+      return "XFCE";
+  }
+  return NULL;
+}
+
+const char* GetDesktopEnvironmentName(Environment* env) {
+  return GetDesktopEnvironmentName(GetDesktopEnvironment(env));
+}
+
+}  // namespace nix
+}  // namespace base
diff --git a/base/nix/xdg_util.h b/base/nix/xdg_util.h
new file mode 100644
index 0000000..fc72663
--- /dev/null
+++ b/base/nix/xdg_util.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NIX_XDG_UTIL_H_
+#define BASE_NIX_XDG_UTIL_H_
+
+// XDG refers to http://en.wikipedia.org/wiki/Freedesktop.org .
+// This file contains utilities found across free desktop environments.
+//
+// TODO(brettw) this file should be in app/x11, but is currently used by
+// net. We should have a net API to allow the embedder to specify the behavior
+// that it uses XDG for, and then move this file.
+
+#include "base/base_export.h"
+
+#ifdef nix
+#error asdf
+#endif
+
+class FilePath;
+
+namespace base {
+
+class Environment;
+
+namespace nix {
+
+// The default XDG config directory name.
+BASE_EXPORT extern const char kDotConfigDir[];
+
+// The XDG config directory environment variable.
+BASE_EXPORT extern const char kXdgConfigHomeEnvVar[];
+
+// Utility function for getting XDG directories.
+// |env_name| is the name of an environment variable that we want to use to get
+// a directory path. |fallback_dir| is the directory relative to $HOME that we
+// use if |env_name| cannot be found or is empty. |fallback_dir| may be NULL.
+// Examples of |env_name| are XDG_CONFIG_HOME and XDG_DATA_HOME.
+BASE_EXPORT FilePath GetXDGDirectory(Environment* env, const char* env_name,
+                                     const char* fallback_dir);
+
+// Wrapper around xdg_user_dir_lookup() from src/base/third_party/xdg-user-dirs
+// This looks up "well known" user directories like the desktop and music
+// folder. Examples of |dir_name| are DESKTOP and MUSIC.
+BASE_EXPORT FilePath GetXDGUserDirectory(const char* dir_name,
+                                         const char* fallback_dir);
+
+enum DesktopEnvironment {
+  DESKTOP_ENVIRONMENT_OTHER,
+  DESKTOP_ENVIRONMENT_GNOME,
+  // KDE3 and KDE4 are sufficiently different that we count
+  // them as two different desktop environments here.
+  DESKTOP_ENVIRONMENT_KDE3,
+  DESKTOP_ENVIRONMENT_KDE4,
+  DESKTOP_ENVIRONMENT_UNITY,
+  DESKTOP_ENVIRONMENT_XFCE,
+};
+
+// Return an entry from the DesktopEnvironment enum with a best guess
+// of which desktop environment we're using.  We use this to know when
+// to attempt to use preferences from the desktop environment --
+// proxy settings, password manager, etc.
+BASE_EXPORT DesktopEnvironment GetDesktopEnvironment(Environment* env);
+
+// Return a string representation of the given desktop environment.
+// May return NULL in the case of DESKTOP_ENVIRONMENT_OTHER.
+BASE_EXPORT const char* GetDesktopEnvironmentName(DesktopEnvironment env);
+// Convenience wrapper that calls GetDesktopEnvironment() first.
+BASE_EXPORT const char* GetDesktopEnvironmentName(Environment* env);
+
+}  // namespace nix
+}  // namespace base
+
+#endif  // BASE_NIX_XDG_UTIL_H_
diff --git a/base/nix/xdg_util_unittest.cc b/base/nix/xdg_util_unittest.cc
new file mode 100644
index 0000000..2fc9d4c
--- /dev/null
+++ b/base/nix/xdg_util_unittest.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/nix/xdg_util.h"
+
+#include "base/environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+
+namespace base {
+namespace nix {
+
+namespace {
+
+class MockEnvironment : public Environment {
+ public:
+  MOCK_METHOD2(GetVar, bool(const char*, std::string* result));
+  MOCK_METHOD2(SetVar, bool(const char*, const std::string& new_value));
+  MOCK_METHOD1(UnSetVar, bool(const char*));
+};
+
+const char* kGnome = "gnome";
+const char* kKDE4 = "kde4";
+const char* kKDE = "kde";
+const char* kXFCE = "xfce";
+
+}  // namespace
+
+TEST(XDGUtilTest, GetDesktopEnvironmentGnome) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kGnome), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME,
+            GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentKDE4) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kKDE4), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4,
+            GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentKDE3) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kKDE), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE3,
+            GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentXFCE) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kXFCE), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_XFCE,
+            GetDesktopEnvironment(&getter));
+}
+
+}  // namespace nix
+}  // namespace base
diff --git a/base/nullable_string16.h b/base/nullable_string16.h
new file mode 100644
index 0000000..6f07183
--- /dev/null
+++ b/base/nullable_string16.h
@@ -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.
+
+#ifndef BASE_NULLABLE_STRING16_H_
+#define BASE_NULLABLE_STRING16_H_
+
+#include "base/string16.h"
+
+// 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_(false) { }
+  explicit NullableString16(bool is_null) : is_null_(is_null) { }
+  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_;
+};
+
+#endif  // BASE_NULLABLE_STRING16_H_
diff --git a/base/observer_list.h b/base/observer_list.h
new file mode 100644
index 0000000..364b180
--- /dev/null
+++ b/base/observer_list.h
@@ -0,0 +1,216 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OBSERVER_LIST_H__
+#define BASE_OBSERVER_LIST_H__
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// OVERVIEW:
+//
+//   A container for a list of observers.  Unlike a normal STL vector or list,
+//   this container can be modified during iteration without invalidating the
+//   iterator.  So, it safely handles the case of an observer removing itself
+//   or other observers from the list while observers are being notified.
+//
+// TYPICAL USAGE:
+//
+//   class MyWidget {
+//    public:
+//     ...
+//
+//     class Observer {
+//      public:
+//       virtual void OnFoo(MyWidget* w) = 0;
+//       virtual void OnBar(MyWidget* w, int x, int y) = 0;
+//     };
+//
+//     void AddObserver(Observer* obs) {
+//       observer_list_.AddObserver(obs);
+//     }
+//
+//     void RemoveObserver(Observer* obs) {
+//       observer_list_.RemoveObserver(obs);
+//     }
+//
+//     void NotifyFoo() {
+//       FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
+//     }
+//
+//     void NotifyBar(int x, int y) {
+//       FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
+//     }
+//
+//    private:
+//     ObserverList<Observer> observer_list_;
+//   };
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename ObserverType>
+class ObserverListThreadSafe;
+
+template <class ObserverType>
+class ObserverListBase
+    : public base::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:
+    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_;
+    }
+
+    ~Iterator() {
+      if (list_ && --list_->notify_depth_ == 0)
+        list_->Compact();
+    }
+
+    ObserverType* GetNext() {
+      if (!list_)
+        return NULL;
+      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_++] : NULL;
+    }
+
+   private:
+    base::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) {
+    if (std::find(observers_.begin(), observers_.end(), obs)
+        != observers_.end()) {
+      NOTREACHED() << "Observers can only be added once!";
+      return;
+    }
+    observers_.push_back(obs);
+  }
+
+  // Remove an observer from the list if it is in the list.
+  void RemoveObserver(ObserverType* obs) {
+    typename ListType::iterator it =
+      std::find(observers_.begin(), observers_.end(), obs);
+    if (it != observers_.end()) {
+      if (notify_depth_) {
+        *it = 0;
+      } else {
+        observers_.erase(it);
+      }
+    }
+  }
+
+  bool HasObserver(ObserverType* observer) const {
+    for (size_t i = 0; i < observers_.size(); ++i) {
+      if (observers_[i] == observer)
+        return true;
+    }
+    return false;
+  }
+
+  void Clear() {
+    if (notify_depth_) {
+      for (typename ListType::iterator it = observers_.begin();
+           it != observers_.end(); ++it) {
+        *it = 0;
+      }
+    } else {
+      observers_.clear();
+    }
+  }
+
+  size_t size() const { return observers_.size(); }
+
+ protected:
+  void Compact() {
+    observers_.erase(
+        std::remove(observers_.begin(), observers_.end(),
+                    static_cast<ObserverType*>(NULL)), observers_.end());
+  }
+
+ 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, 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()) {                    \
+      ObserverListBase<ObserverType>::Iterator it(observer_list);    \
+      ObserverType* obs;                                             \
+      while ((obs = it.GetNext()) != NULL)                           \
+        obs->func;                                                   \
+    }                                                                \
+  } while (0)
+
+#endif  // BASE_OBSERVER_LIST_H__
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
new file mode 100644
index 0000000..7322a1b
--- /dev/null
+++ b/base/observer_list_threadsafe.h
@@ -0,0 +1,297 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
+#define BASE_OBSERVER_LIST_THREADSAFE_H_
+
+#include <algorithm>
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/observer_list.h"
+#include "base/threading/platform_thread.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// OVERVIEW:
+//
+//   A thread-safe container for a list of observers.
+//   This is similar to the observer_list (see observer_list.h), but it
+//   is more robust for multi-threaded situations.
+//
+//   The following use cases are supported:
+//    * Observers can register for notifications from any thread.
+//      Callbacks to the observer will occur on the same thread where
+//      the observer initially called AddObserver() from.
+//    * Any thread may trigger a notification via Notify().
+//    * Observers can remove themselves from the observer list inside
+//      of a callback.
+//    * If one thread is notifying observers concurrently with an observer
+//      removing itself from the observer list, the notifications will
+//      be silently dropped.
+//
+//   The drawback of the threadsafe observer list is that notifications
+//   are not as real-time as the non-threadsafe version of this class.
+//   Notifications will always be done via PostTask() to another thread,
+//   whereas with the non-thread-safe observer_list, notifications happen
+//   synchronously and immediately.
+//
+//   IMPLEMENTATION NOTES
+//   The ObserverListThreadSafe maintains an ObserverList for each thread
+//   which uses the ThreadSafeObserver.  When Notifying the observers,
+//   we simply call PostTask to each registered thread, and then each thread
+//   will notify its regular ObserverList.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Forward declaration for ObserverListThreadSafeTraits.
+template <class ObserverType>
+class ObserverListThreadSafe;
+
+// An UnboundMethod is a wrapper for a method where the actual object is
+// provided at Run dispatch time.
+template <class T, class Method, class Params>
+class UnboundMethod {
+ public:
+  UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
+    COMPILE_ASSERT(
+        (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+        badunboundmethodparams);
+  }
+  void Run(T* obj) const {
+    DispatchToMethod(obj, m_, p_);
+  }
+ private:
+  Method m_;
+  Params p_;
+};
+
+// 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 base::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 = NULL;
+    base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
+    {
+      base::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 = NULL;
+    ObserverList<ObserverType>* list = NULL;
+    base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
+    {
+      base::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 {
+    base::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>
+  void Notify(Method m) {
+    UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple());
+    Notify<Method, Tuple0>(method);
+  }
+
+  template <class Method, class A>
+  void Notify(Method m, const A& a) {
+    UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a));
+    Notify<Method, Tuple1<A> >(method);
+  }
+
+  template <class Method, class A, class B>
+  void Notify(Method m, const A& a, const B& b) {
+    UnboundMethod<ObserverType, Method, Tuple2<A, B> > method(
+        m, MakeTuple(a, b));
+    Notify<Method, Tuple2<A, B> >(method);
+  }
+
+  template <class Method, class A, class B, class C>
+  void Notify(Method m, const A& a, const B& b, const C& c) {
+    UnboundMethod<ObserverType, Method, Tuple3<A, B, C> > method(
+        m, MakeTuple(a, b, c));
+    Notify<Method, Tuple3<A, B, C> >(method);
+  }
+
+  template <class Method, class A, class B, class C, class D>
+  void Notify(Method m, const A& a, const B& b, const C& c, const D& d) {
+    UnboundMethod<ObserverType, Method, Tuple4<A, B, C, D> > method(
+        m, MakeTuple(a, b, c, d));
+    Notify<Method, Tuple4<A, B, C, D> >(method);
+  }
+
+  // TODO(mbelshe):  Add more wrappers for Notify() with more arguments.
+
+ private:
+  // See comment above ObserverListThreadSafeTraits' definition.
+  friend struct ObserverListThreadSafeTraits<ObserverType>;
+
+  struct ObserverListContext {
+    explicit ObserverListContext(NotificationType type)
+        : loop(base::MessageLoopProxy::current()),
+          list(type) {
+    }
+
+    scoped_refptr<base::MessageLoopProxy> loop;
+    ObserverList<ObserverType> list;
+
+    DISALLOW_COPY_AND_ASSIGN(ObserverListContext);
+  };
+
+  ~ObserverListThreadSafe() {
+    typename ObserversListMap::const_iterator it;
+    for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it)
+      delete (*it).second;
+    observer_lists_.clear();
+  }
+
+  template <class Method, class Params>
+  void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
+    base::AutoLock lock(list_lock_);
+    typename ObserversListMap::iterator it;
+    for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
+      ObserverListContext* context = (*it).second;
+      context->loop->PostTask(
+          FROM_HERE,
+          base::Bind(&ObserverListThreadSafe<ObserverType>::
+              template NotifyWrapper<Method, Params>, this, context, method));
+    }
+  }
+
+  // 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 UnboundMethod<ObserverType, Method, Params>& method) {
+
+    // Check that this list still needs notifications.
+    {
+      base::AutoLock lock(list_lock_);
+      typename ObserversListMap::iterator it =
+          observer_lists_.find(base::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()) != NULL)
+        method.Run(obs);
+    }
+
+    // If there are no more observers on the list, we can now delete it.
+    if (context->list.size() == 0) {
+      {
+        base::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(base::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<base::PlatformThreadId, ObserverListContext*>
+      ObserversListMap;
+
+  mutable base::Lock list_lock_;  // Protects the observer_lists_.
+  ObserversListMap observer_lists_;
+  const NotificationType type_;
+
+  DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
+};
+
+#endif  // BASE_OBSERVER_LIST_THREADSAFE_H_
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
new file mode 100644
index 0000000..1650d3e
--- /dev/null
+++ b/base/observer_list_unittest.cc
@@ -0,0 +1,549 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/memory/weak_ptr.h"
+#include "base/message_loop.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::PlatformThread;
+using base::Time;
+
+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) {}
+  virtual void Observe(int x) OVERRIDE {
+    total += x * scaler_;
+  }
+  virtual ~Adder() {}
+  int total;
+
+ private:
+  int scaler_;
+};
+
+class Disrupter : public Foo {
+ public:
+  Disrupter(ObserverList<Foo>* list, Foo* doomed)
+      : list_(list),
+        doomed_(doomed) {
+  }
+  virtual ~Disrupter() {}
+  virtual 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) {
+  }
+  virtual ~ThreadSafeDisrupter() {}
+  virtual 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) {
+  }
+
+  virtual 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_(NULL),
+        in_list_(false),
+        start_(Time::Now()),
+        count_observes_(0),
+        count_addtask_(0),
+        do_notifies_(notify),
+        ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
+  }
+
+  virtual ~AddRemoveThread() {
+  }
+
+  virtual void ThreadMain() OVERRIDE {
+    loop_ = new MessageLoop();  // Fire up a message loop.
+    loop_->PostTask(
+        FROM_HERE,
+        base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
+    loop_->Run();
+    //LOG(ERROR) << "Loop 0x" << std::hex << loop_ << " done. " <<
+    //    count_observes_ << ", " << count_addtask_;
+    delete loop_;
+    loop_ = reinterpret_cast<MessageLoop*>(0xdeadbeef);
+    delete this;
+  }
+
+  // This task just keeps posting to itself in an attempt
+  // to race with the notifier.
+  void AddTask() {
+    count_addtask_++;
+
+    if ((Time::Now() - start_).InMilliseconds() > kThreadRunTime) {
+      VLOG(1) << "DONE!";
+      return;
+    }
+
+    if (!in_list_) {
+      list_->AddObserver(this);
+      in_list_ = true;
+    }
+
+    if (do_notifies_) {
+      list_->Notify(&Foo::Observe, 10);
+    }
+
+    loop_->PostTask(
+        FROM_HERE,
+        base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
+  }
+
+  void Quit() {
+    loop_->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+  }
+
+  virtual 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);
+
+  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(&Foo::Observe, 10);
+  loop.RunUntilIdle();
+
+  observer_list->AddObserver(&evil);
+  observer_list->AddObserver(&c);
+  observer_list->AddObserver(&d);
+
+  observer_list->Notify(&Foo::Observe, 10);
+  loop.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(&Foo::Observe, 10);
+  loop.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(&Foo::Observe, 10);
+  loop.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(&Foo::Observe, 10);
+    loop.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(&Foo::Observe, 20);
+    loop.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(&Foo::Observe, 30);
+  loop.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) {}
+  virtual ~FooRemover() {}
+
+  void AddFooToRemove(Foo* foo) {
+    foos_.push_back(foo);
+  }
+
+  virtual 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);
+  Adder b(1);
+
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  a.AddFooToRemove(&a);
+  a.AddFooToRemove(&b);
+
+  observer_list->Notify(&Foo::Observe, 1);
+  loop.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(&Foo::Observe, 10);
+
+    loop.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(&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
+  // notificaiton.
+  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(&Foo::Observe, 1);
+  loop.RunUntilIdle();
+
+  EXPECT_TRUE(b.added);
+  // B's adder should not have been notified because it was added during
+  // notificaiton.
+  EXPECT_EQ(0, b.adder.total);
+
+  // Notify again to make sure b's adder is notified.
+  observer_list->Notify(&Foo::Observe, 1);
+  loop.RunUntilIdle();
+  EXPECT_EQ(1, b.adder.total);
+}
+
+class AddInClearObserve : public Foo {
+ public:
+  explicit AddInClearObserve(ObserverList<Foo>* list)
+      : list_(list), added_(false), adder_(1) {}
+
+  virtual 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) {}
+  virtual ~ListDestructor() {}
+
+  virtual 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
diff --git a/base/os_compat_android.cc b/base/os_compat_android.cc
new file mode 100644
index 0000000..d434c5b
--- /dev/null
+++ b/base/os_compat_android.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/os_compat_android.h"
+
+#include <errno.h>
+#include <math.h>
+#include <sys/stat.h>
+#include <time64.h>
+
+#include "base/rand_util.h"
+#include "base/string_piece.h"
+#include "base/stringprintf.h"
+
+// There is no futimes() avaiable in Bionic, so we provide our own
+// implementation until it is there.
+extern "C" {
+
+int futimes(int fd, const struct timeval tv[2]) {
+  const std::string fd_path = StringPrintf("/proc/self/fd/%d", fd);
+  return utimes(fd_path.c_str(), tv);
+}
+
+// Android has only timegm64() and no 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 = ~(1 << (sizeof(time_t) * CHAR_BIT - 1));
+  static const time_t kTimeMin = (1 << (sizeof(time_t) * CHAR_BIT - 1));
+  time64_t result = timegm64(t);
+  if (result < kTimeMin || result > kTimeMax)
+    return -1;
+  return result;
+}
+
+// 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__)
+
+// For the record, Clang does not support the 'optimize' attribute.
+// In the unlikely event that it begins performing this optimization too,
+// we'll have to find a different way to achieve this. NOTE: Tested with O1
+// which still performs the optimization.
+//
+#define GCC_NO_OPTIMIZE  __attribute__((optimize("O0")))
+
+GCC_NO_OPTIMIZE
+void sincos(double angle, double* s, double *c) {
+  *c = cos(angle);
+  *s = sin(angle);
+}
+
+GCC_NO_OPTIMIZE
+void sincosf(float angle, float* s, float* c) {
+  *c = cosf(angle);
+  *s = sinf(angle);
+}
+
+#endif // __GNUC__ && !__clang__
+
+// An implementation of mkdtemp, since it is not exposed by the NDK
+// for native API level 9 that we target.
+//
+// For any changes in the mkdtemp function, you should manually run the unittest
+// OsCompatAndroidTest.DISABLED_TestMkdTemp in your local machine to check if it
+// passes. Please don't enable it, since it creates a directory and may be
+// source of flakyness.
+char* mkdtemp(char* path) {
+  if (path == NULL) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  const int path_len = strlen(path);
+
+  // The last six characters of 'path' must be XXXXXX.
+  const base::StringPiece kSuffix("XXXXXX");
+  const int kSuffixLen = kSuffix.length();
+  if (!base::StringPiece(path, path_len).ends_with(kSuffix)) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  // If the path contains a directory, as in /tmp/foo/XXXXXXXX, make sure
+  // that /tmp/foo exists, otherwise we're going to loop a really long
+  // time for nothing below
+  char* dirsep = strrchr(path, '/');
+  if (dirsep != NULL) {
+    struct stat st;
+    int ret;
+
+    *dirsep = '\0';  // Terminating directory path temporarily
+
+    ret = stat(path, &st);
+
+    *dirsep = '/';  // Restoring directory separator
+    if (ret < 0)  // Directory probably does not exist
+      return NULL;
+    if (!S_ISDIR(st.st_mode)) {  // Not a directory
+      errno = ENOTDIR;
+      return NULL;
+    }
+  }
+
+  // Max number of tries using different random suffixes.
+  const int kMaxTries = 100;
+
+  // Now loop until we CAN create a directory by that name or we reach the max
+  // number of tries.
+  for (int i = 0; i < kMaxTries; ++i) {
+    // Fill the suffix XXXXXX with a random string composed of a-z chars.
+    for (int pos = 0; pos < kSuffixLen; ++pos) {
+      char rand_char = static_cast<char>(base::RandInt('a', 'z'));
+      path[path_len - kSuffixLen + pos] = rand_char;
+    }
+    if (mkdir(path, 0700) == 0) {
+      // We just created the directory succesfully.
+      return path;
+    }
+    if (errno != EEXIST) {
+      // The directory doesn't exist, but an error occured
+      return NULL;
+    }
+  }
+
+  // We reached the max number of tries.
+  return NULL;
+}
+
+}  // extern "C"
diff --git a/base/os_compat_android.h b/base/os_compat_android.h
new file mode 100644
index 0000000..0f25444
--- /dev/null
+++ b/base/os_compat_android.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OS_COMPAT_ANDROID_H_
+#define BASE_OS_COMPAT_ANDROID_H_
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <utime.h>
+
+// Not implemented in Bionic.
+extern "C" int futimes(int fd, const struct timeval tv[2]);
+
+// Not exposed or implemented in Bionic.
+extern "C" char* mkdtemp(char* path);
+
+// Android has no timegm().
+extern "C" time_t timegm(struct tm* const t);
+
+// The lockf() function is not available on Android; we translate to flock().
+#define F_LOCK LOCK_EX
+#define F_ULOCK LOCK_UN
+inline int lockf(int fd, int cmd, off_t ignored_len) {
+  return flock(fd, cmd);
+}
+
+#endif  // BASE_OS_COMPAT_ANDROID_H_
diff --git a/base/os_compat_android_unittest.cc b/base/os_compat_android_unittest.cc
new file mode 100644
index 0000000..c749b6a
--- /dev/null
+++ b/base/os_compat_android_unittest.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/os_compat_android.h"
+
+#include "base/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(file_util::GetTempDir(&tmp_dir));
+
+  // Not six XXXXXX at the suffix of the path.
+  FilePath sub_dir = tmp_dir.Append("XX");
+  std::string sub_dir_string = sub_dir.value();
+  // this should be OK since mkdtemp just replaces characters in place
+  char* buffer = const_cast<char*>(sub_dir_string.c_str());
+  EXPECT_EQ(NULL, mkdtemp(buffer));
+
+  // Directory does not exist
+  char invalid_path2[] = "doesntoexist/foobarXXXXXX";
+  EXPECT_EQ(NULL, mkdtemp(invalid_path2));
+
+  // Successfully create a tmp dir.
+  FilePath sub_dir2 = tmp_dir.Append("XXXXXX");
+  std::string sub_dir2_string = sub_dir2.value();
+  // this should be OK since mkdtemp just replaces characters in place
+  char* buffer2 = const_cast<char*>(sub_dir2_string.c_str());
+  EXPECT_TRUE(mkdtemp(buffer2) != NULL);
+}
+
+}  // namespace base
diff --git a/base/os_compat_nacl.cc b/base/os_compat_nacl.cc
new file mode 100644
index 0000000..58fe93e
--- /dev/null
+++ b/base/os_compat_nacl.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/os_compat_nacl.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+#if !defined (__GLIBC__)
+
+extern "C" {
+// Native Client has no timegm().
+time_t timegm(struct tm* tm) {
+  time_t ret;
+  char* tz;
+  tz = getenv("TZ");
+  setenv("TZ", "", 1);
+  tzset();
+  ret = mktime(tm);
+  if (tz)
+    setenv("TZ", tz, 1);
+  else
+    unsetenv("TZ");
+  tzset();
+  return ret;
+}
+}  // extern "C"
+
+#endif  // !defined (__GLIBC__)
diff --git a/base/os_compat_nacl.h b/base/os_compat_nacl.h
new file mode 100644
index 0000000..13e0e3f
--- /dev/null
+++ b/base/os_compat_nacl.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OS_COMPAT_NACL_H_
+#define BASE_OS_COMPAT_NACL_H_
+
+#include <sys/types.h>
+
+#if !defined (__GLIBC__)
+// NaCl has no timegm().
+extern "C" time_t timegm(struct tm* const t);
+#endif  // !defined (__GLIBC__)
+
+#endif  // BASE_OS_COMPAT_NACL_H_
+
diff --git a/base/path_service.cc b/base/path_service.cc
new file mode 100644
index 0000000..2697653
--- /dev/null
+++ b/base/path_service.cc
@@ -0,0 +1,313 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/path_service.h"
+
+#ifdef OS_WIN
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#endif
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+  bool PathProvider(int key, FilePath* result);
+#if defined(OS_WIN)
+  bool PathProviderWin(int key, FilePath* result);
+#elif defined(OS_MACOSX)
+  bool PathProviderMac(int key, FilePath* result);
+#elif defined(OS_ANDROID)
+  bool PathProviderAndroid(int key, FilePath* result);
+#elif defined(OS_POSIX)
+  // PathProviderPosix is the default path provider on POSIX OSes other than
+  // Mac and Android.
+  bool PathProviderPosix(int key, FilePath* result);
+#endif
+}
+
+namespace {
+
+typedef base::hash_map<int, FilePath> PathMap;
+
+// We keep a linked list of providers.  In a debug build we ensure that no two
+// providers claim overlapping keys.
+struct Provider {
+  PathService::ProviderFunc func;
+  struct Provider* next;
+#ifndef NDEBUG
+  int key_start;
+  int key_end;
+#endif
+  bool is_static;
+};
+
+Provider base_provider = {
+  base::PathProvider,
+  NULL,
+#ifndef NDEBUG
+  base::PATH_START,
+  base::PATH_END,
+#endif
+  true
+};
+
+#if defined(OS_WIN)
+Provider base_provider_win = {
+  base::PathProviderWin,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_WIN_START,
+  base::PATH_WIN_END,
+#endif
+  true
+};
+#endif
+
+#if defined(OS_MACOSX)
+Provider base_provider_mac = {
+  base::PathProviderMac,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_MAC_START,
+  base::PATH_MAC_END,
+#endif
+  true
+};
+#endif
+
+#if defined(OS_ANDROID)
+Provider base_provider_android = {
+  base::PathProviderAndroid,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_ANDROID_START,
+  base::PATH_ANDROID_END,
+#endif
+  true
+};
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+Provider base_provider_posix = {
+  base::PathProviderPosix,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_POSIX_START,
+  base::PATH_POSIX_END,
+#endif
+  true
+};
+#endif
+
+
+struct PathData {
+  base::Lock lock;
+  PathMap cache;        // Cache mappings from path key to path value.
+  PathMap overrides;    // Track path overrides.
+  Provider* providers;  // Linked list of path service providers.
+
+  PathData() {
+#if defined(OS_WIN)
+    providers = &base_provider_win;
+#elif defined(OS_MACOSX)
+    providers = &base_provider_mac;
+#elif defined(OS_ANDROID)
+    providers = &base_provider_android;
+#elif defined(OS_POSIX)
+    providers = &base_provider_posix;
+#endif
+  }
+
+  ~PathData() {
+    Provider* p = providers;
+    while (p) {
+      Provider* next = p->next;
+      if (!p->is_static)
+        delete p;
+      p = next;
+    }
+  }
+};
+
+static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
+
+static PathData* GetPathData() {
+  return g_path_data.Pointer();
+}
+
+// Tries to find |key| in the cache. |path_data| should be locked by the caller!
+bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) {
+  // check for a cached version
+  PathMap::const_iterator it = path_data->cache.find(key);
+  if (it != path_data->cache.end()) {
+    *result = it->second;
+    return true;
+  }
+  return false;
+}
+
+// Tries to find |key| in the overrides map. |path_data| should be locked by the
+// caller!
+bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) {
+  // check for an overridden version.
+  PathMap::const_iterator it = path_data->overrides.find(key);
+  if (it != path_data->overrides.end()) {
+    path_data->cache[key] = it->second;
+    *result = it->second;
+    return true;
+  }
+  return false;
+}
+
+}  // namespace
+
+// TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
+// characters). This isn't supported very well by Windows right now, so it is
+// moot, but we should keep this in mind for the future.
+// static
+bool PathService::Get(int key, FilePath* result) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+  DCHECK(result);
+  DCHECK_GE(key, base::DIR_CURRENT);
+
+  // special case the current directory because it can never be cached
+  if (key == base::DIR_CURRENT)
+    return file_util::GetCurrentDirectory(result);
+
+  Provider* provider = NULL;
+  {
+    base::AutoLock scoped_lock(path_data->lock);
+    if (LockedGetFromCache(key, path_data, result))
+      return true;
+
+    if (LockedGetFromOverrides(key, path_data, result))
+      return true;
+
+    // Get the beginning of the list while it is still locked.
+    provider = path_data->providers;
+  }
+
+  FilePath path;
+
+  // Iterating does not need the lock because only the list head might be
+  // modified on another thread.
+  while (provider) {
+    if (provider->func(key, &path))
+      break;
+    DCHECK(path.empty()) << "provider should not have modified path";
+    provider = provider->next;
+  }
+
+  if (path.empty())
+    return false;
+
+  *result = path;
+
+  base::AutoLock scoped_lock(path_data->lock);
+  path_data->cache[key] = path;
+
+  return true;
+}
+
+// static
+bool PathService::Override(int key, const FilePath& path) {
+  // Just call the full function with true for the value of |create|.
+  return OverrideAndCreateIfNeeded(key, path, true);
+}
+
+// static
+bool PathService::OverrideAndCreateIfNeeded(int key,
+                                            const FilePath& path,
+                                            bool create) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+  DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key";
+
+  FilePath file_path = path;
+
+  // For some locations this will fail if called from inside the sandbox there-
+  // fore we protect this call with a flag.
+  if (create) {
+    // Make sure the directory exists. We need to do this before we translate
+    // this to the absolute path because on POSIX, AbsolutePath fails if called
+    // on a non-existent path.
+    if (!file_util::PathExists(file_path) &&
+        !file_util::CreateDirectory(file_path))
+      return false;
+  }
+
+  // We need to have an absolute path, as extensions and plugins don't like
+  // relative paths, and will gladly crash the browser in CHECK()s if they get a
+  // relative path.
+  if (!file_util::AbsolutePath(&file_path))
+    return false;
+
+  base::AutoLock scoped_lock(path_data->lock);
+
+  // Clear the cache now. Some of its entries could have depended
+  // on the value we are overriding, and are now out of sync with reality.
+  path_data->cache.clear();
+
+  path_data->overrides[key] = file_path;
+
+  return true;
+}
+
+// static
+bool PathService::RemoveOverride(int key) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+
+  base::AutoLock scoped_lock(path_data->lock);
+
+  if (path_data->overrides.find(key) == path_data->overrides.end())
+    return false;
+
+  // Clear the cache now. Some of its entries could have depended on the value
+  // we are going to remove, and are now out of sync.
+  path_data->cache.clear();
+
+  path_data->overrides.erase(key);
+
+  return true;
+}
+
+// static
+void PathService::RegisterProvider(ProviderFunc func, int key_start,
+                                   int key_end) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+  DCHECK_GT(key_end, key_start);
+
+  Provider* p;
+
+  p = new Provider;
+  p->is_static = false;
+  p->func = func;
+#ifndef NDEBUG
+  p->key_start = key_start;
+  p->key_end = key_end;
+#endif
+
+  base::AutoLock scoped_lock(path_data->lock);
+
+#ifndef NDEBUG
+  Provider *iter = path_data->providers;
+  while (iter) {
+    DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) <<
+      "path provider collision";
+    iter = iter->next;
+  }
+#endif
+
+  p->next = path_data->providers;
+  path_data->providers = p;
+}
diff --git a/base/path_service.h b/base/path_service.h
new file mode 100644
index 0000000..94b0db3
--- /dev/null
+++ b/base/path_service.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_PATH_SERVICE_H_
+#define BASE_PATH_SERVICE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/base_paths.h"
+#include "base/gtest_prod_util.h"
+#include "build/build_config.h"
+
+class FilePath;
+
+namespace base {
+class ScopedPathOverride;
+}  // namespace
+
+// The path service is a global table mapping keys to file system paths.  It is
+// OK to use this service from multiple threads.
+//
+class BASE_EXPORT PathService {
+ public:
+  // Retrieves a path to a special directory or file and places it into the
+  // string pointed to by 'path'. If you ask for a directory it is guaranteed
+  // to NOT have a path separator at the end. For example, "c:\windows\temp"
+  // Directories are also guaranteed to exist when this function succeeds.
+  //
+  // Returns true if the directory or file was successfully retrieved. On
+  // failure, 'path' will not be changed.
+  static bool Get(int key, FilePath* path);
+
+  // Overrides the path to a special directory or file.  This cannot be used to
+  // change the value of DIR_CURRENT, but that should be obvious.  Also, if the
+  // path specifies a directory that does not exist, the directory will be
+  // created by this method.  This method returns true if successful.
+  //
+  // If the given path is relative, then it will be resolved against
+  // DIR_CURRENT.
+  //
+  // WARNING: Consumers of PathService::Get may expect paths to be constant
+  // over the lifetime of the app, so this method should be used with caution.
+  static bool Override(int key, const FilePath& path);
+
+  // This function does the same as PathService::Override but it takes an extra
+  // parameter |create| which guides whether the directory to be overriden must
+  // be created in case it doesn't exist already.
+  static bool OverrideAndCreateIfNeeded(int key,
+                                        const FilePath& path,
+                                        bool create);
+
+  // To extend the set of supported keys, you can register a path provider,
+  // which is just a function mirroring PathService::Get.  The ProviderFunc
+  // returns false if it cannot provide a non-empty path for the given key.
+  // Otherwise, true is returned.
+  //
+  // WARNING: This function could be called on any thread from which the
+  // PathService is used, so a the ProviderFunc MUST BE THREADSAFE.
+  //
+  typedef bool (*ProviderFunc)(int, FilePath*);
+
+  // Call to register a path provider.  You must specify the range "[key_start,
+  // key_end)" of supported path keys.
+  static void RegisterProvider(ProviderFunc provider,
+                               int key_start,
+                               int key_end);
+
+ private:
+  friend class base::ScopedPathOverride;
+  FRIEND_TEST_ALL_PREFIXES(PathServiceTest, RemoveOverride);
+
+  // Removes an override for a special directory or file. Returns true if there
+  // was an override to remove or false if none was present.
+  // NOTE: This function is intended to be used by tests only!
+  static bool RemoveOverride(int key);
+};
+
+#endif  // BASE_PATH_SERVICE_H_
diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc
new file mode 100644
index 0000000..eef334b
--- /dev/null
+++ b/base/path_service_unittest.cc
@@ -0,0 +1,205 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/path_service.h"
+
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/file_path.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/platform_test.h"
+
+#if defined(OS_WIN)
+#include <userenv.h>
+#include "base/win/windows_version.h"
+// userenv.dll is required for GetDefaultUserProfileDirectory().
+#pragma comment(lib, "userenv.lib")
+#endif
+
+namespace {
+
+// Returns true if PathService::Get returns true and sets the path parameter
+// to non-empty for the given PathService::DirType enumeration value.
+bool ReturnsValidPath(int dir_type) {
+  FilePath path;
+  bool result = PathService::Get(dir_type, &path);
+  // Some paths might not exist on some platforms in which case confirming
+  // |result| is true and !path.empty() is the best we can do.
+  bool check_path_exists = true;
+#if defined(OS_POSIX)
+  // If chromium has never been started on this account, the cache path may not
+  // exist.
+  if (dir_type == base::DIR_CACHE)
+    check_path_exists = false;
+#endif
+#if defined(OS_LINUX)
+  // On the linux try-bots: a path is returned (e.g. /home/chrome-bot/Desktop),
+  // but it doesn't exist.
+  if (dir_type == base::DIR_USER_DESKTOP)
+    check_path_exists = false;
+#endif
+#if defined(OS_WIN)
+  if (dir_type == base::DIR_DEFAULT_USER_QUICK_LAUNCH) {
+    // On Windows XP, the Quick Launch folder for the "Default User" doesn't
+    // exist by default. At least confirm that the path returned begins with the
+    // Default User's profile path.
+    if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+      wchar_t default_profile_path[MAX_PATH];
+      DWORD size = arraysize(default_profile_path);
+      return (result &&
+              ::GetDefaultUserProfileDirectory(default_profile_path, &size) &&
+              StartsWith(path.value(), default_profile_path, false));
+    }
+  } else if (dir_type == base::DIR_TASKBAR_PINS) {
+    // There is no pinned-to-taskbar shortcuts prior to Win7.
+    if(base::win::GetVersion() < base::win::VERSION_WIN7)
+      check_path_exists = false;
+  }
+#endif
+  return result && !path.empty() && (!check_path_exists ||
+                                     file_util::PathExists(path));
+}
+
+#if defined(OS_WIN)
+// Function to test any directory keys that are not supported on some versions
+// of Windows. Checks that the function fails and that the returned path is
+// empty.
+bool ReturnsInvalidPath(int dir_type) {
+  FilePath path;
+  bool result = PathService::Get(dir_type, &path);
+  return !result && path.empty();
+}
+#endif
+
+}  // namespace
+
+// On the Mac this winds up using some autoreleased objects, so we need to
+// be a PlatformTest.
+typedef PlatformTest PathServiceTest;
+
+// Test that all PathService::Get calls return a value and a true result
+// in the development environment.  (This test was created because a few
+// later changes to Get broke the semantics of the function and yielded the
+// correct value while returning false.)
+TEST_F(PathServiceTest, Get) {
+  for (int key = base::PATH_START + 1; key < base::PATH_END; ++key) {
+#if defined(OS_ANDROID)
+    if (key == base::FILE_MODULE || key == base::DIR_USER_DESKTOP)
+      continue;  // Android doesn't implement FILE_MODULE and DIR_USER_DESKTOP;
+#elif defined(OS_IOS)
+    if (key == base::DIR_USER_DESKTOP)
+      continue;  // iOS doesn't implement DIR_USER_DESKTOP;
+#endif
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#if defined(OS_WIN)
+  for (int key = base::PATH_WIN_START + 1; key < base::PATH_WIN_END; ++key) {
+    bool valid = true;
+    switch(key) {
+      case base::DIR_LOCAL_APP_DATA_LOW:
+        // DIR_LOCAL_APP_DATA_LOW is not supported prior Vista and is expected
+        // to fail.
+        valid = base::win::GetVersion() >= base::win::VERSION_VISTA;
+        break;
+      case base::DIR_APP_SHORTCUTS:
+        // DIR_APP_SHORTCUTS is not supported prior Windows 8 and is expected to
+        // fail.
+        valid = base::win::GetVersion() >= base::win::VERSION_WIN8;
+        break;
+    }
+
+    if (valid)
+      EXPECT_TRUE(ReturnsValidPath(key)) << key;
+    else
+      EXPECT_TRUE(ReturnsInvalidPath(key)) << key;
+  }
+#elif defined(OS_MACOSX)
+  for (int key = base::PATH_MAC_START + 1; key < base::PATH_MAC_END; ++key) {
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#elif defined(OS_ANDROID)
+  for (int key = base::PATH_ANDROID_START + 1; key < base::PATH_ANDROID_END;
+       ++key) {
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#elif defined(OS_POSIX)
+  for (int key = base::PATH_POSIX_START + 1; key < base::PATH_POSIX_END;
+       ++key) {
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#endif
+}
+
+// test that all versions of the Override function of PathService do what they
+// are supposed to do.
+TEST_F(PathServiceTest, Override) {
+  int my_special_key = 666;
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath fake_cache_dir(temp_dir.path().AppendASCII("cache"));
+  // PathService::Override should always create the path provided if it doesn't
+  // exist.
+  EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir));
+  EXPECT_TRUE(file_util::PathExists(fake_cache_dir));
+
+  FilePath fake_cache_dir2(temp_dir.path().AppendASCII("cache2"));
+  // PathService::OverrideAndCreateIfNeeded should obey the |create| parameter.
+  PathService::OverrideAndCreateIfNeeded(my_special_key,
+                                         fake_cache_dir2,
+                                         false);
+  EXPECT_FALSE(file_util::PathExists(fake_cache_dir2));
+  EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
+                                                     fake_cache_dir2,
+                                                     true));
+  EXPECT_TRUE(file_util::PathExists(fake_cache_dir2));
+}
+
+// Check if multiple overrides can co-exist.
+TEST_F(PathServiceTest, OverrideMultiple) {
+  int my_special_key = 666;
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath fake_cache_dir1(temp_dir.path().AppendASCII("1"));
+  EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir1));
+  EXPECT_TRUE(file_util::PathExists(fake_cache_dir1));
+  ASSERT_EQ(1, file_util::WriteFile(fake_cache_dir1.AppendASCII("t1"), ".", 1));
+
+  FilePath fake_cache_dir2(temp_dir.path().AppendASCII("2"));
+  EXPECT_TRUE(PathService::Override(my_special_key + 1, fake_cache_dir2));
+  EXPECT_TRUE(file_util::PathExists(fake_cache_dir2));
+  ASSERT_EQ(1, file_util::WriteFile(fake_cache_dir2.AppendASCII("t2"), ".", 1));
+
+  FilePath result;
+  EXPECT_TRUE(PathService::Get(my_special_key, &result));
+  // Override might have changed the path representation but our test file
+  // should be still there.
+  EXPECT_TRUE(file_util::PathExists(result.AppendASCII("t1")));
+  EXPECT_TRUE(PathService::Get(my_special_key + 1, &result));
+  EXPECT_TRUE(file_util::PathExists(result.AppendASCII("t2")));
+}
+
+TEST_F(PathServiceTest, RemoveOverride) {
+  // Before we start the test we have to call RemoveOverride at least once to
+  // clear any overrides that might have been left from other tests.
+  PathService::RemoveOverride(base::DIR_TEMP);
+
+  FilePath original_user_data_dir;
+  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &original_user_data_dir));
+  EXPECT_FALSE(PathService::RemoveOverride(base::DIR_TEMP));
+
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  EXPECT_TRUE(PathService::Override(base::DIR_TEMP, temp_dir.path()));
+  FilePath new_user_data_dir;
+  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir));
+  EXPECT_NE(original_user_data_dir, new_user_data_dir);
+
+  EXPECT_TRUE(PathService::RemoveOverride(base::DIR_TEMP));
+  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir));
+  EXPECT_EQ(original_user_data_dir, new_user_data_dir);
+}
diff --git a/base/pending_task.cc b/base/pending_task.cc
new file mode 100644
index 0000000..b288f28
--- /dev/null
+++ b/base/pending_task.cc
@@ -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.
+
+#include "base/pending_task.h"
+
+#include "base/tracked_objects.h"
+
+namespace base {
+
+#if _MSC_VER >= 1700
+// This a temporary fix for compiling on VS2012. http://crbug.com/154744
+PendingTask::PendingTask() : sequence_num(-1), nestable(false) {
+}
+#endif
+
+PendingTask::PendingTask(const tracked_objects::Location& posted_from,
+                         const base::Closure& task)
+    : base::TrackingInfo(posted_from, TimeTicks()),
+      task(task),
+      posted_from(posted_from),
+      sequence_num(0),
+      nestable(true) {
+}
+
+PendingTask::PendingTask(const tracked_objects::Location& posted_from,
+                         const base::Closure& task,
+                         TimeTicks delayed_run_time,
+                         bool nestable)
+    : base::TrackingInfo(posted_from, delayed_run_time),
+      task(task),
+      posted_from(posted_from),
+      sequence_num(0),
+      nestable(nestable) {
+}
+
+PendingTask::~PendingTask() {
+}
+
+bool PendingTask::operator<(const PendingTask& other) const {
+  // Since the top of a priority queue is defined as the "greatest" element, we
+  // need to invert the comparison here.  We want the smaller time to be at the
+  // top of the heap.
+
+  if (delayed_run_time < other.delayed_run_time)
+    return false;
+
+  if (delayed_run_time > other.delayed_run_time)
+    return true;
+
+  // If the times happen to match, then we use the sequence number to decide.
+  // Compare the difference to support integer roll-over.
+  return (sequence_num - other.sequence_num) > 0;
+}
+
+void TaskQueue::Swap(TaskQueue* queue) {
+  c.swap(queue->c);  // Calls std::deque::swap.
+}
+
+}  // namespace base
diff --git a/base/pending_task.h b/base/pending_task.h
new file mode 100644
index 0000000..6e4a2dd
--- /dev/null
+++ b/base/pending_task.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PENDING_TASK_H_
+#define PENDING_TASK_H_
+
+#include <queue>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/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 {
+#if _MSC_VER >= 1700
+  PendingTask();
+#endif
+  PendingTask(const tracked_objects::Location& posted_from,
+              const Closure& task);
+  PendingTask(const tracked_objects::Location& posted_from,
+              const Closure& task,
+              TimeTicks delayed_run_time,
+              bool nestable);
+  ~PendingTask();
+
+  // Used to support sorting.
+  bool operator<(const PendingTask& other) const;
+
+  // The task to run.
+  Closure task;
+
+  // The site this PendingTask was posted from.
+  tracked_objects::Location posted_from;
+
+  // Secondary sort key for run time.
+  int sequence_num;
+
+  // OK to dispatch from a nested loop.
+  bool nestable;
+};
+
+// Wrapper around std::queue specialized for PendingTask which adds a Swap
+// helper method.
+class BASE_EXPORT TaskQueue : public std::queue<PendingTask> {
+ public:
+  void Swap(TaskQueue* queue);
+};
+
+// PendingTasks are sorted by their |delayed_run_time| property.
+typedef std::priority_queue<base::PendingTask> DelayedTaskQueue;
+
+}  // namespace base
+
+#endif  // PENDING_TASK_H_
diff --git a/base/perftimer.cc b/base/perftimer.cc
new file mode 100644
index 0000000..4c64c5e
--- /dev/null
+++ b/base/perftimer.cc
@@ -0,0 +1,45 @@
+// 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/perftimer.h"
+
+#include <stdio.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+
+static FILE* perf_log_file = NULL;
+
+bool InitPerfLog(const FilePath& log_file) {
+  if (perf_log_file) {
+    // trying to initialize twice
+    NOTREACHED();
+    return false;
+  }
+
+  perf_log_file = file_util::OpenFile(log_file, "w");
+  return perf_log_file != NULL;
+}
+
+void FinalizePerfLog() {
+  if (!perf_log_file) {
+    // trying to cleanup without initializing
+    NOTREACHED();
+    return;
+  }
+  file_util::CloseFile(perf_log_file);
+}
+
+void LogPerfResult(const char* test_name, double value, const char* units) {
+  if (!perf_log_file) {
+    NOTREACHED();
+    return;
+  }
+
+  fprintf(perf_log_file, "%s\t%g\t%s\n", test_name, value, units);
+  printf("%s\t%g\t%s\n", test_name, value, units);
+}
diff --git a/base/perftimer.h b/base/perftimer.h
new file mode 100644
index 0000000..1ac1a7d
--- /dev/null
+++ b/base/perftimer.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PERFTIMER_H_
+#define BASE_PERFTIMER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/time.h"
+
+class FilePath;
+
+// ----------------------------------------------------------------------
+// Initializes and finalizes the perf log. These functions should be
+// called at the beginning and end (respectively) of running all the
+// performance tests. The init function returns true on success.
+// ----------------------------------------------------------------------
+bool InitPerfLog(const FilePath& log_path);
+void FinalizePerfLog();
+
+// ----------------------------------------------------------------------
+// LogPerfResult
+//   Writes to the perf result log the given 'value' resulting from the
+//   named 'test'. The units are to aid in reading the log by people.
+// ----------------------------------------------------------------------
+void LogPerfResult(const char* test_name, double value, const char* units);
+
+// ----------------------------------------------------------------------
+// PerfTimer
+//   A simple wrapper around Now()
+// ----------------------------------------------------------------------
+class PerfTimer {
+ public:
+  PerfTimer() {
+    begin_ = base::TimeTicks::Now();
+  }
+
+  // Returns the time elapsed since object construction
+  base::TimeDelta Elapsed() const {
+    return base::TimeTicks::Now() - begin_;
+  }
+
+ private:
+  base::TimeTicks begin_;
+};
+
+// ----------------------------------------------------------------------
+// PerfTimeLogger
+//   Automates calling LogPerfResult for the common case where you want
+//   to measure the time that something took. Call Done() when the test
+//   is complete if you do extra work after the test or there are stack
+//   objects with potentially expensive constructors. Otherwise, this
+//   class with automatically log on destruction.
+// ----------------------------------------------------------------------
+class PerfTimeLogger {
+ public:
+  explicit PerfTimeLogger(const char* test_name)
+      : logged_(false),
+        test_name_(test_name) {
+  }
+
+  ~PerfTimeLogger() {
+    if (!logged_)
+      Done();
+  }
+
+  void Done() {
+    // we use a floating-point millisecond value because it is more
+    // intuitive than microseconds and we want more precision than
+    // integer milliseconds
+    LogPerfResult(test_name_.c_str(), timer_.Elapsed().InMillisecondsF(), "ms");
+    logged_ = true;
+  }
+
+ private:
+  bool logged_;
+  std::string test_name_;
+  PerfTimer timer_;
+};
+
+#endif  // BASE_PERFTIMER_H_
diff --git a/base/pickle.cc b/base/pickle.cc
new file mode 100644
index 0000000..0e44131
--- /dev/null
+++ b/base/pickle.cc
@@ -0,0 +1,357 @@
+// Copyright (c) 2012 The Chromium Authors. All 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()
+
+//------------------------------------------------------------------------------
+
+// static
+const int Pickle::kPayloadUnit = 64;
+
+static const size_t kCapacityReadOnly = static_cast<size_t>(-1);
+
+PickleIterator::PickleIterator(const Pickle& pickle)
+    : read_ptr_(pickle.payload()),
+      read_end_ptr_(pickle.end_of_payload()) {
+}
+
+template <typename Type>
+inline bool PickleIterator::ReadBuiltinType(Type* result) {
+  const char* read_from = GetReadPointerAndAdvance<Type>();
+  if (!read_from)
+    return false;
+  if (sizeof(Type) > sizeof(uint32))
+    memcpy(result, read_from, sizeof(*result));
+  else
+    *result = *reinterpret_cast<const Type*>(read_from);
+  return true;
+}
+
+template<typename Type>
+inline const char* PickleIterator::GetReadPointerAndAdvance() {
+  const char* current_read_ptr = read_ptr_;
+  if (read_ptr_ + sizeof(Type) > read_end_ptr_)
+    return NULL;
+  if (sizeof(Type) < sizeof(uint32))
+    read_ptr_ += AlignInt(sizeof(Type), sizeof(uint32));
+  else
+    read_ptr_ += sizeof(Type);
+  return current_read_ptr;
+}
+
+const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
+  if (num_bytes < 0 || read_end_ptr_ - read_ptr_ < num_bytes)
+    return NULL;
+  const char* current_read_ptr = read_ptr_;
+  read_ptr_ += AlignInt(num_bytes, sizeof(uint32));
+  return current_read_ptr;
+}
+
+inline const char* PickleIterator::GetReadPointerAndAdvance(int num_elements,
+                                                          size_t size_element) {
+  // Check for int32 overflow.
+  int64 num_bytes = static_cast<int64>(num_elements) * size_element;
+  int num_bytes32 = static_cast<int>(num_bytes);
+  if (num_bytes != static_cast<int64>(num_bytes32))
+    return NULL;
+  return GetReadPointerAndAdvance(num_bytes32);
+}
+
+bool PickleIterator::ReadBool(bool* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadInt(int* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadLong(long* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt16(uint16* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt32(uint32* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadInt64(int64* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt64(uint64* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::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::ReadWString(std::wstring* result) {
+  int len;
+  if (!ReadInt(&len))
+    return false;
+  const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t));
+  if (!read_from)
+    return false;
+
+  result->assign(reinterpret_cast<const wchar_t*>(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::ReadData(const char** data, int* length) {
+  *length = 0;
+  *data = 0;
+
+  if (!ReadInt(length))
+    return false;
+
+  return ReadBytes(data, *length);
+}
+
+bool PickleIterator::ReadBytes(const char** data, int length) {
+  const char* read_from = GetReadPointerAndAdvance(length);
+  if (!read_from)
+    return false;
+  *data = read_from;
+  return true;
+}
+
+// Payload is uint32 aligned.
+
+Pickle::Pickle()
+    : header_(NULL),
+      header_size_(sizeof(Header)),
+      capacity_(0),
+      variable_buffer_offset_(0) {
+  Resize(kPayloadUnit);
+  header_->payload_size = 0;
+}
+
+Pickle::Pickle(int header_size)
+    : header_(NULL),
+      header_size_(AlignInt(header_size, sizeof(uint32))),
+      capacity_(0),
+      variable_buffer_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_(kCapacityReadOnly),
+      variable_buffer_offset_(0) {
+  if (data_len >= static_cast<int>(sizeof(Header)))
+    header_size_ = data_len - header_->payload_size;
+
+  if (header_size_ > static_cast<unsigned int>(data_len))
+    header_size_ = 0;
+
+  if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
+    header_size_ = 0;
+
+  // If there is anything wrong with the data, we're not going to use it.
+  if (!header_size_)
+    header_ = NULL;
+}
+
+Pickle::Pickle(const Pickle& other)
+    : header_(NULL),
+      header_size_(other.header_size_),
+      capacity_(0),
+      variable_buffer_offset_(other.variable_buffer_offset_) {
+  size_t payload_size = header_size_ + other.header_->payload_size;
+  bool resized = Resize(payload_size);
+  CHECK(resized);  // Realloc failed.
+  memcpy(header_, other.header_, payload_size);
+}
+
+Pickle::~Pickle() {
+  if (capacity_ != kCapacityReadOnly)
+    free(header_);
+}
+
+Pickle& Pickle::operator=(const Pickle& other) {
+  if (this == &other) {
+    NOTREACHED();
+    return *this;
+  }
+  if (capacity_ == kCapacityReadOnly) {
+    header_ = NULL;
+    capacity_ = 0;
+  }
+  if (header_size_ != other.header_size_) {
+    free(header_);
+    header_ = NULL;
+    header_size_ = other.header_size_;
+  }
+  bool resized = Resize(other.header_size_ + other.header_->payload_size);
+  CHECK(resized);  // Realloc failed.
+  memcpy(header_, other.header_,
+         other.header_size_ + other.header_->payload_size);
+  variable_buffer_offset_ = other.variable_buffer_offset_;
+  return *this;
+}
+
+bool Pickle::WriteString(const std::string& value) {
+  if (!WriteInt(static_cast<int>(value.size())))
+    return false;
+
+  return WriteBytes(value.data(), static_cast<int>(value.size()));
+}
+
+bool Pickle::WriteWString(const std::wstring& value) {
+  if (!WriteInt(static_cast<int>(value.size())))
+    return false;
+
+  return WriteBytes(value.data(),
+                    static_cast<int>(value.size() * sizeof(wchar_t)));
+}
+
+bool Pickle::WriteString16(const string16& 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 data_len) {
+  DCHECK_NE(kCapacityReadOnly, capacity_) << "oops: pickle is readonly";
+
+  char* dest = BeginWrite(data_len);
+  if (!dest)
+    return false;
+
+  memcpy(dest, data, data_len);
+
+  EndWrite(dest, data_len);
+  return true;
+}
+
+char* Pickle::BeginWriteData(int length) {
+  DCHECK_EQ(variable_buffer_offset_, 0U) <<
+    "There can only be one variable buffer in a Pickle";
+
+  if (length < 0 || !WriteInt(length))
+    return NULL;
+
+  char *data_ptr = BeginWrite(length);
+  if (!data_ptr)
+    return NULL;
+
+  variable_buffer_offset_ =
+      data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
+
+  // EndWrite doesn't necessarily have to be called after the write operation,
+  // so we call it here to pad out what the caller will eventually write.
+  EndWrite(data_ptr, length);
+  return data_ptr;
+}
+
+void Pickle::TrimWriteData(int new_length) {
+  DCHECK_NE(variable_buffer_offset_, 0U);
+
+  // Fetch the the variable buffer size
+  int* cur_length = reinterpret_cast<int*>(
+      reinterpret_cast<char*>(header_) + variable_buffer_offset_);
+
+  if (new_length < 0 || new_length > *cur_length) {
+    NOTREACHED() << "Invalid length in TrimWriteData.";
+    return;
+  }
+
+  // Update the payload size and variable buffer size
+  header_->payload_size -= (*cur_length - new_length);
+  *cur_length = new_length;
+}
+
+char* Pickle::BeginWrite(size_t length) {
+  // write at a uint32-aligned offset from the beginning of the header
+  size_t offset = AlignInt(header_->payload_size, sizeof(uint32));
+
+  size_t new_size = offset + length;
+  size_t needed_size = header_size_ + new_size;
+  if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
+    return NULL;
+
+#ifdef ARCH_CPU_64_BITS
+  DCHECK_LE(length, kuint32max);
+#endif
+
+  header_->payload_size = static_cast<uint32>(new_size);
+  return payload() + offset;
+}
+
+void Pickle::EndWrite(char* dest, int length) {
+  // Zero-pad to keep tools like valgrind from complaining about uninitialized
+  // memory.
+  if (length % sizeof(uint32))
+    memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32)));
+}
+
+bool Pickle::Resize(size_t new_capacity) {
+  new_capacity = AlignInt(new_capacity, kPayloadUnit);
+
+  CHECK_NE(capacity_, kCapacityReadOnly);
+  void* p = realloc(header_, new_capacity);
+  if (!p)
+    return false;
+
+  header_ = reinterpret_cast<Header*>(p);
+  capacity_ = new_capacity;
+  return true;
+}
+
+// static
+const char* Pickle::FindNext(size_t header_size,
+                             const char* start,
+                             const char* end) {
+  DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
+  DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
+
+  if (static_cast<size_t>(end - start) < sizeof(Header))
+    return NULL;
+
+  const Header* hdr = reinterpret_cast<const Header*>(start);
+  const char* payload_base = start + header_size;
+  const char* payload_end = payload_base + hdr->payload_size;
+  if (payload_end < payload_base)
+    return NULL;
+
+  return (payload_end > end) ? NULL : payload_end;
+}
diff --git a/base/pickle.h b/base/pickle.h
new file mode 100644
index 0000000..a92915f
--- /dev/null
+++ b/base/pickle.h
@@ -0,0 +1,343 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PICKLE_H__
+#define BASE_PICKLE_H__
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/string16.h"
+
+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() : read_ptr_(NULL), read_end_ptr_(NULL) {}
+  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.
+  bool ReadBool(bool* result) WARN_UNUSED_RESULT;
+  bool ReadInt(int* result) WARN_UNUSED_RESULT;
+  bool ReadLong(long* result) WARN_UNUSED_RESULT;
+  bool ReadUInt16(uint16* result) WARN_UNUSED_RESULT;
+  bool ReadUInt32(uint32* result) WARN_UNUSED_RESULT;
+  bool ReadInt64(int64* result) WARN_UNUSED_RESULT;
+  bool ReadUInt64(uint64* result) WARN_UNUSED_RESULT;
+  bool ReadString(std::string* result) WARN_UNUSED_RESULT;
+  bool ReadWString(std::wstring* result) WARN_UNUSED_RESULT;
+  bool ReadString16(string16* result) WARN_UNUSED_RESULT;
+  bool ReadData(const char** data, int* length) WARN_UNUSED_RESULT;
+  bool ReadBytes(const char** data, int length) WARN_UNUSED_RESULT;
+
+  // Safer version of ReadInt() checks for the result not being negative.
+  // Use it for reading the object sizes.
+  bool ReadLength(int* result) WARN_UNUSED_RESULT {
+    return ReadInt(result) && *result >= 0;
+  }
+
+  // Skips bytes in the read buffer and returns true if there are at least
+  // num_bytes available. Otherwise, does nothing and returns false.
+  bool SkipBytes(int num_bytes) WARN_UNUSED_RESULT {
+    return !!GetReadPointerAndAdvance(num_bytes);
+  }
+
+ private:
+  // Aligns 'i' by rounding it up to the next multiple of 'alignment'
+  static size_t AlignInt(size_t i, int alignment) {
+    return i + (alignment - (i % alignment)) % alignment;
+  }
+
+  // Read Type from Pickle.
+  template <typename Type>
+  inline bool ReadBuiltinType(Type* result);
+
+  // Get read pointer for Type and advance read pointer.
+  template<typename Type>
+  inline 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.
+  inline const char* GetReadPointerAndAdvance(int num_elements,
+                                              size_t size_element);
+
+  // Pointers to the Pickle data.
+  const char* read_ptr_;
+  const char* read_end_ptr_;
+
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, GetReadPointerAndAdvance);
+};
+
+// This class provides facilities for basic binary value packing and unpacking.
+//
+// The Pickle class supports appending primitive values (ints, strings, etc.)
+// to a pickle instance.  The Pickle instance grows its internal memory buffer
+// dynamically to hold the sequence of primitive values.   The internal memory
+// buffer is exposed as the "data" of the Pickle.  This "data" can be passed
+// to a Pickle object to initialize it for reading.
+//
+// When reading from a Pickle object, it is important for the consumer to know
+// what value types to read and in what order to read them as the Pickle does
+// not keep track of the type of data written to it.
+//
+// The Pickle's data has a header which contains the size of the Pickle's
+// payload.  It can optionally support additional space in the header.  That
+// space is controlled by the header_size parameter passed to the Pickle
+// constructor.
+//
+class BASE_EXPORT Pickle {
+ public:
+  // Initialize a Pickle object using the default header size.
+  Pickle();
+
+  // Initialize a Pickle object with the specified header size in bytes, which
+  // must be greater-than-or-equal-to sizeof(Pickle::Header).  The header size
+  // will be rounded up to ensure that the header size is 32bit-aligned.
+  explicit Pickle(int header_size);
+
+  // Initializes a Pickle from a const block of data.  The data is not copied;
+  // instead the data is merely referenced by this Pickle.  Only const methods
+  // should be used on the Pickle when initialized this way.  The header
+  // padding size is deduced from the data length.
+  Pickle(const char* data, int data_len);
+
+  // Initializes a Pickle as a deep copy of another Pickle.
+  Pickle(const Pickle& other);
+
+  // Note: There are no virtual methods in this class.  This destructor is
+  // virtual as an element of defensive coding.  Other classes have derived from
+  // this class, and there is a *chance* that they will cast into this base
+  // class before destruction.  At least one such class does have a virtual
+  // destructor, suggesting at least some need to call more derived destructors.
+  virtual ~Pickle();
+
+  // Performs a deep copy.
+  Pickle& operator=(const Pickle& other);
+
+  // Returns the size of the Pickle's data.
+  size_t size() const { return header_size_ + header_->payload_size; }
+
+  // Returns the data for this Pickle.
+  const void* data() const { return header_; }
+
+  // For compatibility, these older style read methods pass through to the
+  // PickleIterator methods.
+  // TODO(jbates) Remove these methods.
+  bool ReadBool(PickleIterator* iter, bool* result) const {
+    return iter->ReadBool(result);
+  }
+  bool ReadInt(PickleIterator* iter, int* result) const {
+    return iter->ReadInt(result);
+  }
+  bool ReadLong(PickleIterator* iter, long* result) const {
+    return iter->ReadLong(result);
+  }
+  bool ReadUInt16(PickleIterator* iter, uint16* result) const {
+    return iter->ReadUInt16(result);
+  }
+  bool ReadUInt32(PickleIterator* iter, uint32* result) const {
+    return iter->ReadUInt32(result);
+  }
+  bool ReadInt64(PickleIterator* iter, int64* result) const {
+    return iter->ReadInt64(result);
+  }
+  bool ReadUInt64(PickleIterator* iter, uint64* result) const {
+    return iter->ReadUInt64(result);
+  }
+  bool ReadString(PickleIterator* iter, std::string* result) const {
+    return iter->ReadString(result);
+  }
+  bool ReadWString(PickleIterator* iter, std::wstring* result) const {
+    return iter->ReadWString(result);
+  }
+  bool ReadString16(PickleIterator* iter, string16* result) const {
+    return iter->ReadString16(result);
+  }
+  // A pointer to the data will be placed in *data, and the length will be
+  // placed in *length. This buffer will be into the message's buffer so will
+  // be scoped to the lifetime of the message (or until the message data is
+  // mutated).
+  bool ReadData(PickleIterator* iter, const char** data, int* length) const {
+    return iter->ReadData(data, length);
+  }
+  // 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
+  // returned buffer will be into the message's buffer so will be scoped to the
+  // lifetime of the message (or until the message data is mutated).
+  bool ReadBytes(PickleIterator* iter, const char** data, int length) const {
+    return iter->ReadBytes(data, length);
+  }
+
+  // Safer version of ReadInt() checks for the result not being negative.
+  // Use it for reading the object sizes.
+  bool ReadLength(PickleIterator* iter, int* result) const {
+    return iter->ReadLength(result);
+  }
+
+  // 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 WriteBytes(&value, sizeof(value));
+  }
+  // WARNING: DO NOT USE THIS METHOD IF PICKLES ARE PERSISTED IN ANY WAY.
+  // It will write whatever a "long" is on this architecture. On 32-bit
+  // platforms, it is 32 bits. On 64-bit platforms, it is 64 bits. If persisted
+  // pickles are still around after upgrading to 64-bit, or if they are copied
+  // between dissimilar systems, YOUR PICKLES WILL HAVE GONE BAD.
+  bool WriteLongUsingDangerousNonPortableLessPersistableForm(long value) {
+    return WriteBytes(&value, sizeof(value));
+  }
+  bool WriteUInt16(uint16 value) {
+    return WriteBytes(&value, sizeof(value));
+  }
+  bool WriteUInt32(uint32 value) {
+    return WriteBytes(&value, sizeof(value));
+  }
+  bool WriteInt64(int64 value) {
+    return WriteBytes(&value, sizeof(value));
+  }
+  bool WriteUInt64(uint64 value) {
+    return WriteBytes(&value, sizeof(value));
+  }
+  bool WriteString(const std::string& value);
+  bool WriteWString(const std::wstring& value);
+  bool WriteString16(const string16& 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 lenght 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 data_len);
+
+  // Same as WriteData, but allows the caller to write directly into the
+  // Pickle. This saves a copy in cases where the data is not already
+  // available in a buffer. The caller should take care to not write more
+  // than the length it declares it will. Use ReadData to get the data.
+  // Returns NULL on failure.
+  //
+  // The returned pointer will only be valid until the next write operation
+  // on this Pickle.
+  char* BeginWriteData(int length);
+
+  // For Pickles which contain variable length buffers (e.g. those created
+  // with BeginWriteData), the Pickle can
+  // be 'trimmed' if the amount of data required is less than originally
+  // requested.  For example, you may have created a buffer with 10K of data,
+  // but decided to only fill 10 bytes of that data.  Use this function
+  // to trim the buffer so that we don't send 9990 bytes of unused data.
+  // You cannot increase the size of the variable buffer; only shrink it.
+  // This function assumes that the length of the variable buffer has
+  // not been changed.
+  void TrimWriteData(int length);
+
+  // Payload follows after allocation of Header (header size is customizable).
+  struct Header {
+    uint32 payload_size;  // Specifies the size of the payload.
+  };
+
+  // Returns the header, cast to a user-specified type T.  The type T must be a
+  // subclass of Header and its size must correspond to the header_size passed
+  // to the Pickle constructor.
+  template <class T>
+  T* headerT() {
+    DCHECK_EQ(header_size_, sizeof(T));
+    return static_cast<T*>(header_);
+  }
+  template <class T>
+  const T* headerT() const {
+    DCHECK_EQ(header_size_, sizeof(T));
+    return static_cast<const T*>(header_);
+  }
+
+  // The payload is the pickle data immediately following the header.
+  size_t payload_size() const { return header_->payload_size; }
+  const char* payload() const {
+    return reinterpret_cast<const char*>(header_) + header_size_;
+  }
+
+ protected:
+  char* payload() {
+    return reinterpret_cast<char*>(header_) + header_size_;
+  }
+
+  // Returns the address of the byte immediately following the currently valid
+  // header + payload.
+  char* end_of_payload() {
+    // We must have a valid header_.
+    return payload() + payload_size();
+  }
+  const char* end_of_payload() const {
+    // This object may be invalid.
+    return header_ ? payload() + payload_size() : NULL;
+  }
+
+  size_t capacity() const {
+    return capacity_;
+  }
+
+  // Resizes the buffer for use when writing the specified amount of data. The
+  // location that the data should be written at is returned, or NULL if there
+  // was an error. Call EndWrite with the returned offset and the given length
+  // to pad out for the next write.
+  char* BeginWrite(size_t length);
+
+  // Completes the write operation by padding the data with NULL bytes until it
+  // is padded. Should be paired with BeginWrite, but it does not necessarily
+  // have to be called after the data is written.
+  void EndWrite(char* dest, int length);
+
+  // Resize the capacity, note that the input value should include the size of
+  // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
+  // A realloc() failure will cause a Resize failure... and caller should check
+  // the return result for true (i.e., successful resizing).
+  bool Resize(size_t new_capacity);
+
+  // Aligns 'i' by rounding it up to the next multiple of 'alignment'
+  static size_t AlignInt(size_t i, int alignment) {
+    return i + (alignment - (i % alignment)) % alignment;
+  }
+
+  // Find the end of the pickled data that starts at range_start.  Returns NULL
+  // if the entire Pickle is not found in the given data range.
+  static const char* FindNext(size_t header_size,
+                              const char* range_start,
+                              const char* range_end);
+
+  // The allocation granularity of the payload.
+  static const int kPayloadUnit;
+
+ private:
+  friend class PickleIterator;
+
+  Header* header_;
+  size_t header_size_;  // Supports extra data between header and payload.
+  // Allocation size of payload (or -1 if allocation is const).
+  size_t capacity_;
+  size_t variable_buffer_offset_;  // IF non-zero, then offset to a buffer.
+
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader);
+};
+
+#endif  // BASE_PICKLE_H__
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
new file mode 100644
index 0000000..8cb1d2a
--- /dev/null
+++ b/base/pickle_unittest.cc
@@ -0,0 +1,336 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
+#include "base/string16.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const int testint = 2093847192;
+const std::string teststr("Hello world");  // note non-aligned string length
+const std::wstring testwstr(L"Hello, world");
+const char testdata[] = "AAA\0BBB\0";
+const int testdatalen = arraysize(testdata) - 1;
+const bool testbool1 = false;
+const bool testbool2 = true;
+const uint16 testuint16 = 32123;
+
+// checks that the result
+void VerifyResult(const Pickle& pickle) {
+  PickleIterator iter(pickle);
+
+  int outint;
+  EXPECT_TRUE(pickle.ReadInt(&iter, &outint));
+  EXPECT_EQ(testint, outint);
+
+  std::string outstr;
+  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
+  EXPECT_EQ(teststr, outstr);
+
+  std::wstring outwstr;
+  EXPECT_TRUE(pickle.ReadWString(&iter, &outwstr));
+  EXPECT_EQ(testwstr, outwstr);
+
+  bool outbool;
+  EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
+  EXPECT_EQ(testbool1, outbool);
+  EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
+  EXPECT_EQ(testbool2, outbool);
+
+  uint16 outuint16;
+  EXPECT_TRUE(pickle.ReadUInt16(&iter, &outuint16));
+  EXPECT_EQ(testuint16, outuint16);
+
+  const char* outdata;
+  int outdatalen;
+  EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
+  EXPECT_EQ(testdatalen, outdatalen);
+  EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);
+
+  EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
+  EXPECT_EQ(testdatalen, outdatalen);
+  EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);
+
+  // reads past the end should fail
+  EXPECT_FALSE(pickle.ReadInt(&iter, &outint));
+}
+
+}  // namespace
+
+TEST(PickleTest, EncodeDecode) {
+  Pickle pickle;
+
+  EXPECT_TRUE(pickle.WriteInt(testint));
+  EXPECT_TRUE(pickle.WriteString(teststr));
+  EXPECT_TRUE(pickle.WriteWString(testwstr));
+  EXPECT_TRUE(pickle.WriteBool(testbool1));
+  EXPECT_TRUE(pickle.WriteBool(testbool2));
+  EXPECT_TRUE(pickle.WriteUInt16(testuint16));
+  EXPECT_TRUE(pickle.WriteData(testdata, testdatalen));
+
+  // Over allocate BeginWriteData so we can test TrimWriteData.
+  char* dest = pickle.BeginWriteData(testdatalen + 100);
+  EXPECT_TRUE(dest);
+  memcpy(dest, testdata, testdatalen);
+
+  pickle.TrimWriteData(testdatalen);
+
+  VerifyResult(pickle);
+
+  // test copy constructor
+  Pickle pickle2(pickle);
+  VerifyResult(pickle2);
+
+  // test operator=
+  Pickle pickle3;
+  pickle3 = pickle;
+  VerifyResult(pickle3);
+}
+
+// Tests that we can handle really small buffers.
+TEST(PickleTest, SmallBuffer) {
+  scoped_array<char> buffer(new char[1]);
+
+  // We should not touch the buffer.
+  Pickle pickle(buffer.get(), 1);
+
+  PickleIterator iter(pickle);
+  int data;
+  EXPECT_FALSE(pickle.ReadInt(&iter, &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(pickle.ReadInt(&iter, &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(pickle.ReadInt(&iter, &data));
+}
+
+TEST(PickleTest, ZeroLenStr) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteString(""));
+
+  PickleIterator iter(pickle);
+  std::string outstr;
+  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
+  EXPECT_EQ("", outstr);
+}
+
+TEST(PickleTest, ZeroLenWStr) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteWString(L""));
+
+  PickleIterator iter(pickle);
+  std::string outstr;
+  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
+  EXPECT_EQ("", outstr);
+}
+
+TEST(PickleTest, BadLenStr) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteInt(-2));
+
+  PickleIterator iter(pickle);
+  std::string outstr;
+  EXPECT_FALSE(pickle.ReadString(&iter, &outstr));
+}
+
+TEST(PickleTest, BadLenWStr) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteInt(-1));
+
+  PickleIterator iter(pickle);
+  std::wstring woutstr;
+  EXPECT_FALSE(pickle.ReadWString(&iter, &woutstr));
+}
+
+TEST(PickleTest, FindNext) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteInt(1));
+  EXPECT_TRUE(pickle.WriteString("Domo"));
+
+  const char* start = reinterpret_cast<const char*>(pickle.data());
+  const char* end = start + pickle.size();
+
+  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end));
+  EXPECT_TRUE(NULL == Pickle::FindNext(pickle.header_size_, start, end - 1));
+  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1));
+}
+
+TEST(PickleTest, FindNextWithIncompleteHeader) {
+  size_t header_size = sizeof(Pickle::Header);
+  scoped_array<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));
+}
+
+TEST(PickleTest, GetReadPointerAndAdvance) {
+  Pickle pickle;
+
+  PickleIterator iter(pickle);
+  EXPECT_FALSE(iter.GetReadPointerAndAdvance(1));
+
+  EXPECT_TRUE(pickle.WriteInt(1));
+  EXPECT_TRUE(pickle.WriteInt(2));
+  int bytes = sizeof(int) * 2;
+
+  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(0));
+  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(1));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(-1));
+  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes + 1));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MAX));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MIN));
+}
+
+TEST(PickleTest, Resize) {
+  size_t unit = Pickle::kPayloadUnit;
+  scoped_array<char> data(new char[unit]);
+  char* data_ptr = data.get();
+  for (size_t i = 0; i < unit; i++)
+    data_ptr[i] = 'G';
+
+  // construct a message that will be exactly the size of one payload unit,
+  // note that any data will have a 4-byte header indicating the size
+  const size_t payload_size_after_header = unit - sizeof(uint32);
+  Pickle pickle;
+  pickle.WriteData(data_ptr,
+      static_cast<int>(payload_size_after_header - sizeof(uint32)));
+  size_t cur_payload = payload_size_after_header;
+
+  // note: we assume 'unit' is a power of 2
+  EXPECT_EQ(unit, pickle.capacity());
+  EXPECT_EQ(pickle.payload_size(), payload_size_after_header);
+
+  // fill out a full page (noting data header)
+  pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32)));
+  cur_payload += unit;
+  EXPECT_EQ(unit * 2, pickle.capacity());
+  EXPECT_EQ(cur_payload, pickle.payload_size());
+
+  // one more byte should double the capacity
+  pickle.WriteData(data_ptr, 1);
+  cur_payload += 5;
+  EXPECT_EQ(unit * 4, pickle.capacity());
+  EXPECT_EQ(cur_payload, pickle.payload_size());
+}
+
+namespace {
+
+struct CustomHeader : Pickle::Header {
+  int blah;
+};
+
+}  // namespace
+
+TEST(PickleTest, HeaderPadding) {
+  const uint32 kMagic = 0x12345678;
+
+  Pickle pickle(sizeof(CustomHeader));
+  pickle.WriteInt(kMagic);
+
+  // this should not overwrite the 'int' payload
+  pickle.headerT<CustomHeader>()->blah = 10;
+
+  PickleIterator iter(pickle);
+  int result;
+  ASSERT_TRUE(pickle.ReadInt(&iter, &result));
+
+  EXPECT_EQ(static_cast<uint32>(result), kMagic);
+}
+
+TEST(PickleTest, EqualsOperator) {
+  Pickle source;
+  source.WriteInt(1);
+
+  Pickle copy_refs_source_buffer(static_cast<const char*>(source.data()),
+                                 source.size());
+  Pickle copy;
+  copy = copy_refs_source_buffer;
+  ASSERT_EQ(source.size(), copy.size());
+}
+
+TEST(PickleTest, EvilLengths) {
+  Pickle source;
+  std::string str(100000, 'A');
+  EXPECT_TRUE(source.WriteData(str.c_str(), 100000));
+  // ReadString16 used to have its read buffer length calculation wrong leading
+  // to out-of-bounds reading.
+  PickleIterator iter(source);
+  string16 str16;
+  EXPECT_FALSE(source.ReadString16(&iter, &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(str16_pickle.ReadString16(&iter, &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(bad_len.ReadString16(&iter, &str16));
+
+  // Check we don't fail in a length check with large WStrings.
+  Pickle big_len;
+  EXPECT_TRUE(big_len.WriteInt(1 << 30));
+  iter = PickleIterator(big_len);
+  std::wstring wstr;
+  EXPECT_FALSE(big_len.ReadWString(&iter, &wstr));
+}
+
+// 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(pickle.ReadData(&iter, &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(pickle.ReadBytes(&iter, &outdata_char, sizeof(data)));
+
+  int outdata;
+  memcpy(&outdata, outdata_char, sizeof(outdata));
+  EXPECT_EQ(data, outdata);
+}
diff --git a/base/platform_file.cc b/base/platform_file.cc
new file mode 100644
index 0000000..70700fc
--- /dev/null
+++ b/base/platform_file.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 "base/platform_file.h"
+
+namespace base {
+
+PlatformFileInfo::PlatformFileInfo()
+    : size(0),
+      is_directory(false),
+      is_symbolic_link(false) {
+}
+
+PlatformFileInfo::~PlatformFileInfo() {}
+
+}  // namespace base
diff --git a/base/platform_file.h b/base/platform_file.h
new file mode 100644
index 0000000..bcf1915
--- /dev/null
+++ b/base/platform_file.h
@@ -0,0 +1,230 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PLATFORM_FILE_H_
+#define BASE_PLATFORM_FILE_H_
+
+#include "build/build_config.h"
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/time.h"
+
+namespace base {
+
+#if defined(OS_WIN)
+typedef HANDLE PlatformFile;
+const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
+#elif defined(OS_POSIX)
+typedef int PlatformFile;
+const PlatformFile kInvalidPlatformFileValue = -1;
+#endif
+
+// PLATFORM_FILE_(OPEN|CREATE).* are mutually exclusive. You should specify
+// exactly one of the five (possibly combining with other flags) when opening
+// or creating a file.
+enum PlatformFileFlags {
+  PLATFORM_FILE_OPEN = 1 << 0,             // Opens a file, only if it exists.
+  PLATFORM_FILE_CREATE = 1 << 1,           // Creates a new file, only if it
+                                           // does not already exist.
+  PLATFORM_FILE_OPEN_ALWAYS = 1 << 2,      // May create a new file.
+  PLATFORM_FILE_CREATE_ALWAYS = 1 << 3,    // May overwrite an old file.
+  PLATFORM_FILE_OPEN_TRUNCATED = 1 << 4,   // Opens a file and truncates it,
+                                           // only if it exists.
+  PLATFORM_FILE_READ = 1 << 5,
+  PLATFORM_FILE_WRITE = 1 << 6,
+  PLATFORM_FILE_EXCLUSIVE_READ = 1 << 7,   // EXCLUSIVE is opposite of Windows
+                                           // SHARE
+  PLATFORM_FILE_EXCLUSIVE_WRITE = 1 << 8,
+  PLATFORM_FILE_ASYNC = 1 << 9,
+  PLATFORM_FILE_TEMPORARY = 1 << 10,       // Used on Windows only
+  PLATFORM_FILE_HIDDEN = 1 << 11,          // Used on Windows only
+  PLATFORM_FILE_DELETE_ON_CLOSE = 1 << 12,
+
+  PLATFORM_FILE_WRITE_ATTRIBUTES = 1 << 13,  // Used on Windows only
+  PLATFORM_FILE_ENUMERATE = 1 << 14,         // May enumerate directory
+
+  PLATFORM_FILE_SHARE_DELETE = 1 << 15,      // Used on Windows only
+
+  PLATFORM_FILE_TERMINAL_DEVICE = 1 << 16,   // Serial port flags
+  PLATFORM_FILE_BACKUP_SEMANTICS = 1 << 17,  // Used on Windows only
+};
+
+// PLATFORM_FILE_ERROR_ACCESS_DENIED is returned when a call fails because of
+// a filesystem restriction. PLATFORM_FILE_ERROR_SECURITY is returned when a
+// browser policy doesn't allow the operation to be executed.
+enum PlatformFileError {
+  PLATFORM_FILE_OK = 0,
+  PLATFORM_FILE_ERROR_FAILED = -1,
+  PLATFORM_FILE_ERROR_IN_USE = -2,
+  PLATFORM_FILE_ERROR_EXISTS = -3,
+  PLATFORM_FILE_ERROR_NOT_FOUND = -4,
+  PLATFORM_FILE_ERROR_ACCESS_DENIED = -5,
+  PLATFORM_FILE_ERROR_TOO_MANY_OPENED = -6,
+  PLATFORM_FILE_ERROR_NO_MEMORY = -7,
+  PLATFORM_FILE_ERROR_NO_SPACE = -8,
+  PLATFORM_FILE_ERROR_NOT_A_DIRECTORY = -9,
+  PLATFORM_FILE_ERROR_INVALID_OPERATION = -10,
+  PLATFORM_FILE_ERROR_SECURITY = -11,
+  PLATFORM_FILE_ERROR_ABORT = -12,
+  PLATFORM_FILE_ERROR_NOT_A_FILE = -13,
+  PLATFORM_FILE_ERROR_NOT_EMPTY = -14,
+  PLATFORM_FILE_ERROR_INVALID_URL = -15,
+};
+
+// This explicit mapping matches both FILE_ on Windows and SEEK_ on Linux.
+enum PlatformFileWhence {
+  PLATFORM_FILE_FROM_BEGIN   = 0,
+  PLATFORM_FILE_FROM_CURRENT = 1,
+  PLATFORM_FILE_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::PlatformFileInfo> implementation in
+// chrome/common/common_param_traits.cc.
+struct BASE_EXPORT PlatformFileInfo {
+  PlatformFileInfo();
+  ~PlatformFileInfo();
+
+  // The size of the file in bytes.  Undefined when is_directory is true.
+  int64 size;
+
+  // True if the file corresponds to a directory.
+  bool is_directory;
+
+  // True if the file corresponds to a symbolic link.
+  bool is_symbolic_link;
+
+  // The last modified time of a file.
+  base::Time last_modified;
+
+  // The last accessed time of a file.
+  base::Time last_accessed;
+
+  // The creation time of a file.
+  base::Time creation_time;
+};
+
+// Creates or opens the given file. If |created| is provided, it will be set to
+// true if a new file was created [or an old one truncated to zero length to
+// simulate a new file, which can happen with PLATFORM_FILE_CREATE_ALWAYS], and
+// false otherwise.  |error_code| can be NULL.
+BASE_EXPORT PlatformFile CreatePlatformFile(const FilePath& name,
+                                            int flags,
+                                            bool* created,
+                                            PlatformFileError* error_code);
+
+// Closes a file handle. Returns |true| on success and |false| otherwise.
+BASE_EXPORT bool ClosePlatformFile(PlatformFile file);
+
+// 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.
+BASE_EXPORT int64 SeekPlatformFile(PlatformFile file,
+                                   PlatformFileWhence whence,
+                                   int64 offset);
+
+// Reads the given number of bytes (or until EOF is reached) starting with the
+// given offset. Returns the number of bytes read, or -1 on error. Note that
+// this function makes a best effort to read all data on all platforms, so it is
+// not intended for stream oriented files but instead for cases when the normal
+// expectation is that actually |size| bytes are read unless there is an error.
+BASE_EXPORT int ReadPlatformFile(PlatformFile file, int64 offset,
+                                 char* data, int size);
+
+// Same as above but without seek.
+BASE_EXPORT int ReadPlatformFileAtCurrentPos(PlatformFile file,
+                                             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.
+BASE_EXPORT int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset,
+                                             char* data, int size);
+
+// Same as above but without seek.
+BASE_EXPORT int ReadPlatformFileCurPosNoBestEffort(PlatformFile file,
+                                                   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.
+BASE_EXPORT int WritePlatformFile(PlatformFile file, int64 offset,
+                                  const char* data, int size);
+
+// Save as above but without seek.
+BASE_EXPORT int WritePlatformFileAtCurrentPos(PlatformFile file,
+                                              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.
+BASE_EXPORT int WritePlatformFileCurPosNoBestEffort(PlatformFile file,
+                                                    const char* data, int size);
+
+// Truncates the given 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.
+BASE_EXPORT bool TruncatePlatformFile(PlatformFile file, int64 length);
+
+// Flushes the buffers of the given file.
+BASE_EXPORT bool FlushPlatformFile(PlatformFile file);
+
+// Touches the given file.
+BASE_EXPORT bool TouchPlatformFile(PlatformFile file,
+                                   const Time& last_access_time,
+                                   const Time& last_modified_time);
+
+// Returns some information for the given file.
+BASE_EXPORT bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info);
+
+// Use this class to pass ownership of a PlatformFile to a receiver that may or
+// may not want to accept it.  This class does not own the storage for the
+// PlatformFile.
+//
+// EXAMPLE:
+//
+//  void MaybeProcessFile(PassPlatformFile pass_file) {
+//    if (...) {
+//      PlatformFile file = pass_file.ReleaseValue();
+//      // Now, we are responsible for closing |file|.
+//    }
+//  }
+//
+//  void OpenAndMaybeProcessFile(const FilePath& path) {
+//    PlatformFile file = CreatePlatformFile(path, ...);
+//    MaybeProcessFile(PassPlatformFile(&file));
+//    if (file != kInvalidPlatformFileValue)
+//      ClosePlatformFile(file);
+//  }
+//
+class BASE_EXPORT PassPlatformFile {
+ public:
+  explicit PassPlatformFile(PlatformFile* value) : value_(value) {
+  }
+
+  // Called to retrieve the PlatformFile stored in this object.  The caller
+  // gains ownership of the PlatformFile and is now responsible for closing it.
+  // Any subsequent calls to this method will return an invalid PlatformFile.
+  PlatformFile ReleaseValue() {
+    PlatformFile temp = *value_;
+    *value_ = kInvalidPlatformFileValue;
+    return temp;
+  }
+
+ private:
+  PlatformFile* value_;
+};
+
+}  // namespace base
+
+#endif  // BASE_PLATFORM_FILE_H_
diff --git a/base/platform_file_posix.cc b/base/platform_file_posix.cc
new file mode 100644
index 0000000..83cf622
--- /dev/null
+++ b/base/platform_file_posix.cc
@@ -0,0 +1,318 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/platform_file.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/utf_string_conversions.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#endif
+
+namespace base {
+
+// Make sure our Whence mappings match the system headers.
+COMPILE_ASSERT(PLATFORM_FILE_FROM_BEGIN   == SEEK_SET &&
+               PLATFORM_FILE_FROM_CURRENT == SEEK_CUR &&
+               PLATFORM_FILE_FROM_END     == SEEK_END, whence_matches_system);
+
+#if defined(OS_BSD) || defined(OS_MACOSX)
+typedef struct stat stat_wrapper_t;
+static int CallFstat(int fd, stat_wrapper_t *sb) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return fstat(fd, sb);
+}
+#else
+typedef struct stat64 stat_wrapper_t;
+static int CallFstat(int fd, stat_wrapper_t *sb) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return fstat64(fd, sb);
+}
+#endif
+
+// TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
+PlatformFile CreatePlatformFile(const FilePath& name, int flags,
+                                bool* created, PlatformFileError* error_code) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  int open_flags = 0;
+  if (flags & PLATFORM_FILE_CREATE)
+    open_flags = O_CREAT | O_EXCL;
+
+  if (created)
+    *created = false;
+
+  if (flags & PLATFORM_FILE_CREATE_ALWAYS) {
+    DCHECK(!open_flags);
+    open_flags = O_CREAT | O_TRUNC;
+  }
+
+  if (flags & PLATFORM_FILE_OPEN_TRUNCATED) {
+    DCHECK(!open_flags);
+    DCHECK(flags & PLATFORM_FILE_WRITE);
+    open_flags = O_TRUNC;
+  }
+
+  if (!open_flags && !(flags & PLATFORM_FILE_OPEN) &&
+      !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
+    NOTREACHED();
+    errno = EOPNOTSUPP;
+    if (error_code)
+      *error_code = PLATFORM_FILE_ERROR_FAILED;
+    return kInvalidPlatformFileValue;
+  }
+
+  if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) {
+    open_flags |= O_RDWR;
+  } else if (flags & PLATFORM_FILE_WRITE) {
+    open_flags |= O_WRONLY;
+  } else if (!(flags & PLATFORM_FILE_READ) &&
+             !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) &&
+             !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
+    NOTREACHED();
+  }
+
+  if (flags & PLATFORM_FILE_TERMINAL_DEVICE)
+    open_flags |= O_NOCTTY | O_NDELAY;
+
+  COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
+
+  int mode = S_IRUSR | S_IWUSR;
+#if defined(OS_CHROMEOS)
+  mode |= S_IRGRP | S_IROTH;
+#endif
+
+  int descriptor =
+      HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
+
+  if (flags & PLATFORM_FILE_OPEN_ALWAYS) {
+    if (descriptor < 0) {
+      open_flags |= O_CREAT;
+      if (flags & PLATFORM_FILE_EXCLUSIVE_READ ||
+          flags & PLATFORM_FILE_EXCLUSIVE_WRITE) {
+        open_flags |= O_EXCL;   // together with O_CREAT implies O_NOFOLLOW
+      }
+      descriptor = HANDLE_EINTR(
+          open(name.value().c_str(), open_flags, mode));
+      if (created && descriptor >= 0)
+        *created = true;
+    }
+  }
+
+  if (created && (descriptor >= 0) &&
+      (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)))
+    *created = true;
+
+  if ((descriptor >= 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) {
+    unlink(name.value().c_str());
+  }
+
+  if (error_code) {
+    if (descriptor >= 0)
+      *error_code = PLATFORM_FILE_OK;
+    else {
+      switch (errno) {
+        case EACCES:
+        case EISDIR:
+        case EROFS:
+        case EPERM:
+          *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED;
+          break;
+        case ETXTBSY:
+          *error_code = PLATFORM_FILE_ERROR_IN_USE;
+          break;
+        case EEXIST:
+          *error_code = PLATFORM_FILE_ERROR_EXISTS;
+          break;
+        case ENOENT:
+          *error_code = PLATFORM_FILE_ERROR_NOT_FOUND;
+          break;
+        case EMFILE:
+          *error_code = PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
+          break;
+        case ENOMEM:
+          *error_code = PLATFORM_FILE_ERROR_NO_MEMORY;
+          break;
+        case ENOSPC:
+          *error_code = PLATFORM_FILE_ERROR_NO_SPACE;
+          break;
+        case ENOTDIR:
+          *error_code = PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
+          break;
+        default:
+          *error_code = PLATFORM_FILE_ERROR_FAILED;
+      }
+    }
+  }
+
+  return descriptor;
+}
+
+bool ClosePlatformFile(PlatformFile file) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return !HANDLE_EINTR(close(file));
+}
+
+int64 SeekPlatformFile(PlatformFile file,
+                       PlatformFileWhence whence,
+                       int64 offset) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file < 0 || offset < 0)
+    return -1;
+
+  return lseek(file, static_cast<off_t>(offset), static_cast<int>(whence));
+}
+
+int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file < 0 || size < 0)
+    return -1;
+
+  int bytes_read = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(pread(file, 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 ReadPlatformFileAtCurrentPos(PlatformFile file, char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file < 0 || size < 0)
+    return -1;
+
+  int bytes_read = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(read(file, data, size));
+    if (rv <= 0)
+      break;
+
+    bytes_read += rv;
+  } while (bytes_read < size);
+
+  return bytes_read ? bytes_read : rv;
+}
+
+int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset,
+                                 char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file < 0)
+    return -1;
+
+  return HANDLE_EINTR(pread(file, data, size, offset));
+}
+
+int ReadPlatformFileCurPosNoBestEffort(PlatformFile file,
+                                       char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file < 0 || size < 0)
+    return -1;
+
+  return HANDLE_EINTR(read(file, data, size));
+}
+
+int WritePlatformFile(PlatformFile file, int64 offset,
+                      const char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file < 0 || size < 0)
+    return -1;
+
+  int bytes_written = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(pwrite(file, 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 WritePlatformFileAtCurrentPos(PlatformFile file,
+                                  const char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file < 0 || size < 0)
+    return -1;
+
+  int bytes_written = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(write(file, data, size));
+    if (rv <= 0)
+      break;
+
+    bytes_written += rv;
+  } while (bytes_written < size);
+
+  return bytes_written ? bytes_written : rv;
+}
+
+int WritePlatformFileCurPosNoBestEffort(PlatformFile file,
+                                        const char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file < 0 || size < 0)
+    return -1;
+
+  return HANDLE_EINTR(write(file, data, size));
+}
+
+bool TruncatePlatformFile(PlatformFile file, int64 length) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length)));
+}
+
+bool FlushPlatformFile(PlatformFile file) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return !HANDLE_EINTR(fsync(file));
+}
+
+bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
+                       const base::Time& last_modified_time) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file < 0)
+    return false;
+
+  timeval times[2];
+  times[0] = last_access_time.ToTimeVal();
+  times[1] = last_modified_time.ToTimeVal();
+  return !futimes(file, times);
+}
+
+bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
+  if (!info)
+    return false;
+
+  stat_wrapper_t file_info;
+  if (CallFstat(file, &file_info))
+    return false;
+
+  info->is_directory = S_ISDIR(file_info.st_mode);
+  info->is_symbolic_link = S_ISLNK(file_info.st_mode);
+  info->size = file_info.st_size;
+  info->last_modified = base::Time::FromTimeT(file_info.st_mtime);
+  info->last_accessed = base::Time::FromTimeT(file_info.st_atime);
+  info->creation_time = base::Time::FromTimeT(file_info.st_ctime);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/platform_file_unittest.cc b/base/platform_file_unittest.cc
new file mode 100644
index 0000000..671deb0
--- /dev/null
+++ b/base/platform_file_unittest.cc
@@ -0,0 +1,331 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_util.h"
+#include "base/platform_file.h"
+#include "base/scoped_temp_dir.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Reads from a file the given number of bytes, or until EOF is reached.
+// Returns the number of bytes read.
+int ReadFully(base::PlatformFile file, int64 offset, char* data, int size) {
+  return base::ReadPlatformFile(file, offset, data, size);
+}
+
+// Writes the given number of bytes to a file.
+// Returns the number of bytes written.
+int WriteFully(base::PlatformFile file, int64 offset,
+               const char* data, int size) {
+  return base::WritePlatformFile(file, offset, data, size);
+}
+
+} // namespace
+
+TEST(PlatformFile, CreatePlatformFile) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("create_file_1");
+
+  // Open a file that doesn't exist.
+  base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
+  base::PlatformFile file = base::CreatePlatformFile(
+      file_path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+      NULL, &error_code);
+  EXPECT_EQ(base::kInvalidPlatformFileValue, file);
+  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, error_code);
+
+  // Open or create a file.
+  bool created = false;
+  error_code = base::PLATFORM_FILE_OK;
+  file = base::CreatePlatformFile(
+      file_path, base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_READ,
+      &created, &error_code);
+  EXPECT_NE(base::kInvalidPlatformFileValue, file);
+  EXPECT_TRUE(created);
+  EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+  base::ClosePlatformFile(file);
+
+  // Open an existing file.
+  created = false;
+  file = base::CreatePlatformFile(
+      file_path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+      &created, &error_code);
+  EXPECT_NE(base::kInvalidPlatformFileValue, file);
+  EXPECT_FALSE(created);
+  EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+  base::ClosePlatformFile(file);
+
+  // Create a file that exists.
+  file = base::CreatePlatformFile(
+      file_path, base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ,
+      &created, &error_code);
+  EXPECT_EQ(base::kInvalidPlatformFileValue, file);
+  EXPECT_FALSE(created);
+  EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, error_code);
+
+  // Create or overwrite a file.
+  error_code = base::PLATFORM_FILE_OK;
+  file = base::CreatePlatformFile(
+      file_path, base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ,
+      &created, &error_code);
+  EXPECT_NE(base::kInvalidPlatformFileValue, file);
+  EXPECT_TRUE(created);
+  EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+  base::ClosePlatformFile(file);
+
+  // Create a delete-on-close file.
+  created = false;
+  file_path = temp_dir.path().AppendASCII("create_file_2");
+  file = base::CreatePlatformFile(
+      file_path,
+      base::PLATFORM_FILE_OPEN_ALWAYS |
+      base::PLATFORM_FILE_DELETE_ON_CLOSE |
+      base::PLATFORM_FILE_READ,
+      &created, &error_code);
+  EXPECT_NE(base::kInvalidPlatformFileValue, file);
+  EXPECT_TRUE(created);
+  EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+
+  EXPECT_TRUE(base::ClosePlatformFile(file));
+  EXPECT_FALSE(file_util::PathExists(file_path));
+}
+
+TEST(PlatformFile, DeleteOpenFile) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("create_file_1");
+
+  // Create a file.
+  bool created = false;
+  base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
+  base::PlatformFile file = base::CreatePlatformFile(
+      file_path,
+      base::PLATFORM_FILE_OPEN_ALWAYS |
+      base::PLATFORM_FILE_READ |
+      base::PLATFORM_FILE_SHARE_DELETE,
+      &created, &error_code);
+  EXPECT_NE(base::kInvalidPlatformFileValue, file);
+  EXPECT_TRUE(created);
+  EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+
+  // Open an existing file and mark it as delete on close.
+  created = false;
+  base::PlatformFile same_file = base::CreatePlatformFile(
+      file_path,
+      base::PLATFORM_FILE_OPEN |
+      base::PLATFORM_FILE_DELETE_ON_CLOSE |
+      base::PLATFORM_FILE_READ,
+      &created, &error_code);
+  EXPECT_NE(base::kInvalidPlatformFileValue, file);
+  EXPECT_FALSE(created);
+  EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+
+  // Close both handles and check that the file is gone.
+  base::ClosePlatformFile(file);
+  base::ClosePlatformFile(same_file);
+  EXPECT_FALSE(file_util::PathExists(file_path));
+}
+
+TEST(PlatformFile, ReadWritePlatformFile) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("read_write_file");
+  base::PlatformFile file = base::CreatePlatformFile(
+      file_path,
+      base::PLATFORM_FILE_CREATE |
+      base::PLATFORM_FILE_READ |
+      base::PLATFORM_FILE_WRITE,
+      NULL, NULL);
+  EXPECT_NE(base::kInvalidPlatformFileValue, file);
+
+  char data_to_write[] = "test";
+  const int kTestDataSize = 4;
+
+  // Write 0 bytes to the file.
+  int bytes_written = WriteFully(file, 0, data_to_write, 0);
+  EXPECT_EQ(0, bytes_written);
+
+  // Write "test" to the file.
+  bytes_written = WriteFully(file, 0, data_to_write, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_written);
+
+  // Read from EOF.
+  char data_read_1[32];
+  int bytes_read = ReadFully(file, 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 = ReadFully(file, 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 = ReadFully(file, 0, data_read_1, 0);
+  EXPECT_EQ(0, bytes_read);
+
+  // Read the entire file.
+  bytes_read = ReadFully(file, 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 = base::ReadPlatformFileNoBestEffort(file, 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 = WriteFully(file, kOffsetBeyondEndOfFile,
+                             data_to_write, kPartialWriteLength);
+  EXPECT_EQ(kPartialWriteLength, bytes_written);
+
+  // Make sure the file was extended.
+  int64 file_size = 0;
+  EXPECT_TRUE(file_util::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 = ReadFully(file, 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]);
+
+  // Close the file handle to allow the temp directory to be deleted.
+  base::ClosePlatformFile(file);
+}
+
+TEST(PlatformFile, TruncatePlatformFile) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("truncate_file");
+  base::PlatformFile file = base::CreatePlatformFile(
+      file_path,
+      base::PLATFORM_FILE_CREATE |
+      base::PLATFORM_FILE_READ |
+      base::PLATFORM_FILE_WRITE,
+      NULL, NULL);
+  EXPECT_NE(base::kInvalidPlatformFileValue, file);
+
+  // Write "test" to the file.
+  char data_to_write[] = "test";
+  int kTestDataSize = 4;
+  int bytes_written = WriteFully(file, 0, data_to_write, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_written);
+
+  // Extend the file.
+  const int kExtendedFileLength = 10;
+  int64 file_size = 0;
+  EXPECT_TRUE(base::TruncatePlatformFile(file, kExtendedFileLength));
+  EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size));
+  EXPECT_EQ(kExtendedFileLength, file_size);
+
+  // Make sure the file was zero-padded.
+  char data_read[32];
+  int bytes_read = ReadFully(file, 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(base::TruncatePlatformFile(file, kTruncatedFileLength));
+  EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size));
+  EXPECT_EQ(kTruncatedFileLength, file_size);
+
+  // Make sure the file was truncated.
+  bytes_read = ReadFully(file, 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]);
+
+  // Close the file handle to allow the temp directory to be deleted.
+  base::ClosePlatformFile(file);
+}
+
+// Flakily fails: http://crbug.com/86494
+TEST(PlatformFile, DISABLED_TouchGetInfoPlatformFile) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::PlatformFile file = base::CreatePlatformFile(
+      temp_dir.path().AppendASCII("touch_get_info_file"),
+      base::PLATFORM_FILE_CREATE |
+      base::PLATFORM_FILE_WRITE |
+      base::PLATFORM_FILE_WRITE_ATTRIBUTES,
+      NULL, NULL);
+  EXPECT_NE(base::kInvalidPlatformFileValue, file);
+
+  // Get info for a newly created file.
+  base::PlatformFileInfo info;
+  EXPECT_TRUE(base::GetPlatformFileInfo(file, &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 = WriteFully(file, 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(base::TouchPlatformFile(file, new_last_accessed,
+                                      new_last_modified));
+
+  // Make sure the file info was updated accordingly.
+  EXPECT_TRUE(base::GetPlatformFileInfo(file, &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());
+
+  // Close the file handle to allow the temp directory to be deleted.
+  base::ClosePlatformFile(file);
+}
diff --git a/base/platform_file_win.cc b/base/platform_file_win.cc
new file mode 100644
index 0000000..92f1c1f
--- /dev/null
+++ b/base/platform_file_win.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/platform_file.h"
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+PlatformFile CreatePlatformFile(const FilePath& name,
+                                int flags,
+                                bool* created,
+                                PlatformFileError* error_code) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  DWORD disposition = 0;
+  if (created)
+    *created = false;
+
+  if (flags & PLATFORM_FILE_OPEN)
+    disposition = OPEN_EXISTING;
+
+  if (flags & PLATFORM_FILE_CREATE) {
+    DCHECK(!disposition);
+    disposition = CREATE_NEW;
+  }
+
+  if (flags & PLATFORM_FILE_OPEN_ALWAYS) {
+    DCHECK(!disposition);
+    disposition = OPEN_ALWAYS;
+  }
+
+  if (flags & PLATFORM_FILE_CREATE_ALWAYS) {
+    DCHECK(!disposition);
+    disposition = CREATE_ALWAYS;
+  }
+
+  if (flags & PLATFORM_FILE_OPEN_TRUNCATED) {
+    DCHECK(!disposition);
+    DCHECK(flags & PLATFORM_FILE_WRITE);
+    disposition = TRUNCATE_EXISTING;
+  }
+
+  if (!disposition) {
+    NOTREACHED();
+    return NULL;
+  }
+
+  DWORD access = (flags & PLATFORM_FILE_READ) ? GENERIC_READ : 0;
+  if (flags & PLATFORM_FILE_WRITE)
+    access |= GENERIC_WRITE;
+  if (flags & PLATFORM_FILE_WRITE_ATTRIBUTES)
+    access |= FILE_WRITE_ATTRIBUTES;
+
+  DWORD sharing = (flags & PLATFORM_FILE_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
+  if (!(flags & PLATFORM_FILE_EXCLUSIVE_WRITE))
+    sharing |= FILE_SHARE_WRITE;
+  if (flags & PLATFORM_FILE_SHARE_DELETE)
+    sharing |= FILE_SHARE_DELETE;
+
+  DWORD create_flags = 0;
+  if (flags & PLATFORM_FILE_ASYNC)
+    create_flags |= FILE_FLAG_OVERLAPPED;
+  if (flags & PLATFORM_FILE_TEMPORARY)
+    create_flags |= FILE_ATTRIBUTE_TEMPORARY;
+  if (flags & PLATFORM_FILE_HIDDEN)
+    create_flags |= FILE_ATTRIBUTE_HIDDEN;
+  if (flags & PLATFORM_FILE_DELETE_ON_CLOSE)
+    create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
+  if (flags & PLATFORM_FILE_BACKUP_SEMANTICS)
+    create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
+
+  HANDLE file = CreateFile(name.value().c_str(), access, sharing, NULL,
+                           disposition, create_flags, NULL);
+
+  if (created && (INVALID_HANDLE_VALUE != file)) {
+    if (flags & (PLATFORM_FILE_OPEN_ALWAYS))
+      *created = (ERROR_ALREADY_EXISTS != GetLastError());
+    else if (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE))
+      *created = true;
+  }
+
+  if (error_code) {
+    if (file != kInvalidPlatformFileValue)
+      *error_code = PLATFORM_FILE_OK;
+    else {
+      DWORD last_error = GetLastError();
+      switch (last_error) {
+        case ERROR_SHARING_VIOLATION:
+          *error_code = PLATFORM_FILE_ERROR_IN_USE;
+          break;
+        case ERROR_FILE_EXISTS:
+          *error_code = PLATFORM_FILE_ERROR_EXISTS;
+          break;
+        case ERROR_FILE_NOT_FOUND:
+          *error_code = PLATFORM_FILE_ERROR_NOT_FOUND;
+          break;
+        case ERROR_ACCESS_DENIED:
+          *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED;
+          break;
+        default:
+          *error_code = PLATFORM_FILE_ERROR_FAILED;
+      }
+    }
+  }
+
+  return file;
+}
+
+bool ClosePlatformFile(PlatformFile file) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return (CloseHandle(file) != 0);
+}
+
+int64 SeekPlatformFile(PlatformFile file,
+                       PlatformFileWhence whence,
+                       int64 offset) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file < 0 || offset < 0)
+    return -1;
+
+  LARGE_INTEGER distance, res;
+  distance.QuadPart = offset;
+  DWORD move_method = static_cast<DWORD>(whence);
+  if (!SetFilePointerEx(file, distance, &res, move_method))
+    return -1;
+  return res.QuadPart;
+}
+
+int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file == kInvalidPlatformFileValue)
+    return -1;
+
+  LARGE_INTEGER offset_li;
+  offset_li.QuadPart = offset;
+
+  OVERLAPPED overlapped = {0};
+  overlapped.Offset = offset_li.LowPart;
+  overlapped.OffsetHigh = offset_li.HighPart;
+
+  DWORD bytes_read;
+  if (::ReadFile(file, data, size, &bytes_read, &overlapped) != 0)
+    return bytes_read;
+  else if (ERROR_HANDLE_EOF == GetLastError())
+    return 0;
+
+  return -1;
+}
+
+int ReadPlatformFileAtCurrentPos(PlatformFile file, char* data, int size) {
+  return ReadPlatformFile(file, 0, data, size);
+}
+
+int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset, char* data,
+                                 int size) {
+  return ReadPlatformFile(file, offset, data, size);
+}
+
+int ReadPlatformFileCurPosNoBestEffort(PlatformFile file,
+                                       char* data, int size) {
+  return ReadPlatformFile(file, 0, data, size);
+}
+
+int WritePlatformFile(PlatformFile file, int64 offset,
+                      const char* data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file == kInvalidPlatformFileValue)
+    return -1;
+
+  LARGE_INTEGER offset_li;
+  offset_li.QuadPart = offset;
+
+  OVERLAPPED overlapped = {0};
+  overlapped.Offset = offset_li.LowPart;
+  overlapped.OffsetHigh = offset_li.HighPart;
+
+  DWORD bytes_written;
+  if (::WriteFile(file, data, size, &bytes_written, &overlapped) != 0)
+    return bytes_written;
+
+  return -1;
+}
+
+int WritePlatformFileAtCurrentPos(PlatformFile file, const char* data,
+                                  int size) {
+  return WritePlatformFile(file, 0, data, size);
+}
+
+int WritePlatformFileCurPosNoBestEffort(PlatformFile file,
+                                        const char* data, int size) {
+  return WritePlatformFile(file, 0, data, size);
+}
+
+bool TruncatePlatformFile(PlatformFile file, int64 length) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file == kInvalidPlatformFileValue)
+    return false;
+
+  // Get the current file pointer.
+  LARGE_INTEGER file_pointer;
+  LARGE_INTEGER zero;
+  zero.QuadPart = 0;
+  if (::SetFilePointerEx(file, zero, &file_pointer, FILE_CURRENT) == 0)
+    return false;
+
+  LARGE_INTEGER length_li;
+  length_li.QuadPart = length;
+  // If length > file size, SetFilePointerEx() should extend the file
+  // with zeroes on all Windows standard file systems (NTFS, FATxx).
+  if (!::SetFilePointerEx(file, length_li, NULL, FILE_BEGIN))
+    return false;
+
+  // Set the new file length and move the file pointer to its old position.
+  // This is consistent with ftruncate()'s behavior, even when the file
+  // pointer points to a location beyond the end of the file.
+  return ((::SetEndOfFile(file) != 0) &&
+          (::SetFilePointerEx(file, file_pointer, NULL, FILE_BEGIN) != 0));
+}
+
+bool FlushPlatformFile(PlatformFile file) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return ((file != kInvalidPlatformFileValue) && ::FlushFileBuffers(file));
+}
+
+bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
+                       const base::Time& last_modified_time) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (file == kInvalidPlatformFileValue)
+    return false;
+
+  FILETIME last_access_filetime = last_access_time.ToFileTime();
+  FILETIME last_modified_filetime = last_modified_time.ToFileTime();
+  return (::SetFileTime(file, NULL, &last_access_filetime,
+                        &last_modified_filetime) != 0);
+}
+
+bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  if (!info)
+    return false;
+
+  BY_HANDLE_FILE_INFORMATION file_info;
+  if (GetFileInformationByHandle(file, &file_info) == 0)
+    return false;
+
+  LARGE_INTEGER size;
+  size.HighPart = file_info.nFileSizeHigh;
+  size.LowPart = file_info.nFileSizeLow;
+  info->size = size.QuadPart;
+  info->is_directory =
+      (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+  info->is_symbolic_link = false; // Windows doesn't have symbolic links.
+  info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime);
+  info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime);
+  info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/port.h b/base/port.h
new file mode 100644
index 0000000..af4e450
--- /dev/null
+++ b/base/port.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PORT_H_
+#define BASE_PORT_H_
+
+#include <stdarg.h>
+#include "build/build_config.h"
+
+#ifdef COMPILER_MSVC
+#define GG_LONGLONG(x) x##I64
+#define GG_ULONGLONG(x) x##UI64
+#else
+#define GG_LONGLONG(x) x##LL
+#define GG_ULONGLONG(x) x##ULL
+#endif
+
+// Per C99 7.8.14, define __STDC_CONSTANT_MACROS before including <stdint.h>
+// to get the INTn_C and UINTn_C macros for integer constants.  It's difficult
+// to guarantee any specific ordering of header includes, so it's difficult to
+// guarantee that the INTn_C macros can be defined by including <stdint.h> at
+// any specific point.  Provide GG_INTn_C macros instead.
+
+#define GG_INT8_C(x)    (x)
+#define GG_INT16_C(x)   (x)
+#define GG_INT32_C(x)   (x)
+#define GG_INT64_C(x)   GG_LONGLONG(x)
+
+#define GG_UINT8_C(x)   (x ## U)
+#define GG_UINT16_C(x)  (x ## U)
+#define GG_UINT32_C(x)  (x ## U)
+#define GG_UINT64_C(x)  GG_ULONGLONG(x)
+
+// It's possible for functions that use a va_list, such as StringPrintf, to
+// invalidate the data in it upon use.  The fix is to make a copy of the
+// structure before using it and use that copy instead.  va_copy is provided
+// for this purpose.  MSVC does not provide va_copy, so define an
+// implementation here.  It is not guaranteed that assignment is a copy, so the
+// StringUtil.VariableArgsFunc unit test tests this capability.
+#if defined(COMPILER_GCC)
+#define GG_VA_COPY(a, b) (va_copy(a, b))
+#elif defined(COMPILER_MSVC)
+#define GG_VA_COPY(a, b) (a = b)
+#endif
+
+// Define an OS-neutral wrapper for shared library entry points
+#if defined(OS_WIN)
+#define API_CALL __stdcall
+#else
+#define API_CALL
+#endif
+
+#endif  // BASE_PORT_H_
diff --git a/base/posix/file_descriptor_shuffle.cc b/base/posix/file_descriptor_shuffle.cc
new file mode 100644
index 0000000..0dde958
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/posix/file_descriptor_shuffle.h"
+
+#include <unistd.h>
+#include <stddef.h>
+#include <ostream>
+
+#include "base/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 may not allocate.
+
+  for (InjectiveMultimap::iterator i = m->begin(); i != m->end(); ++i) {
+    int temp_fd = -1;
+
+    // We DCHECK the injectiveness of the mapping.
+    for (InjectiveMultimap::iterator j = i + 1; j != m->end(); ++j) {
+      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 (InjectiveMultimap::iterator j = i + 1; j != m->end(); ++j) {
+      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 = HANDLE_EINTR(close(fd));
+  DPCHECK(ret == 0);
+}
+
+}  // namespace base
diff --git a/base/posix/file_descriptor_shuffle.h b/base/posix/file_descriptor_shuffle.h
new file mode 100644
index 0000000..6888c3e
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
+#define BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
+
+// This code exists to perform the shuffling of file descriptors which is
+// commonly needed when forking subprocesses. The naive approve is very simple,
+// just call dup2 to setup the desired descriptors, but wrong. It's tough to
+// handle the 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 FileDescriptorTableInjection : public InjectionDelegate {
+  virtual bool Duplicate(int* result, int fd) OVERRIDE;
+  virtual bool Move(int src, int dest) OVERRIDE;
+  virtual void Close(int fd) OVERRIDE;
+};
+
+// A single arc of the directed graph which describes an injective multimapping.
+struct InjectionArc {
+  InjectionArc(int in_source, int in_dest, bool in_close)
+      : source(in_source),
+        dest(in_dest),
+        close(in_close) {
+  }
+
+  int source;
+  int dest;
+  bool close;  // if true, delete the source element after performing the
+               // mapping.
+};
+
+typedef std::vector<InjectionArc> InjectiveMultimap;
+
+BASE_EXPORT bool PerformInjectiveMultimap(const InjectiveMultimap& map,
+                                          InjectionDelegate* delegate);
+
+BASE_EXPORT bool PerformInjectiveMultimapDestructive(
+    InjectiveMultimap* map,
+    InjectionDelegate* delegate);
+
+// This function will not call malloc but will mutate |map|
+static inline bool ShuffleFileDescriptors(InjectiveMultimap* map) {
+  FileDescriptorTableInjection delegate;
+  return PerformInjectiveMultimapDestructive(map, &delegate);
+}
+
+}  // namespace base
+
+#endif  // BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
diff --git a/base/posix/file_descriptor_shuffle_unittest.cc b/base/posix/file_descriptor_shuffle_unittest.cc
new file mode 100644
index 0000000..9e1b2500
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle_unittest.cc
@@ -0,0 +1,287 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/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) {
+  }
+
+  virtual bool Duplicate(int* result, int fd) OVERRIDE {
+    *result = next_duplicate_++;
+    actions_.push_back(Action(Action::DUPLICATE, *result, fd));
+    return true;
+  }
+
+  virtual bool Move(int src, int dest) OVERRIDE {
+    actions_.push_back(Action(Action::MOVE, src, dest));
+    return true;
+  }
+
+  virtual 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:
+  virtual bool Duplicate(int* result, int fd) OVERRIDE {
+    return false;
+  }
+
+  virtual bool Move(int src, int dest) OVERRIDE {
+    return false;
+  }
+
+  virtual void Close(int fd) OVERRIDE {}
+};
+
+TEST(FileDescriptorShuffleTest, EmptyWithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
+}
+
+TEST(FileDescriptorShuffleTest, NoopWithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+  map.push_back(InjectionArc(0, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
+}
+
+TEST(FileDescriptorShuffleTest, Simple1WithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+  map.push_back(InjectionArc(0, 1, false));
+
+  EXPECT_FALSE(PerformInjectiveMultimap(map, &failing));
+}
+
+}  // namespace base
diff --git a/base/posix/global_descriptors.cc b/base/posix/global_descriptors.cc
new file mode 100644
index 0000000..bcca443
--- /dev/null
+++ b/base/posix/global_descriptors.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/posix/global_descriptors.h"
+
+#include <vector>
+#include <utility>
+
+#include "base/logging.h"
+
+namespace base {
+
+// 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->first == key)
+      return i->second;
+  }
+
+  return -1;
+}
+
+void GlobalDescriptors::Set(Key key, int fd) {
+  for (Mapping::iterator
+       i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+    if (i->first == key) {
+      i->second = fd;
+      return;
+    }
+  }
+
+  descriptors_.push_back(std::make_pair(key, fd));
+}
+
+void GlobalDescriptors::Reset(const Mapping& mapping) {
+  descriptors_ = mapping;
+}
+
+GlobalDescriptors::GlobalDescriptors() {}
+
+GlobalDescriptors::~GlobalDescriptors() {}
+
+}  // namespace base
diff --git a/base/posix/global_descriptors.h b/base/posix/global_descriptors.h
new file mode 100644
index 0000000..c7b9f87
--- /dev/null
+++ b/base/posix/global_descriptors.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_POSIX_GLOBAL_DESCRIPTORS_H_
+#define BASE_POSIX_GLOBAL_DESCRIPTORS_H_
+
+#include "build/build_config.h"
+
+#include <vector>
+#include <utility>
+
+#include <stdint.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;
+  typedef std::pair<Key, int> KeyFDPair;
+  typedef std::vector<KeyFDPair> Mapping;
+
+  // Often we want a canonical descriptor for a given Key. In this case, we add
+  // the following constant to the key value:
+  static const int kBaseDescriptor = 3;  // 0, 1, 2 are already taken.
+
+  // 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 give a key. Returns -1 on error.
+  int MaybeGet(Key key) const;
+
+  // Set the descriptor for the given key.
+  void Set(Key key, int fd);
+
+  void Reset(const Mapping& mapping);
+
+ private:
+  friend struct DefaultSingletonTraits<GlobalDescriptors>;
+  GlobalDescriptors();
+  ~GlobalDescriptors();
+
+  Mapping descriptors_;
+};
+
+}  // namespace base
+
+#endif  // BASE_POSIX_GLOBAL_DESCRIPTORS_H_
diff --git a/base/posix/unix_domain_socket.cc b/base/posix/unix_domain_socket.cc
new file mode 100644
index 0000000..bd11292
--- /dev/null
+++ b/base/posix/unix_domain_socket.cc
@@ -0,0 +1,146 @@
+// Copyright (c) 2011 The Chromium Authors. All 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.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/pickle.h"
+#include "base/stl_util.h"
+
+const size_t UnixDomainSocket::kMaxFileDescriptors = 16;
+
+// 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;
+  }
+
+  const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, 0));
+  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<int>* fds) {
+  fds->clear();
+
+  struct msghdr msg;
+  memset(&msg, 0, sizeof(msg));
+  struct iovec iov = {buf, length};
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+  char control_buffer[CMSG_SPACE(sizeof(int) * kMaxFileDescriptors)];
+  msg.msg_control = control_buffer;
+  msg.msg_controllen = sizeof(control_buffer);
+
+  const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, 0));
+  if (r == -1)
+    return -1;
+
+  int* wire_fds = NULL;
+  unsigned wire_fds_len = 0;
+
+  if (msg.msg_controllen > 0) {
+    struct cmsghdr* cmsg;
+    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+      if (cmsg->cmsg_level == SOL_SOCKET &&
+          cmsg->cmsg_type == SCM_RIGHTS) {
+        const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
+        DCHECK(payload_len % sizeof(int) == 0);
+        wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+        wire_fds_len = payload_len / sizeof(int);
+        break;
+      }
+    }
+  }
+
+  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;
+  }
+
+  fds->resize(wire_fds_len);
+  memcpy(vector_as_array(fds), wire_fds, sizeof(int) * wire_fds_len);
+
+  return r;
+}
+
+// static
+ssize_t UnixDomainSocket::SendRecvMsg(int fd,
+                                      uint8_t* reply,
+                                      unsigned max_reply_len,
+                                      int* result_fd,
+                                      const Pickle& request) {
+  int fds[2];
+
+  // This socketpair is only used for the IPC and is cleaned up before
+  // returning.
+  if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) == -1)
+    return -1;
+
+  std::vector<int> fd_vector;
+  fd_vector.push_back(fds[1]);
+  if (!SendMsg(fd, request.data(), request.size(), fd_vector)) {
+    close(fds[0]);
+    close(fds[1]);
+    return -1;
+  }
+  close(fds[1]);
+
+  fd_vector.clear();
+  const ssize_t reply_len = RecvMsg(fds[0], reply, max_reply_len, &fd_vector);
+  close(fds[0]);
+  if (reply_len == -1)
+    return -1;
+
+  if ((!fd_vector.empty() && result_fd == NULL) || fd_vector.size() > 1) {
+    for (std::vector<int>::const_iterator
+         i = fd_vector.begin(); i != fd_vector.end(); ++i) {
+      close(*i);
+    }
+
+    NOTREACHED();
+
+    return -1;
+  }
+
+  if (result_fd)
+    *result_fd = fd_vector.empty() ? -1 : fd_vector[0];
+
+  return reply_len;
+}
diff --git a/base/posix/unix_domain_socket.h b/base/posix/unix_domain_socket.h
new file mode 100644
index 0000000..cb2a0b8
--- /dev/null
+++ b/base/posix/unix_domain_socket.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_POSIX_UNIX_DOMAIN_SOCKET_H_
+#define BASE_POSIX_UNIX_DOMAIN_SOCKET_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <vector>
+
+#include "base/base_export.h"
+
+class Pickle;
+
+class BASE_EXPORT UnixDomainSocket {
+ public:
+  // Maximum number of file descriptors that can be read by RecvMsg().
+  static const size_t kMaxFileDescriptors;
+
+  // 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<int>* fds);
+
+  // Perform a sendmsg/recvmsg pair.
+  //   1. This process creates a UNIX DGRAM socketpair.
+  //   2. This proces 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);
+};
+
+#endif  // BASE_POSIX_UNIX_DOMAIN_SOCKET_POSIX_H_
diff --git a/base/pr_time_unittest.cc b/base/pr_time_unittest.cc
new file mode 100644
index 0000000..4000afd
--- /dev/null
+++ b/base/pr_time_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 <time.h>
+
+#include "base/compiler_specific.h"
+#include "base/third_party/nspr/prtime.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+
+namespace {
+
+// time_t representation of 15th Oct 2007 12:45:00 PDT
+PRTime comparison_time_pdt = 1192477500 * Time::kMicrosecondsPerSecond;
+
+// 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:
+  virtual 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);
+  }
+
+  PRTime comparison_time_local_;
+};
+
+// 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(parsed_time, comparison_time_pdt);
+}
+
+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(parsed_time, comparison_time_local_);
+}
+
+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(parsed_time, comparison_time_pdt);
+}
+
+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(parsed_time, comparison_time_pdt);
+}
+
+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(parsed_time, comparison_time_local_);
+}
+
+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(parsed_time, comparison_time_local_);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest8) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("15-OCT-2007 12:45pm", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(parsed_time, comparison_time_local_);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest9) {
+  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(parsed_time, comparison_time_pdt);
+}
+
+// This test should not crash when compiled with Visual C++ 2005 (see
+// http://crbug.com/4387).
+TEST_F(PRTimeTest, ParseTimeTestOutOfRange) {
+  PRTime parsed_time = 0;
+  // Note the lack of timezone in the time string.  The year has to be 3001.
+  // The date has to be after 23:59:59, December 31, 3000, US Pacific Time, so
+  // we use January 2, 3001 to make sure it's after the magic maximum in any
+  // timezone.
+  PRStatus result = PR_ParseTimeString("Sun Jan  2 00:00:00 3001",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestNotNormalized1) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Mon Oct 15 12:44:60 PDT 2007",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestNotNormalized2) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Sun Oct 14 36:45 PDT 2007",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+}  // namespace
diff --git a/base/prefs/DEPS b/base/prefs/DEPS
new file mode 100644
index 0000000..233fb42
--- /dev/null
+++ b/base/prefs/DEPS
@@ -0,0 +1,13 @@
+specific_include_rules = {
+  '.*_[a-z]+test\.cc': [
+    "!chrome/common/chrome_notification_types.h",
+    "!chrome/common/chrome_paths.h",
+    "!chrome/common/important_file_writer.h",
+    "!chrome/common/pref_names.h",
+    "!chrome/test/base/testing_pref_service.h",
+    "!content/public/browser/notification_details.h",
+    "!content/public/browser/notification_source.h",
+    "!content/public/browser/notification_types.h",
+    "!content/public/test/mock_notification_observer.h",
+  ],
+}
diff --git a/base/prefs/OWNERS b/base/prefs/OWNERS
new file mode 100644
index 0000000..f3708af
--- /dev/null
+++ b/base/prefs/OWNERS
@@ -0,0 +1,7 @@
+battre@chromium.org
+bauerb@chromium.org
+mnissler@chromium.org
+pam@chromium.org
+
+# For refactoring changes
+joi@chromium.org
diff --git a/base/prefs/README b/base/prefs/README
new file mode 100644
index 0000000..a49604e
--- /dev/null
+++ b/base/prefs/README
@@ -0,0 +1,10 @@
+Prefs is a general-purpose key-value store for application preferences.
+
+At the moment, src/base/prefs has a bunch of dependencies back to
+src/chrome, and thus should only be used by code under src/chrome.
+
+We are working to remove these dependencies; once we do so,
+src/base/prefs will be available as a separate module, 'base_prefs',
+from src/base/base.gyp.
+
+Until that happens, please do not try to reuse outside of chrome/.
diff --git a/base/prefs/base_prefs_export.h b/base/prefs/base_prefs_export.h
new file mode 100644
index 0000000..3d207db
--- /dev/null
+++ b/base/prefs/base_prefs_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_BASE_PREFS_EXPORT_H_
+#define BASE_PREFS_BASE_PREFS_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_PREFS_IMPLEMENTATION)
+#define BASE_PREFS_EXPORT __declspec(dllexport)
+#else
+#define BASE_PREFS_EXPORT __declspec(dllimport)
+#endif  // defined(BASE_PREFS_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(BASE_PREFS_IMPLEMENTATION)
+#define BASE_PREFS_EXPORT __attribute__((visibility("default")))
+#else
+#define BASE_PREFS_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define BASE_PREFS_EXPORT
+#endif
+
+#endif  // BASE_PREFS_BASE_PREFS_EXPORT_H_
diff --git a/base/prefs/default_pref_store.cc b/base/prefs/default_pref_store.cc
new file mode 100644
index 0000000..8e2644c
--- /dev/null
+++ b/base/prefs/default_pref_store.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/prefs/default_pref_store.h"
+#include "base/logging.h"
+
+using base::Value;
+
+DefaultPrefStore::DefaultPrefStore() {}
+
+bool DefaultPrefStore::GetValue(
+    const std::string& key,
+    const base::Value** result) const {
+  return prefs_.GetValue(key, result);
+}
+
+void DefaultPrefStore::SetDefaultValue(const std::string& key, Value* value) {
+  DCHECK(!GetValue(key, NULL));
+  prefs_.SetValue(key, value);
+}
+
+void DefaultPrefStore::RemoveDefaultValue(const std::string& key) {
+  DCHECK(GetValue(key, NULL));
+  prefs_.RemoveValue(key);
+}
+
+base::Value::Type DefaultPrefStore::GetType(const std::string& key) const {
+  const Value* value = NULL;
+  return GetValue(key, &value) ? value->GetType() : Value::TYPE_NULL;
+}
+
+DefaultPrefStore::const_iterator DefaultPrefStore::begin() const {
+  return prefs_.begin();
+}
+
+DefaultPrefStore::const_iterator DefaultPrefStore::end() const {
+  return prefs_.end();
+}
+
+DefaultPrefStore::~DefaultPrefStore() {}
diff --git a/base/prefs/default_pref_store.h b/base/prefs/default_pref_store.h
new file mode 100644
index 0000000..996bf8b
--- /dev/null
+++ b/base/prefs/default_pref_store.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_DEFAULT_PREF_STORE_H_
+#define BASE_PREFS_DEFAULT_PREF_STORE_H_
+
+#include <string>
+
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_store.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+
+// This PrefStore keeps track of default preference values set when a
+// preference is registered with the PrefService.
+class BASE_PREFS_EXPORT DefaultPrefStore : public PrefStore {
+ public:
+  typedef PrefValueMap::const_iterator const_iterator;
+
+  DefaultPrefStore();
+
+  virtual bool GetValue(const std::string& key,
+                        const base::Value** result) const OVERRIDE;
+
+  // Stores a new |value| for |key|. Assumes ownership of |value|.
+  void SetDefaultValue(const std::string& key, Value* value);
+
+  // Removes the value for |key|.
+  void RemoveDefaultValue(const std::string& key);
+
+  // Returns the registered type for |key| or Value::TYPE_NULL if the |key|
+  // has not been registered.
+  base::Value::Type GetType(const std::string& key) const;
+
+  const_iterator begin() const;
+  const_iterator end() const;
+
+ protected:
+  virtual ~DefaultPrefStore();
+
+ private:
+  PrefValueMap prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultPrefStore);
+};
+
+#endif  // BASE_PREFS_DEFAULT_PREF_STORE_H_
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc
new file mode 100644
index 0000000..0447975
--- /dev/null
+++ b/base/prefs/json_pref_store.cc
@@ -0,0 +1,357 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/json_pref_store.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop_proxy.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/values.h"
+
+namespace {
+
+// Some extensions we'll tack on to copies of the Preferences files.
+const FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad");
+
+// Differentiates file loading between origin thread and passed
+// (aka file) thread.
+class FileThreadDeserializer
+    : public base::RefCountedThreadSafe<FileThreadDeserializer> {
+ public:
+  FileThreadDeserializer(JsonPrefStore* delegate,
+                         base::SequencedTaskRunner* sequenced_task_runner)
+      : no_dir_(false),
+        error_(PersistentPrefStore::PREF_READ_ERROR_NONE),
+        delegate_(delegate),
+        sequenced_task_runner_(sequenced_task_runner),
+        origin_loop_proxy_(base::MessageLoopProxy::current()) {
+  }
+
+  void Start(const FilePath& path) {
+    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+    sequenced_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&FileThreadDeserializer::ReadFileAndReport,
+                   this, path));
+  }
+
+  // Deserializes JSON on the sequenced task runner.
+  void ReadFileAndReport(const FilePath& path) {
+    DCHECK(sequenced_task_runner_->RunsTasksOnCurrentThread());
+
+    value_.reset(DoReading(path, &error_, &no_dir_));
+
+    origin_loop_proxy_->PostTask(
+        FROM_HERE,
+        base::Bind(&FileThreadDeserializer::ReportOnOriginThread, this));
+  }
+
+  // Reports deserialization result on the origin thread.
+  void ReportOnOriginThread() {
+    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+    delegate_->OnFileRead(value_.release(), error_, no_dir_);
+  }
+
+  static Value* DoReading(const FilePath& path,
+                          PersistentPrefStore::PrefReadError* error,
+                          bool* no_dir) {
+    int error_code;
+    std::string error_msg;
+    JSONFileValueSerializer serializer(path);
+    Value* value = serializer.Deserialize(&error_code, &error_msg);
+    HandleErrors(value, path, error_code, error_msg, error);
+    *no_dir = !file_util::PathExists(path.DirName());
+    return value;
+  }
+
+  static void HandleErrors(const Value* value,
+                           const FilePath& path,
+                           int error_code,
+                           const std::string& error_msg,
+                           PersistentPrefStore::PrefReadError* error);
+
+ private:
+  friend class base::RefCountedThreadSafe<FileThreadDeserializer>;
+  ~FileThreadDeserializer() {}
+
+  bool no_dir_;
+  PersistentPrefStore::PrefReadError error_;
+  scoped_ptr<Value> value_;
+  const scoped_refptr<JsonPrefStore> delegate_;
+  const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
+  const scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;
+};
+
+// static
+void FileThreadDeserializer::HandleErrors(
+    const Value* value,
+    const FilePath& path,
+    int error_code,
+    const std::string& error_msg,
+    PersistentPrefStore::PrefReadError* error) {
+  *error = PersistentPrefStore::PREF_READ_ERROR_NONE;
+  if (!value) {
+    DVLOG(1) << "Error while loading JSON file: " << error_msg
+             << ", file: " << path.value();
+    switch (error_code) {
+      case JSONFileValueSerializer::JSON_ACCESS_DENIED:
+        *error = PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
+        break;
+      case JSONFileValueSerializer::JSON_CANNOT_READ_FILE:
+        *error = PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
+        break;
+      case JSONFileValueSerializer::JSON_FILE_LOCKED:
+        *error = PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
+        break;
+      case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
+        *error = PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
+        break;
+      default:
+        *error = PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
+        // JSON errors indicate file corruption of some sort.
+        // Since the file is corrupt, move it to the side and continue with
+        // empty preferences.  This will result in them losing their settings.
+        // We keep the old file for possible support and debugging assistance
+        // as well as to detect if they're seeing these errors repeatedly.
+        // TODO(erikkay) Instead, use the last known good file.
+        FilePath bad = path.ReplaceExtension(kBadExtension);
+
+        // If they've ever had a parse error before, put them in another bucket.
+        // TODO(erikkay) if we keep this error checking for very long, we may
+        // want to differentiate between recent and long ago errors.
+        if (file_util::PathExists(bad))
+          *error = PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT;
+        file_util::Move(path, bad);
+        break;
+    }
+  } else if (!value->IsType(Value::TYPE_DICTIONARY)) {
+    *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
+  }
+}
+
+}  // namespace
+
+scoped_refptr<base::SequencedTaskRunner> JsonPrefStore::GetTaskRunnerForFile(
+    const FilePath& filename,
+    base::SequencedWorkerPool* worker_pool) {
+  std::string token("json_pref_store-");
+  token.append(filename.AsUTF8Unsafe());
+  return worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+      worker_pool->GetNamedSequenceToken(token),
+      base::SequencedWorkerPool::BLOCK_SHUTDOWN);
+}
+
+JsonPrefStore::JsonPrefStore(const FilePath& filename,
+                             base::SequencedTaskRunner* sequenced_task_runner)
+    : path_(filename),
+      sequenced_task_runner_(sequenced_task_runner),
+      prefs_(new DictionaryValue()),
+      read_only_(false),
+      writer_(filename, sequenced_task_runner),
+      error_delegate_(NULL),
+      initialized_(false),
+      read_error_(PREF_READ_ERROR_OTHER) {
+}
+
+bool JsonPrefStore::GetValue(const std::string& key,
+                             const Value** result) const {
+  Value* tmp = NULL;
+  if (!prefs_->Get(key, &tmp))
+    return false;
+
+  if (result)
+    *result = tmp;
+  return true;
+}
+
+void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+size_t JsonPrefStore::NumberOfObservers() const {
+  return observers_.size();
+}
+
+bool JsonPrefStore::IsInitializationComplete() const {
+  return initialized_;
+}
+
+bool JsonPrefStore::GetMutableValue(const std::string& key,
+                                    Value** result) {
+  return prefs_->Get(key, result);
+}
+
+void JsonPrefStore::SetValue(const std::string& key, Value* value) {
+  DCHECK(value);
+  scoped_ptr<Value> new_value(value);
+  Value* old_value = NULL;
+  prefs_->Get(key, &old_value);
+  if (!old_value || !value->Equals(old_value)) {
+    prefs_->Set(key, new_value.release());
+    ReportValueChanged(key);
+  }
+}
+
+void JsonPrefStore::SetValueSilently(const std::string& key, Value* value) {
+  DCHECK(value);
+  scoped_ptr<Value> new_value(value);
+  Value* old_value = NULL;
+  prefs_->Get(key, &old_value);
+  if (!old_value || !value->Equals(old_value)) {
+    prefs_->Set(key, new_value.release());
+    if (!read_only_)
+      writer_.ScheduleWrite(this);
+  }
+}
+
+void JsonPrefStore::RemoveValue(const std::string& key) {
+  if (prefs_->Remove(key, NULL))
+    ReportValueChanged(key);
+}
+
+void JsonPrefStore::MarkNeedsEmptyValue(const std::string& key) {
+  keys_need_empty_value_.insert(key);
+}
+
+bool JsonPrefStore::ReadOnly() const {
+  return read_only_;
+}
+
+PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
+  return read_error_;
+}
+
+PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
+  if (path_.empty()) {
+    OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
+    return PREF_READ_ERROR_FILE_NOT_SPECIFIED;
+  }
+
+  PrefReadError error;
+  bool no_dir;
+  Value* value = FileThreadDeserializer::DoReading(path_, &error, &no_dir);
+  OnFileRead(value, error, no_dir);
+  return error;
+}
+
+void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) {
+  initialized_ = false;
+  error_delegate_.reset(error_delegate);
+  if (path_.empty()) {
+    OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
+    return;
+  }
+
+  // Start async reading of the preferences file. It will delete itself
+  // in the end.
+  scoped_refptr<FileThreadDeserializer> deserializer(
+      new FileThreadDeserializer(this, sequenced_task_runner_.get()));
+  deserializer->Start(path_);
+}
+
+void JsonPrefStore::CommitPendingWrite() {
+  if (writer_.HasPendingWrite() && !read_only_)
+    writer_.DoScheduledWrite();
+}
+
+void JsonPrefStore::ReportValueChanged(const std::string& key) {
+  FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
+  if (!read_only_)
+    writer_.ScheduleWrite(this);
+}
+
+void JsonPrefStore::OnFileRead(Value* value_owned,
+                               PersistentPrefStore::PrefReadError error,
+                               bool no_dir) {
+  scoped_ptr<Value> value(value_owned);
+  read_error_ = error;
+
+  if (no_dir) {
+    FOR_EACH_OBSERVER(PrefStore::Observer,
+                      observers_,
+                      OnInitializationCompleted(false));
+    return;
+  }
+
+  initialized_ = true;
+
+  switch (error) {
+    case PREF_READ_ERROR_ACCESS_DENIED:
+    case PREF_READ_ERROR_FILE_OTHER:
+    case PREF_READ_ERROR_FILE_LOCKED:
+    case PREF_READ_ERROR_JSON_TYPE:
+    case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
+      read_only_ = true;
+      break;
+    case PREF_READ_ERROR_NONE:
+      DCHECK(value.get());
+      prefs_.reset(static_cast<DictionaryValue*>(value.release()));
+      break;
+    case PREF_READ_ERROR_NO_FILE:
+      // If the file just doesn't exist, maybe this is first run.  In any case
+      // there's no harm in writing out default prefs in this case.
+      break;
+    case PREF_READ_ERROR_JSON_PARSE:
+    case PREF_READ_ERROR_JSON_REPEAT:
+      break;
+    default:
+      NOTREACHED() << "Unknown error: " << error;
+  }
+
+  if (error_delegate_.get() && error != PREF_READ_ERROR_NONE)
+    error_delegate_->OnError(error);
+
+  FOR_EACH_OBSERVER(PrefStore::Observer,
+                    observers_,
+                    OnInitializationCompleted(true));
+}
+
+JsonPrefStore::~JsonPrefStore() {
+  CommitPendingWrite();
+}
+
+bool JsonPrefStore::SerializeData(std::string* output) {
+  // TODO(tc): Do we want to prune webkit preferences that match the default
+  // value?
+  JSONStringValueSerializer serializer(output);
+  serializer.set_pretty_print(true);
+  scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren());
+
+  // Iterates |keys_need_empty_value_| and if the key exists in |prefs_|,
+  // ensure its empty ListValue or DictonaryValue is preserved.
+  for (std::set<std::string>::const_iterator
+       it = keys_need_empty_value_.begin();
+       it != keys_need_empty_value_.end();
+       ++it) {
+    const std::string& key = *it;
+
+    base::Value* value = NULL;
+    if (!prefs_->Get(key, &value))
+      continue;
+
+    if (value->IsType(base::Value::TYPE_LIST)) {
+      const base::ListValue* list = NULL;
+      if (value->GetAsList(&list) && list->empty())
+        copy->Set(key, new base::ListValue);
+    } else if (value->IsType(base::Value::TYPE_DICTIONARY)) {
+      const base::DictionaryValue* dict = NULL;
+      if (value->GetAsDictionary(&dict) && dict->empty())
+        copy->Set(key, new base::DictionaryValue);
+    }
+  }
+
+  return serializer.Serialize(*(copy.get()));
+}
diff --git a/base/prefs/json_pref_store.h b/base/prefs/json_pref_store.h
new file mode 100644
index 0000000..49dd71a
--- /dev/null
+++ b/base/prefs/json_pref_store.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 BASE_PREFS_JSON_PREF_STORE_H_
+#define BASE_PREFS_JSON_PREF_STORE_H_
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/file_path.h"
+#include "base/files/important_file_writer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop_proxy.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/persistent_pref_store.h"
+
+namespace base {
+class DictionaryValue;
+class SequencedWorkerPool;
+class SequencedTaskRunner;
+class Value;
+}
+
+class FilePath;
+
+// A writable PrefStore implementation that is used for user preferences.
+class BASE_PREFS_EXPORT JsonPrefStore
+    : public PersistentPrefStore,
+      public base::ImportantFileWriter::DataSerializer {
+ public:
+  // Returns instance of SequencedTaskRunner which guarantees that file
+  // operations on the same file will be executed in sequenced order.
+  static scoped_refptr<base::SequencedTaskRunner> GetTaskRunnerForFile(
+      const FilePath& pref_filename,
+      base::SequencedWorkerPool* worker_pool);
+
+  // |sequenced_task_runner| is must be a shutdown-blocking task runner, ideally
+  // created by GetTaskRunnerForFile() method above.
+  JsonPrefStore(const FilePath& pref_filename,
+                base::SequencedTaskRunner* sequenced_task_runner);
+
+  // PrefStore overrides:
+  virtual bool GetValue(const std::string& key,
+                        const base::Value** result) const OVERRIDE;
+  virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE;
+  virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE;
+  virtual size_t NumberOfObservers() const OVERRIDE;
+  virtual bool IsInitializationComplete() const OVERRIDE;
+
+  // PersistentPrefStore overrides:
+  virtual bool GetMutableValue(const std::string& key,
+                               base::Value** result) OVERRIDE;
+  virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE;
+  virtual void SetValueSilently(const std::string& key,
+                                base::Value* value) OVERRIDE;
+  virtual void RemoveValue(const std::string& key) OVERRIDE;
+  virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE;
+  virtual bool ReadOnly() const OVERRIDE;
+  virtual PrefReadError GetReadError() const OVERRIDE;
+  virtual PrefReadError ReadPrefs() OVERRIDE;
+  virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) OVERRIDE;
+  virtual void CommitPendingWrite() OVERRIDE;
+  virtual void ReportValueChanged(const std::string& key) OVERRIDE;
+
+  // This method is called after JSON file has been read. Method takes
+  // ownership of the |value| pointer. Note, this method is used with
+  // asynchronous file reading, so class exposes it only for the internal needs.
+  // (read: do not call it manually).
+  void OnFileRead(base::Value* value_owned, PrefReadError error, bool no_dir);
+
+ private:
+  virtual ~JsonPrefStore();
+
+  // ImportantFileWriter::DataSerializer overrides:
+  virtual bool SerializeData(std::string* output) OVERRIDE;
+
+  FilePath path_;
+  const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
+
+  scoped_ptr<base::DictionaryValue> prefs_;
+
+  bool read_only_;
+
+  // Helper for safely writing pref data.
+  base::ImportantFileWriter writer_;
+
+  ObserverList<PrefStore::Observer, true> observers_;
+
+  scoped_ptr<ReadErrorDelegate> error_delegate_;
+
+  bool initialized_;
+  PrefReadError read_error_;
+
+  std::set<std::string> keys_need_empty_value_;
+
+  DISALLOW_COPY_AND_ASSIGN(JsonPrefStore);
+};
+
+#endif  // BASE_PREFS_JSON_PREF_STORE_H_
diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc
new file mode 100644
index 0000000..5258660
--- /dev/null
+++ b/base/prefs/json_pref_store_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/file_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/prefs/json_pref_store.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/pref_names.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MockPrefStoreObserver : public PrefStore::Observer {
+ public:
+  MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
+  MOCK_METHOD1(OnInitializationCompleted, void (bool));
+};
+
+class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
+ public:
+  MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
+};
+
+}  // namespace
+
+class JsonPrefStoreTest : public testing::Test {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_dir_));
+    data_dir_ = data_dir_.AppendASCII("pref_service");
+    ASSERT_TRUE(file_util::PathExists(data_dir_));
+  }
+
+  // The path to temporary directory used to contain the test operations.
+  ScopedTempDir temp_dir_;
+  // The path to the directory where the test data is stored.
+  FilePath data_dir_;
+  // A message loop that we can use as the file thread message loop.
+  MessageLoop message_loop_;
+};
+
+// Test fallback behavior for a nonexistent file.
+TEST_F(JsonPrefStoreTest, NonExistentFile) {
+  FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
+  ASSERT_FALSE(file_util::PathExists(bogus_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(
+          bogus_input_file, message_loop_.message_loop_proxy());
+  EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+            pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+}
+
+// Test fallback behavior for an invalid file.
+TEST_F(JsonPrefStoreTest, InvalidFile) {
+  FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
+  FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
+  ASSERT_TRUE(file_util::CopyFile(invalid_file_original, invalid_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(
+          invalid_file, message_loop_.message_loop_proxy());
+  EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
+            pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+
+  // The file should have been moved aside.
+  EXPECT_FALSE(file_util::PathExists(invalid_file));
+  FilePath moved_aside = temp_dir_.path().AppendASCII("invalid.bad");
+  EXPECT_TRUE(file_util::PathExists(moved_aside));
+  EXPECT_TRUE(file_util::TextContentsEqual(invalid_file_original,
+                                           moved_aside));
+}
+
+// This function is used to avoid code duplication while testing synchronous and
+// asynchronous version of the JsonPrefStore loading.
+void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
+                               const FilePath& output_file,
+                               const FilePath& golden_output_file) {
+  const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
+  const char kMaxTabs[] = "tabs.max_tabs";
+  const char kLongIntPref[] = "long_int.pref";
+
+  std::string cnn("http://www.cnn.com");
+
+  const Value* actual;
+  EXPECT_TRUE(pref_store->GetValue(prefs::kHomePage, &actual));
+  std::string string_value;
+  EXPECT_TRUE(actual->GetAsString(&string_value));
+  EXPECT_EQ(cnn, string_value);
+
+  const char kSomeDirectory[] = "some_directory";
+
+  EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
+  FilePath::StringType path;
+  EXPECT_TRUE(actual->GetAsString(&path));
+  EXPECT_EQ(FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
+  FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
+
+  pref_store->SetValue(kSomeDirectory,
+                       Value::CreateStringValue(some_path.value()));
+  EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
+  EXPECT_TRUE(actual->GetAsString(&path));
+  EXPECT_EQ(some_path.value(), path);
+
+  // Test reading some other data types from sub-dictionaries.
+  EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
+  bool boolean = false;
+  EXPECT_TRUE(actual->GetAsBoolean(&boolean));
+  EXPECT_TRUE(boolean);
+
+  pref_store->SetValue(kNewWindowsInTabs,
+                      Value::CreateBooleanValue(false));
+  EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
+  EXPECT_TRUE(actual->GetAsBoolean(&boolean));
+  EXPECT_FALSE(boolean);
+
+  EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
+  int integer = 0;
+  EXPECT_TRUE(actual->GetAsInteger(&integer));
+  EXPECT_EQ(20, integer);
+  pref_store->SetValue(kMaxTabs, Value::CreateIntegerValue(10));
+  EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
+  EXPECT_TRUE(actual->GetAsInteger(&integer));
+  EXPECT_EQ(10, integer);
+
+  pref_store->SetValue(kLongIntPref,
+                      Value::CreateStringValue(
+                          base::Int64ToString(214748364842LL)));
+  EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
+  EXPECT_TRUE(actual->GetAsString(&string_value));
+  int64 value;
+  base::StringToInt64(string_value, &value);
+  EXPECT_EQ(214748364842LL, value);
+
+  // Serialize and compare to expected output.
+  ASSERT_TRUE(file_util::PathExists(golden_output_file));
+  pref_store->CommitPendingWrite();
+  MessageLoop::current()->RunUntilIdle();
+  EXPECT_TRUE(file_util::TextContentsEqual(golden_output_file, output_file));
+  ASSERT_TRUE(file_util::Delete(output_file, false));
+}
+
+TEST_F(JsonPrefStoreTest, Basic) {
+  ASSERT_TRUE(file_util::CopyFile(data_dir_.AppendASCII("read.json"),
+                                  temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the persistent value can be loaded.
+  FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  ASSERT_TRUE(file_util::PathExists(input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(
+          input_file, message_loop_.message_loop_proxy());
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+  ASSERT_FALSE(pref_store->ReadOnly());
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(pref_store,
+                            input_file,
+                            data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, BasicAsync) {
+  ASSERT_TRUE(file_util::CopyFile(data_dir_.AppendASCII("read.json"),
+                                  temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the persistent value can be loaded.
+  FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  ASSERT_TRUE(file_util::PathExists(input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(
+          input_file, message_loop_.message_loop_proxy());
+
+  {
+    MockPrefStoreObserver mock_observer;
+    pref_store->AddObserver(&mock_observer);
+
+    MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
+    pref_store->ReadPrefsAsync(mock_error_delegate);
+
+    EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+    EXPECT_CALL(*mock_error_delegate,
+                OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
+    message_loop_.RunUntilIdle();
+    pref_store->RemoveObserver(&mock_observer);
+
+    ASSERT_FALSE(pref_store->ReadOnly());
+  }
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(pref_store,
+                            input_file,
+                            data_dir_.AppendASCII("write.golden.json"));
+}
+
+// Tests asynchronous reading of the file when there is no file.
+TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
+  FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
+  ASSERT_FALSE(file_util::PathExists(bogus_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(
+          bogus_input_file, message_loop_.message_loop_proxy());
+  MockPrefStoreObserver mock_observer;
+  pref_store->AddObserver(&mock_observer);
+
+  MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
+  pref_store->ReadPrefsAsync(mock_error_delegate);
+
+  EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+  EXPECT_CALL(*mock_error_delegate,
+              OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
+  message_loop_.RunUntilIdle();
+  pref_store->RemoveObserver(&mock_observer);
+
+  EXPECT_FALSE(pref_store->ReadOnly());
+}
+
+TEST_F(JsonPrefStoreTest, NeedsEmptyValue) {
+  FilePath pref_file = temp_dir_.path().AppendASCII("write.json");
+
+  ASSERT_TRUE(file_util::CopyFile(
+      data_dir_.AppendASCII("read.need_empty_value.json"),
+      pref_file));
+
+  // Test that the persistent value can be loaded.
+  ASSERT_TRUE(file_util::PathExists(pref_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(
+          pref_file, message_loop_.message_loop_proxy());
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+  ASSERT_FALSE(pref_store->ReadOnly());
+
+  // The JSON file looks like this:
+  // {
+  //   "list": [ 1 ],
+  //   "list_needs_empty_value": [ 2 ],
+  //   "dict": {
+  //     "dummy": true,
+  //   },
+  //   "dict_needs_empty_value": {
+  //     "dummy": true,
+  //   },
+  // }
+
+  // Set flag to preserve empty values for the following keys.
+  pref_store->MarkNeedsEmptyValue("list_needs_empty_value");
+  pref_store->MarkNeedsEmptyValue("dict_needs_empty_value");
+
+  // Set all keys to empty values.
+  pref_store->SetValue("list", new base::ListValue);
+  pref_store->SetValue("list_needs_empty_value", new base::ListValue);
+  pref_store->SetValue("dict", new base::DictionaryValue);
+  pref_store->SetValue("dict_needs_empty_value", new base::DictionaryValue);
+
+  // Write to file.
+  pref_store->CommitPendingWrite();
+  MessageLoop::current()->RunUntilIdle();
+
+  // Compare to expected output.
+  FilePath golden_output_file =
+      data_dir_.AppendASCII("write.golden.need_empty_value.json");
+  ASSERT_TRUE(file_util::PathExists(golden_output_file));
+  EXPECT_TRUE(file_util::TextContentsEqual(golden_output_file, pref_file));
+}
diff --git a/base/prefs/overlay_user_pref_store.cc b/base/prefs/overlay_user_pref_store.cc
new file mode 100644
index 0000000..3a74a5c
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/overlay_user_pref_store.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+OverlayUserPrefStore::OverlayUserPrefStore(
+    PersistentPrefStore* underlay)
+    : underlay_(underlay) {
+  underlay_->AddObserver(this);
+}
+
+bool OverlayUserPrefStore::IsSetInOverlay(const std::string& key) const {
+  return overlay_.GetValue(key, NULL);
+}
+
+void OverlayUserPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void OverlayUserPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+size_t OverlayUserPrefStore::NumberOfObservers() const {
+  return observers_.size();
+}
+
+bool OverlayUserPrefStore::IsInitializationComplete() const {
+  return underlay_->IsInitializationComplete();
+}
+
+bool OverlayUserPrefStore::GetValue(const std::string& key,
+                                    const Value** result) const {
+  // If the |key| shall NOT be stored in the overlay store, there must not
+  // be an entry.
+  DCHECK(ShallBeStoredInOverlay(key) || !overlay_.GetValue(key, NULL));
+
+  if (overlay_.GetValue(key, result))
+    return true;
+  return underlay_->GetValue(GetUnderlayKey(key), result);
+}
+
+bool OverlayUserPrefStore::GetMutableValue(const std::string& key,
+                                           Value** result) {
+  if (!ShallBeStoredInOverlay(key))
+    return underlay_->GetMutableValue(GetUnderlayKey(key), result);
+
+  if (overlay_.GetValue(key, result))
+    return true;
+
+  // Try to create copy of underlay if the overlay does not contain a value.
+  Value* underlay_value = NULL;
+  if (!underlay_->GetMutableValue(GetUnderlayKey(key), &underlay_value))
+    return false;
+
+  *result = underlay_value->DeepCopy();
+  overlay_.SetValue(key, *result);
+  return true;
+}
+
+void OverlayUserPrefStore::SetValue(const std::string& key,
+                                    Value* value) {
+  if (!ShallBeStoredInOverlay(key)) {
+    underlay_->SetValue(GetUnderlayKey(key), value);
+    return;
+  }
+
+  if (overlay_.SetValue(key, value))
+    ReportValueChanged(key);
+}
+
+void OverlayUserPrefStore::SetValueSilently(const std::string& key,
+                                            Value* value) {
+  if (!ShallBeStoredInOverlay(key)) {
+    underlay_->SetValueSilently(GetUnderlayKey(key), value);
+    return;
+  }
+
+  overlay_.SetValue(key, value);
+}
+
+void OverlayUserPrefStore::RemoveValue(const std::string& key) {
+  if (!ShallBeStoredInOverlay(key)) {
+    underlay_->RemoveValue(GetUnderlayKey(key));
+    return;
+  }
+
+  if (overlay_.RemoveValue(key))
+    ReportValueChanged(key);
+}
+
+void OverlayUserPrefStore::MarkNeedsEmptyValue(const std::string& key) {
+  if (!ShallBeStoredInOverlay(key))
+    underlay_->MarkNeedsEmptyValue(key);
+}
+
+bool OverlayUserPrefStore::ReadOnly() const {
+  return false;
+}
+
+PersistentPrefStore::PrefReadError OverlayUserPrefStore::GetReadError() const {
+  return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+PersistentPrefStore::PrefReadError OverlayUserPrefStore::ReadPrefs() {
+  // We do not read intentionally.
+  OnInitializationCompleted(true);
+  return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+void OverlayUserPrefStore::ReadPrefsAsync(
+    ReadErrorDelegate* error_delegate_raw) {
+  scoped_ptr<ReadErrorDelegate> error_delegate(error_delegate_raw);
+  // We do not read intentionally.
+  OnInitializationCompleted(true);
+}
+
+void OverlayUserPrefStore::CommitPendingWrite() {
+  underlay_->CommitPendingWrite();
+  // We do not write our content intentionally.
+}
+
+void OverlayUserPrefStore::ReportValueChanged(const std::string& key) {
+  FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
+}
+
+void OverlayUserPrefStore::OnPrefValueChanged(const std::string& key) {
+  if (!overlay_.GetValue(GetOverlayKey(key), NULL))
+    ReportValueChanged(GetOverlayKey(key));
+}
+
+void OverlayUserPrefStore::OnInitializationCompleted(bool succeeded) {
+  FOR_EACH_OBSERVER(PrefStore::Observer, observers_,
+                    OnInitializationCompleted(succeeded));
+}
+
+void OverlayUserPrefStore::RegisterOverlayPref(const std::string& key) {
+  RegisterOverlayPref(key, key);
+}
+
+void OverlayUserPrefStore::RegisterOverlayPref(
+    const std::string& overlay_key,
+    const std::string& underlay_key) {
+  DCHECK(!overlay_key.empty()) << "Overlay key is empty";
+  DCHECK(overlay_to_underlay_names_map_.find(overlay_key) ==
+         overlay_to_underlay_names_map_.end()) <<
+      "Overlay key already registered";
+  DCHECK(!underlay_key.empty()) << "Underlay key is empty";
+  DCHECK(underlay_to_overlay_names_map_.find(underlay_key) ==
+         underlay_to_overlay_names_map_.end()) <<
+      "Underlay key already registered";
+  overlay_to_underlay_names_map_[overlay_key] = underlay_key;
+  underlay_to_overlay_names_map_[underlay_key] = overlay_key;
+}
+
+OverlayUserPrefStore::~OverlayUserPrefStore() {
+  underlay_->RemoveObserver(this);
+}
+
+const std::string& OverlayUserPrefStore::GetOverlayKey(
+    const std::string& underlay_key) const {
+  NamesMap::const_iterator i =
+      underlay_to_overlay_names_map_.find(underlay_key);
+  return i != underlay_to_overlay_names_map_.end() ? i->second : underlay_key;
+}
+
+const std::string& OverlayUserPrefStore::GetUnderlayKey(
+    const std::string& overlay_key) const {
+  NamesMap::const_iterator i =
+      overlay_to_underlay_names_map_.find(overlay_key);
+  return i != overlay_to_underlay_names_map_.end() ? i->second : overlay_key;
+}
+
+bool OverlayUserPrefStore::ShallBeStoredInOverlay(
+    const std::string& key) const {
+  return overlay_to_underlay_names_map_.find(key) !=
+      overlay_to_underlay_names_map_.end();
+}
diff --git a/base/prefs/overlay_user_pref_store.h b/base/prefs/overlay_user_pref_store.h
new file mode 100644
index 0000000..120d405
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store.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_PREFS_OVERLAY_USER_PREF_STORE_H_
+#define BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/prefs/pref_value_map.h"
+
+// PersistentPrefStore that directs all write operations into an in-memory
+// PrefValueMap. Read operations are first answered by the PrefValueMap.
+// If the PrefValueMap does not contain a value for the requested key,
+// the look-up is passed on to an underlying PersistentPrefStore |underlay_|.
+class BASE_PREFS_EXPORT OverlayUserPrefStore : public PersistentPrefStore,
+                                               public PrefStore::Observer {
+ public:
+  explicit OverlayUserPrefStore(PersistentPrefStore* underlay);
+
+  // Returns true if a value has been set for the |key| in this
+  // OverlayUserPrefStore, i.e. if it potentially overrides a value
+  // from the |underlay_|.
+  virtual bool IsSetInOverlay(const std::string& key) const;
+
+  // Methods of PrefStore.
+  virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE;
+  virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE;
+  virtual size_t NumberOfObservers() const OVERRIDE;
+  virtual bool IsInitializationComplete() const OVERRIDE;
+  virtual bool GetValue(const std::string& key,
+                        const base::Value** result) const OVERRIDE;
+
+  // Methods of PersistentPrefStore.
+  virtual bool GetMutableValue(const std::string& key,
+                               base::Value** result) OVERRIDE;
+  virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE;
+  virtual void SetValueSilently(const std::string& key,
+                                base::Value* value) OVERRIDE;
+  virtual void RemoveValue(const std::string& key) OVERRIDE;
+  virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE;
+  virtual bool ReadOnly() const OVERRIDE;
+  virtual PrefReadError GetReadError() const OVERRIDE;
+  virtual PrefReadError ReadPrefs() OVERRIDE;
+  virtual void ReadPrefsAsync(ReadErrorDelegate* delegate) OVERRIDE;
+  virtual void CommitPendingWrite() OVERRIDE;
+  virtual void ReportValueChanged(const std::string& key) OVERRIDE;
+
+  // Methods of PrefStore::Observer.
+  virtual void OnPrefValueChanged(const std::string& key) OVERRIDE;
+  virtual void OnInitializationCompleted(bool succeeded) OVERRIDE;
+
+  void RegisterOverlayPref(const std::string& key);
+  void RegisterOverlayPref(const std::string& overlay_key,
+                           const std::string& underlay_key);
+
+ protected:
+  virtual ~OverlayUserPrefStore();
+
+ private:
+  typedef std::map<std::string, std::string> NamesMap;
+
+  const std::string& GetOverlayKey(const std::string& underlay_key) const;
+  const std::string& GetUnderlayKey(const std::string& overlay_key) const;
+
+  // Returns true if |key| corresponds to a preference that shall be stored in
+  // an in-memory PrefStore that is not persisted to disk.
+  bool ShallBeStoredInOverlay(const std::string& key) const;
+
+  ObserverList<PrefStore::Observer, true> observers_;
+  PrefValueMap overlay_;
+  scoped_refptr<PersistentPrefStore> underlay_;
+  NamesMap overlay_to_underlay_names_map_;
+  NamesMap underlay_to_overlay_names_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(OverlayUserPrefStore);
+};
+
+#endif  // BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
diff --git a/base/prefs/overlay_user_pref_store_unittest.cc b/base/prefs/overlay_user_pref_store_unittest.cc
new file mode 100644
index 0000000..d6615af
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store_unittest.cc
@@ -0,0 +1,272 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/overlay_user_pref_store.h"
+#include "base/prefs/pref_store_observer_mock.h"
+#include "base/prefs/testing_pref_store.h"
+#include "base/values.h"
+#include "chrome/common/pref_names.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Mock;
+using ::testing::StrEq;
+
+namespace {
+
+const char* overlay_key = prefs::kBrowserWindowPlacement;
+const char* regular_key = prefs::kShowBookmarkBar;
+// With the removal of the kWebKitGlobalXXX prefs, we'll no longer have real
+// prefs using the overlay pref store, so make up keys here.
+const char* mapped_overlay_key = "test.per_tab.javascript_enabled";
+const char* mapped_underlay_key = "test.per_profile.javascript_enabled";
+
+}  // namespace
+
+class OverlayUserPrefStoreTest : public testing::Test {
+ protected:
+  OverlayUserPrefStoreTest()
+      : underlay_(new TestingPrefStore()),
+        overlay_(new OverlayUserPrefStore(underlay_.get())) {
+    overlay_->RegisterOverlayPref(overlay_key);
+    overlay_->RegisterOverlayPref(mapped_overlay_key, mapped_underlay_key);
+  }
+
+  virtual ~OverlayUserPrefStoreTest() {}
+
+  scoped_refptr<TestingPrefStore> underlay_;
+  scoped_refptr<OverlayUserPrefStore> overlay_;
+};
+
+TEST_F(OverlayUserPrefStoreTest, Observer) {
+  PrefStoreObserverMock obs;
+  overlay_->AddObserver(&obs);
+
+  // Check that underlay first value is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1);
+  underlay_->SetValue(overlay_key, Value::CreateIntegerValue(42));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that underlay overwriting is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1);
+  underlay_->SetValue(overlay_key, Value::CreateIntegerValue(43));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that overwriting change in overlay is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1);
+  overlay_->SetValue(overlay_key, Value::CreateIntegerValue(44));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that hidden underlay change is not reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(0);
+  underlay_->SetValue(overlay_key, Value::CreateIntegerValue(45));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that overlay remove is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1);
+  overlay_->RemoveValue(overlay_key);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that underlay remove is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1);
+  underlay_->RemoveValue(overlay_key);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check respecting of silence.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(0);
+  overlay_->SetValueSilently(overlay_key, Value::CreateIntegerValue(46));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  overlay_->RemoveObserver(&obs);
+
+  // Check successful unsubscription.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(0);
+  underlay_->SetValue(overlay_key, Value::CreateIntegerValue(47));
+  overlay_->SetValue(overlay_key, Value::CreateIntegerValue(48));
+  Mock::VerifyAndClearExpectations(&obs);
+}
+
+TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
+  const Value* value = NULL;
+  EXPECT_FALSE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_FALSE(underlay_->GetValue(overlay_key, &value));
+
+  underlay_->SetValue(overlay_key, Value::CreateIntegerValue(42));
+
+  // Value shines through:
+  EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  overlay_->SetValue(overlay_key, Value::CreateIntegerValue(43));
+
+  EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  overlay_->RemoveValue(overlay_key);
+
+  // Value shines through:
+  EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+}
+
+// Check that GetMutableValue does not return the dictionary of the underlay.
+TEST_F(OverlayUserPrefStoreTest, ModifyDictionaries) {
+  underlay_->SetValue(overlay_key, new DictionaryValue);
+
+  Value* modify = NULL;
+  EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modify));
+  ASSERT_TRUE(modify);
+  ASSERT_TRUE(modify->IsType(Value::TYPE_DICTIONARY));
+  static_cast<DictionaryValue*>(modify)->SetInteger(overlay_key, 42);
+
+  Value* original_in_underlay = NULL;
+  EXPECT_TRUE(underlay_->GetMutableValue(overlay_key, &original_in_underlay));
+  ASSERT_TRUE(original_in_underlay);
+  ASSERT_TRUE(original_in_underlay->IsType(Value::TYPE_DICTIONARY));
+  EXPECT_TRUE(static_cast<DictionaryValue*>(original_in_underlay)->empty());
+
+  Value* modified = NULL;
+  EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modified));
+  ASSERT_TRUE(modified);
+  ASSERT_TRUE(modified->IsType(Value::TYPE_DICTIONARY));
+  EXPECT_TRUE(Value::Equals(modify, static_cast<DictionaryValue*>(modified)));
+}
+
+// Here we consider a global preference that is not overlayed.
+TEST_F(OverlayUserPrefStoreTest, GlobalPref) {
+  PrefStoreObserverMock obs;
+  overlay_->AddObserver(&obs);
+
+  const Value* value = NULL;
+
+  // Check that underlay first value is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1);
+  underlay_->SetValue(regular_key, Value::CreateIntegerValue(42));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that underlay overwriting is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1);
+  underlay_->SetValue(regular_key, Value::CreateIntegerValue(43));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that we get this value from the overlay
+  EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  // Check that overwriting change in overlay is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1);
+  overlay_->SetValue(regular_key, Value::CreateIntegerValue(44));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that we get this value from the overlay and the underlay.
+  EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+  EXPECT_TRUE(underlay_->GetValue(regular_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+
+  // Check that overlay remove is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1);
+  overlay_->RemoveValue(regular_key);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that value was removed from overlay and underlay
+  EXPECT_FALSE(overlay_->GetValue(regular_key, &value));
+  EXPECT_FALSE(underlay_->GetValue(regular_key, &value));
+
+  // Check respecting of silence.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(0);
+  overlay_->SetValueSilently(regular_key, Value::CreateIntegerValue(46));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  overlay_->RemoveObserver(&obs);
+
+  // Check successful unsubscription.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(0);
+  underlay_->SetValue(regular_key, Value::CreateIntegerValue(47));
+  overlay_->SetValue(regular_key, Value::CreateIntegerValue(48));
+  Mock::VerifyAndClearExpectations(&obs);
+}
+
+// Check that names mapping works correctly.
+TEST_F(OverlayUserPrefStoreTest, NamesMapping) {
+  PrefStoreObserverMock obs;
+  overlay_->AddObserver(&obs);
+
+  const Value* value = NULL;
+
+  // Check that if there is no override in the overlay, changing underlay value
+  // is reported as changing an overlay value.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1);
+  underlay_->SetValue(mapped_underlay_key, Value::CreateIntegerValue(42));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that underlay overwriting is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1);
+  underlay_->SetValue(mapped_underlay_key, Value::CreateIntegerValue(43));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that we get this value from the overlay with both keys
+  EXPECT_TRUE(overlay_->GetValue(mapped_overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+  // In this case, overlay reads directly from the underlay.
+  EXPECT_TRUE(overlay_->GetValue(mapped_underlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  // Check that overwriting change in overlay is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1);
+  overlay_->SetValue(mapped_overlay_key, Value::CreateIntegerValue(44));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that we get an overriden value from overlay, while reading the
+  // value from underlay still holds an old value.
+  EXPECT_TRUE(overlay_->GetValue(mapped_overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+  EXPECT_TRUE(overlay_->GetValue(mapped_underlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+  EXPECT_TRUE(underlay_->GetValue(mapped_underlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  // Check that hidden underlay change is not reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(0);
+  underlay_->SetValue(mapped_underlay_key, Value::CreateIntegerValue(45));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that overlay remove is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1);
+  overlay_->RemoveValue(mapped_overlay_key);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that underlay remove is reported.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1);
+  underlay_->RemoveValue(mapped_underlay_key);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Check that value was removed.
+  EXPECT_FALSE(overlay_->GetValue(mapped_overlay_key, &value));
+  EXPECT_FALSE(overlay_->GetValue(mapped_underlay_key, &value));
+
+  // Check respecting of silence.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(0);
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_underlay_key))).Times(0);
+  overlay_->SetValueSilently(mapped_overlay_key, Value::CreateIntegerValue(46));
+  Mock::VerifyAndClearExpectations(&obs);
+
+  overlay_->RemoveObserver(&obs);
+
+  // Check successful unsubscription.
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(0);
+  EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_underlay_key))).Times(0);
+  underlay_->SetValue(mapped_underlay_key, Value::CreateIntegerValue(47));
+  overlay_->SetValue(mapped_overlay_key, Value::CreateIntegerValue(48));
+  Mock::VerifyAndClearExpectations(&obs);
+}
diff --git a/base/prefs/persistent_pref_store.h b/base/prefs/persistent_pref_store.h
new file mode 100644
index 0000000..0baf02a
--- /dev/null
+++ b/base/prefs/persistent_pref_store.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PERSISTENT_PREF_STORE_H_
+#define BASE_PREFS_PERSISTENT_PREF_STORE_H_
+
+#include <string>
+
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_store.h"
+
+// This interface is complementary to the PrefStore interface, declaring
+// additional functionality that adds support for setting values and persisting
+// the data to some backing store.
+class BASE_PREFS_EXPORT PersistentPrefStore : public PrefStore {
+ public:
+  // Unique integer code for each type of error so we can report them
+  // distinctly in a histogram.
+  // NOTE: Don't change the order here as it will change the server's meaning
+  // of the histogram.
+  enum PrefReadError {
+    PREF_READ_ERROR_NONE = 0,
+    PREF_READ_ERROR_JSON_PARSE,
+    PREF_READ_ERROR_JSON_TYPE,
+    PREF_READ_ERROR_ACCESS_DENIED,
+    PREF_READ_ERROR_FILE_OTHER,
+    PREF_READ_ERROR_FILE_LOCKED,
+    PREF_READ_ERROR_NO_FILE,
+    PREF_READ_ERROR_JSON_REPEAT,
+    PREF_READ_ERROR_OTHER,
+    PREF_READ_ERROR_FILE_NOT_SPECIFIED,
+    PREF_READ_ERROR_MAX_ENUM
+  };
+
+  class ReadErrorDelegate {
+   public:
+    virtual ~ReadErrorDelegate() {}
+
+    virtual void OnError(PrefReadError error) = 0;
+  };
+
+  // Equivalent to PrefStore::GetValue but returns a mutable value.
+  virtual bool GetMutableValue(const std::string& key,
+                               base::Value** result) = 0;
+
+  // Triggers a value changed notification. This function needs to be called
+  // if one retrieves a list or dictionary with GetMutableValue and change its
+  // value. SetValue takes care of notifications itself. Note that
+  // ReportValueChanged will trigger notifications even if nothing has changed.
+  virtual void ReportValueChanged(const std::string& key) = 0;
+
+  // Sets a |value| for |key| in the store. Assumes ownership of |value|, which
+  // must be non-NULL.
+  virtual void SetValue(const std::string& key, base::Value* value) = 0;
+
+  // Same as SetValue, but doesn't generate notifications. This is used by
+  // PrefService::GetMutableUserPref() in order to put empty entries
+  // into the user pref store. Using SetValue is not an option since existing
+  // tests rely on the number of notifications generated.
+  virtual void SetValueSilently(const std::string& key, base::Value* value) = 0;
+
+  // Removes the value for |key|.
+  virtual void RemoveValue(const std::string& key) = 0;
+
+  // Marks that the |key| with empty ListValue/DictionaryValue needs to be
+  // persisted.
+  virtual void MarkNeedsEmptyValue(const std::string& key) = 0;
+
+  // Whether the store is in a pseudo-read-only mode where changes are not
+  // actually persisted to disk.  This happens in some cases when there are
+  // read errors during startup.
+  virtual bool ReadOnly() const = 0;
+
+  // Gets the read error. Only valid if IsInitializationComplete() returns true.
+  virtual PrefReadError GetReadError() const = 0;
+
+  // Reads the preferences from disk. Notifies observers via
+  // "PrefStore::OnInitializationCompleted" when done.
+  virtual PrefReadError ReadPrefs() = 0;
+
+  // Reads the preferences from disk asynchronously. Notifies observers via
+  // "PrefStore::OnInitializationCompleted" when done. Also it fires
+  // |error_delegate| if it is not NULL and reading error has occurred.
+  // Owns |error_delegate|.
+  virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) = 0;
+
+  // Lands any pending writes to disk.
+  virtual void CommitPendingWrite() = 0;
+
+ protected:
+  virtual ~PersistentPrefStore() {}
+};
+
+#endif  // BASE_PREFS_PERSISTENT_PREF_STORE_H_
diff --git a/base/prefs/pref_notifier.h b/base/prefs/pref_notifier.h
new file mode 100644
index 0000000..e0df260
--- /dev/null
+++ b/base/prefs/pref_notifier.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_NOTIFIER_H_
+#define BASE_PREFS_PREF_NOTIFIER_H_
+
+#include <string>
+
+// Delegate interface used by PrefValueStore to notify its owner about changes
+// to the preference values.
+// TODO(mnissler, danno): Move this declaration to pref_value_store.h once we've
+// cleaned up all public uses of this interface.
+class PrefNotifier {
+ public:
+  virtual ~PrefNotifier() {}
+
+  // Sends out a change notification for the preference identified by
+  // |pref_name|.
+  virtual void OnPreferenceChanged(const std::string& pref_name) = 0;
+
+  // Broadcasts the intialization completed notification.
+  virtual void OnInitializationCompleted(bool succeeded) = 0;
+};
+
+#endif  // BASE_PREFS_PREF_NOTIFIER_H_
diff --git a/base/prefs/pref_store.cc b/base/prefs/pref_store.cc
new file mode 100644
index 0000000..0521654
--- /dev/null
+++ b/base/prefs/pref_store.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_store.h"
+
+size_t PrefStore::NumberOfObservers() const {
+  return 0;
+}
+
+bool PrefStore::IsInitializationComplete() const {
+  return true;
+}
diff --git a/base/prefs/pref_store.h b/base/prefs/pref_store.h
new file mode 100644
index 0000000..2239528
--- /dev/null
+++ b/base/prefs/pref_store.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_STORE_H_
+#define BASE_PREFS_PREF_STORE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+
+namespace base {
+class Value;
+}
+
+// This is an abstract interface for reading and writing from/to a persistent
+// preference store, used by PrefService. An implementation using a JSON file
+// can be found in JsonPrefStore, while an implementation without any backing
+// store for testing can be found in TestingPrefStore. Furthermore, there is
+// CommandLinePrefStore, which bridges command line options to preferences and
+// ConfigurationPolicyPrefStore, which is used for hooking up configuration
+// policy with the preference subsystem.
+class BASE_PREFS_EXPORT PrefStore : public base::RefCounted<PrefStore> {
+ public:
+  // Observer interface for monitoring PrefStore.
+  class BASE_PREFS_EXPORT Observer {
+   public:
+    // Called when the value for the given |key| in the store changes.
+    virtual void OnPrefValueChanged(const std::string& key) = 0;
+    // Notification about the PrefStore being fully initialized.
+    virtual void OnInitializationCompleted(bool succeeded) = 0;
+
+   protected:
+    virtual ~Observer() {}
+  };
+
+  PrefStore() {}
+
+  // Add and remove observers.
+  virtual void AddObserver(Observer* observer) {}
+  virtual void RemoveObserver(Observer* observer) {}
+  virtual size_t NumberOfObservers() const;
+
+  // Whether the store has completed all asynchronous initialization.
+  virtual bool IsInitializationComplete() const;
+
+  // Get the value for a given preference |key| and stores it in |*result|.
+  // |*result| is only modified if the return value is true and if |result|
+  // is not NULL. Ownership of the |*result| value remains with the PrefStore.
+  virtual bool GetValue(const std::string& key,
+                        const base::Value** result) const = 0;
+
+ protected:
+  friend class base::RefCounted<PrefStore>;
+  virtual ~PrefStore() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefStore);
+};
+
+#endif  // BASE_PREFS_PREF_STORE_H_
diff --git a/base/prefs/pref_store_observer_mock.cc b/base/prefs/pref_store_observer_mock.cc
new file mode 100644
index 0000000..0970e63
--- /dev/null
+++ b/base/prefs/pref_store_observer_mock.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_store_observer_mock.h"
+
+PrefStoreObserverMock::PrefStoreObserverMock() {}
+
+PrefStoreObserverMock::~PrefStoreObserverMock() {}
diff --git a/base/prefs/pref_store_observer_mock.h b/base/prefs/pref_store_observer_mock.h
new file mode 100644
index 0000000..8252c3b
--- /dev/null
+++ b/base/prefs/pref_store_observer_mock.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_PREFS_PREF_STORE_OBSERVER_MOCK_H_
+#define BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_
+
+#include "base/basictypes.h"
+#include "base/prefs/pref_store.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+// A gmock-ified implementation of PrefStore::Observer.
+class PrefStoreObserverMock : public PrefStore::Observer {
+ public:
+  PrefStoreObserverMock();
+  virtual ~PrefStoreObserverMock();
+
+  MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
+  MOCK_METHOD1(OnInitializationCompleted, void(bool));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefStoreObserverMock);
+};
+
+#endif  // BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_
diff --git a/base/prefs/pref_value_map.cc b/base/prefs/pref_value_map.cc
new file mode 100644
index 0000000..48e8fa3
--- /dev/null
+++ b/base/prefs/pref_value_map.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 "base/prefs/pref_value_map.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+
+PrefValueMap::PrefValueMap() {}
+
+PrefValueMap::~PrefValueMap() {
+  Clear();
+}
+
+bool PrefValueMap::GetValue(const std::string& key, const Value** value) const {
+  const Map::const_iterator entry = prefs_.find(key);
+  if (entry != prefs_.end()) {
+    if (value)
+      *value = entry->second;
+    return true;
+  }
+
+  return false;
+}
+
+bool PrefValueMap::GetValue(const std::string& key, Value** value) {
+  const Map::const_iterator entry = prefs_.find(key);
+  if (entry != prefs_.end()) {
+    if (value)
+      *value = entry->second;
+    return true;
+  }
+
+  return false;
+}
+
+bool PrefValueMap::SetValue(const std::string& key, Value* value) {
+  DCHECK(value);
+  scoped_ptr<Value> value_ptr(value);
+  const Map::iterator entry = prefs_.find(key);
+  if (entry != prefs_.end()) {
+    if (Value::Equals(entry->second, value))
+      return false;
+    delete entry->second;
+    entry->second = value_ptr.release();
+  } else {
+    prefs_[key] = value_ptr.release();
+  }
+
+  return true;
+}
+
+bool PrefValueMap::RemoveValue(const std::string& key) {
+  const Map::iterator entry = prefs_.find(key);
+  if (entry != prefs_.end()) {
+    delete entry->second;
+    prefs_.erase(entry);
+    return true;
+  }
+
+  return false;
+}
+
+void PrefValueMap::Clear() {
+  STLDeleteValues(&prefs_);
+  prefs_.clear();
+}
+
+void PrefValueMap::Swap(PrefValueMap* other) {
+  prefs_.swap(other->prefs_);
+}
+
+PrefValueMap::iterator PrefValueMap::begin() {
+  return prefs_.begin();
+}
+
+PrefValueMap::iterator PrefValueMap::end() {
+  return prefs_.end();
+}
+
+PrefValueMap::const_iterator PrefValueMap::begin() const {
+  return prefs_.begin();
+}
+
+PrefValueMap::const_iterator PrefValueMap::end() const {
+  return prefs_.end();
+}
+
+bool PrefValueMap::GetBoolean(const std::string& key,
+                              bool* value) const {
+  const Value* stored_value = NULL;
+  return GetValue(key, &stored_value) && stored_value->GetAsBoolean(value);
+}
+
+void PrefValueMap::SetBoolean(const std::string& key, bool value) {
+  SetValue(key, Value::CreateBooleanValue(value));
+}
+
+bool PrefValueMap::GetString(const std::string& key,
+                             std::string* value) const {
+  const Value* stored_value = NULL;
+  return GetValue(key, &stored_value) && stored_value->GetAsString(value);
+}
+
+void PrefValueMap::SetString(const std::string& key,
+                             const std::string& value) {
+  SetValue(key, Value::CreateStringValue(value));
+}
+
+bool PrefValueMap::GetInteger(const std::string& key, int* value) const {
+  const Value* stored_value = NULL;
+  return GetValue(key, &stored_value) && stored_value->GetAsInteger(value);
+}
+
+void PrefValueMap::SetInteger(const std::string& key, const int value) {
+  SetValue(key, Value::CreateIntegerValue(value));
+}
+
+void PrefValueMap::GetDifferingKeys(
+    const PrefValueMap* other,
+    std::vector<std::string>* differing_keys) const {
+  differing_keys->clear();
+
+  // Walk over the maps in lockstep, adding everything that is different.
+  Map::const_iterator this_pref(prefs_.begin());
+  Map::const_iterator other_pref(other->prefs_.begin());
+  while (this_pref != prefs_.end() && other_pref != other->prefs_.end()) {
+    const int diff = this_pref->first.compare(other_pref->first);
+    if (diff == 0) {
+      if (!this_pref->second->Equals(other_pref->second))
+        differing_keys->push_back(this_pref->first);
+      ++this_pref;
+      ++other_pref;
+    } else if (diff < 0) {
+      differing_keys->push_back(this_pref->first);
+      ++this_pref;
+    } else if (diff > 0) {
+      differing_keys->push_back(other_pref->first);
+      ++other_pref;
+    }
+  }
+
+  // Add the remaining entries.
+  for ( ; this_pref != prefs_.end(); ++this_pref)
+      differing_keys->push_back(this_pref->first);
+  for ( ; other_pref != other->prefs_.end(); ++other_pref)
+      differing_keys->push_back(other_pref->first);
+}
diff --git a/base/prefs/pref_value_map.h b/base/prefs/pref_value_map.h
new file mode 100644
index 0000000..1d79127
--- /dev/null
+++ b/base/prefs/pref_value_map.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_VALUE_MAP_H_
+#define BASE_PREFS_PREF_VALUE_MAP_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/prefs/base_prefs_export.h"
+
+namespace base {
+class Value;
+}
+
+// A generic string to value map used by the PrefStore implementations.
+class BASE_PREFS_EXPORT PrefValueMap {
+ public:
+  typedef std::map<std::string, base::Value*>::iterator iterator;
+  typedef std::map<std::string, base::Value*>::const_iterator const_iterator;
+
+  PrefValueMap();
+  virtual ~PrefValueMap();
+
+  // Gets the value for |key| and stores it in |value|. Ownership remains with
+  // the map. Returns true if a value is present. If not, |value| is not
+  // touched.
+  bool GetValue(const std::string& key, const base::Value** value) const;
+  bool GetValue(const std::string& key, base::Value** value);
+
+  // Sets a new |value| for |key|. Takes ownership of |value|, which must be
+  // non-NULL. Returns true if the value changed.
+  bool SetValue(const std::string& key, base::Value* value);
+
+  // Removes the value for |key| from the map. Returns true if a value was
+  // removed.
+  bool RemoveValue(const std::string& key);
+
+  // Clears the map.
+  void Clear();
+
+  // Swaps the contents of two maps.
+  void Swap(PrefValueMap* other);
+
+  iterator begin();
+  iterator end();
+  const_iterator begin() const;
+  const_iterator end() const;
+
+  // Gets a boolean value for |key| and stores it in |value|. Returns true if
+  // the value was found and of the proper type.
+  bool GetBoolean(const std::string& key, bool* value) const;
+
+  // Sets the value for |key| to the boolean |value|.
+  void SetBoolean(const std::string& key, bool value);
+
+  // Gets a string value for |key| and stores it in |value|. Returns true if
+  // the value was found and of the proper type.
+  bool GetString(const std::string& key, std::string* value) const;
+
+  // Sets the value for |key| to the string |value|.
+  void SetString(const std::string& key, const std::string& value);
+
+  // Gets an int value for |key| and stores it in |value|. Returns true if
+  // the value was found and of the proper type.
+  bool GetInteger(const std::string& key, int* value) const;
+
+  // Sets the value for |key| to the int |value|.
+  void SetInteger(const std::string& key, const int value);
+
+  // Compares this value map against |other| and stores all key names that have
+  // different values in |differing_keys|. This includes keys that are present
+  // only in one of the maps.
+  void GetDifferingKeys(const PrefValueMap* other,
+                        std::vector<std::string>* differing_keys) const;
+
+ private:
+  typedef std::map<std::string, base::Value*> Map;
+
+  Map prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefValueMap);
+};
+
+#endif  // BASE_PREFS_PREF_VALUE_MAP_H_
diff --git a/base/prefs/pref_value_map_unittest.cc b/base/prefs/pref_value_map_unittest.cc
new file mode 100644
index 0000000..b406db8
--- /dev/null
+++ b/base/prefs/pref_value_map_unittest.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class PrefValueMapTest : public testing::Test {
+};
+
+TEST_F(PrefValueMapTest, SetValue) {
+  PrefValueMap map;
+  const Value* result = NULL;
+  EXPECT_FALSE(map.GetValue("key", &result));
+  EXPECT_FALSE(result);
+
+  EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("test")));
+  EXPECT_FALSE(map.SetValue("key", Value::CreateStringValue("test")));
+  EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("hi mom!")));
+
+  EXPECT_TRUE(map.GetValue("key", &result));
+  EXPECT_TRUE(StringValue("hi mom!").Equals(result));
+}
+
+TEST_F(PrefValueMapTest, GetAndSetIntegerValue) {
+  PrefValueMap map;
+  ASSERT_TRUE(map.SetValue("key", Value::CreateIntegerValue(5)));
+
+  int int_value = 0;
+  EXPECT_TRUE(map.GetInteger("key", &int_value));
+  EXPECT_EQ(5, int_value);
+
+  map.SetInteger("key", -14);
+  EXPECT_TRUE(map.GetInteger("key", &int_value));
+  EXPECT_EQ(-14, int_value);
+}
+
+TEST_F(PrefValueMapTest, RemoveValue) {
+  PrefValueMap map;
+  EXPECT_FALSE(map.RemoveValue("key"));
+
+  EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("test")));
+  EXPECT_TRUE(map.GetValue("key", NULL));
+
+  EXPECT_TRUE(map.RemoveValue("key"));
+  EXPECT_FALSE(map.GetValue("key", NULL));
+
+  EXPECT_FALSE(map.RemoveValue("key"));
+}
+
+TEST_F(PrefValueMapTest, Clear) {
+  PrefValueMap map;
+  EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("test")));
+  EXPECT_TRUE(map.GetValue("key", NULL));
+
+  map.Clear();
+
+  EXPECT_FALSE(map.GetValue("key", NULL));
+}
+
+TEST_F(PrefValueMapTest, GetDifferingKeys) {
+  PrefValueMap reference;
+  EXPECT_TRUE(reference.SetValue("b", Value::CreateStringValue("test")));
+  EXPECT_TRUE(reference.SetValue("c", Value::CreateStringValue("test")));
+  EXPECT_TRUE(reference.SetValue("e", Value::CreateStringValue("test")));
+
+  PrefValueMap check;
+  std::vector<std::string> differing_paths;
+  std::vector<std::string> expected_differing_paths;
+
+  reference.GetDifferingKeys(&check, &differing_paths);
+  expected_differing_paths.push_back("b");
+  expected_differing_paths.push_back("c");
+  expected_differing_paths.push_back("e");
+  EXPECT_EQ(expected_differing_paths, differing_paths);
+
+  EXPECT_TRUE(check.SetValue("a", Value::CreateStringValue("test")));
+  EXPECT_TRUE(check.SetValue("c", Value::CreateStringValue("test")));
+  EXPECT_TRUE(check.SetValue("d", Value::CreateStringValue("test")));
+
+  reference.GetDifferingKeys(&check, &differing_paths);
+  expected_differing_paths.clear();
+  expected_differing_paths.push_back("a");
+  expected_differing_paths.push_back("b");
+  expected_differing_paths.push_back("d");
+  expected_differing_paths.push_back("e");
+  EXPECT_EQ(expected_differing_paths, differing_paths);
+}
+
+TEST_F(PrefValueMapTest, SwapTwoMaps) {
+  PrefValueMap first_map;
+  EXPECT_TRUE(first_map.SetValue("a", Value::CreateStringValue("test")));
+  EXPECT_TRUE(first_map.SetValue("b", Value::CreateStringValue("test")));
+  EXPECT_TRUE(first_map.SetValue("c", Value::CreateStringValue("test")));
+
+  PrefValueMap second_map;
+  EXPECT_TRUE(second_map.SetValue("d", Value::CreateStringValue("test")));
+  EXPECT_TRUE(second_map.SetValue("e", Value::CreateStringValue("test")));
+  EXPECT_TRUE(second_map.SetValue("f", Value::CreateStringValue("test")));
+
+  first_map.Swap(&second_map);
+
+  EXPECT_TRUE(first_map.GetValue("d", NULL));
+  EXPECT_TRUE(first_map.GetValue("e", NULL));
+  EXPECT_TRUE(first_map.GetValue("f", NULL));
+
+  EXPECT_TRUE(second_map.GetValue("a", NULL));
+  EXPECT_TRUE(second_map.GetValue("b", NULL));
+  EXPECT_TRUE(second_map.GetValue("c", NULL));
+}
diff --git a/base/prefs/public/pref_change_registrar.cc b/base/prefs/public/pref_change_registrar.cc
new file mode 100644
index 0000000..3f94b04
--- /dev/null
+++ b/base/prefs/public/pref_change_registrar.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/public/pref_change_registrar.h"
+
+#include "base/logging.h"
+#include "base/prefs/public/pref_service_base.h"
+
+PrefChangeRegistrar::PrefChangeRegistrar() : service_(NULL) {}
+
+PrefChangeRegistrar::~PrefChangeRegistrar() {
+  // If you see an invalid memory access in this destructor, this
+  // PrefChangeRegistrar might be subscribed to an OffTheRecordProfileImpl that
+  // has been destroyed. This should not happen any more but be warned.
+  // Feel free to contact battre@chromium.org in case this happens.
+  RemoveAll();
+}
+
+void PrefChangeRegistrar::Init(PrefServiceBase* service) {
+  DCHECK(IsEmpty() || service_ == service);
+  service_ = service;
+}
+
+void PrefChangeRegistrar::Add(const char* path, PrefObserver* obs) {
+  if (!service_) {
+    NOTREACHED();
+    return;
+  }
+  ObserverRegistration registration(path, obs);
+  if (observers_.find(registration) != observers_.end()) {
+    NOTREACHED();
+    return;
+  }
+  observers_.insert(registration);
+  service_->AddPrefObserver(path, obs);
+}
+
+void PrefChangeRegistrar::Remove(const char* path, PrefObserver* obs) {
+  if (!service_) {
+    NOTREACHED();
+    return;
+  }
+  ObserverRegistration registration(path, obs);
+  std::set<ObserverRegistration>::iterator it =
+       observers_.find(registration);
+  if (it == observers_.end()) {
+    NOTREACHED();
+    return;
+  }
+  service_->RemovePrefObserver(it->first.c_str(), it->second);
+  observers_.erase(it);
+}
+
+void PrefChangeRegistrar::RemoveAll() {
+  if (service_) {
+    for (std::set<ObserverRegistration>::const_iterator it = observers_.begin();
+         it != observers_.end(); ++it) {
+      service_->RemovePrefObserver(it->first.c_str(), it->second);
+    }
+    observers_.clear();
+  }
+}
+
+bool PrefChangeRegistrar::IsEmpty() const {
+  return observers_.empty();
+}
+
+bool PrefChangeRegistrar::IsObserved(const std::string& pref) {
+  for (std::set<ObserverRegistration>::const_iterator it = observers_.begin();
+       it != observers_.end(); ++it) {
+    if (it->first == pref)
+      return true;
+  }
+  return false;
+}
+
+bool PrefChangeRegistrar::IsManaged() {
+  for (std::set<ObserverRegistration>::const_iterator it = observers_.begin();
+       it != observers_.end(); ++it) {
+    const PrefServiceBase::Preference* pref =
+        service_->FindPreference(it->first.c_str());
+    if (pref && pref->IsManaged())
+      return true;
+  }
+  return false;
+}
diff --git a/base/prefs/public/pref_change_registrar.h b/base/prefs/public/pref_change_registrar.h
new file mode 100644
index 0000000..f3abd98
--- /dev/null
+++ b/base/prefs/public/pref_change_registrar.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PUBLIC_PREF_CHANGE_REGISTRAR_H_
+#define BASE_PREFS_PUBLIC_PREF_CHANGE_REGISTRAR_H_
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/prefs/base_prefs_export.h"
+
+class PrefObserver;
+class PrefServiceBase;
+
+// Automatically manages the registration of one or more pref change observers
+// with a PrefStore. Functions much like NotificationRegistrar, but specifically
+// manages observers of preference changes. When the Registrar is destroyed,
+// all registered observers are automatically unregistered with the PrefStore.
+class BASE_PREFS_EXPORT PrefChangeRegistrar {
+ public:
+  PrefChangeRegistrar();
+  virtual ~PrefChangeRegistrar();
+
+  // Must be called before adding or removing observers. Can be called more
+  // than once as long as the value of |service| doesn't change.
+  void Init(PrefServiceBase* service);
+
+  // Adds an pref observer for the specified pref |path| and |obs| observer
+  // object. All registered observers will be automatically unregistered
+  // when the registrar's destructor is called unless the observer has been
+  // explicitly removed by a call to Remove beforehand.
+  void Add(const char* path, PrefObserver* obs);
+
+  // Removes a preference observer that has previously been added with a call to
+  // Add.
+  void Remove(const char* path, PrefObserver* obs);
+
+  // Removes all observers that have been previously added with a call to Add.
+  void RemoveAll();
+
+  // Returns true if no pref observers are registered.
+  bool IsEmpty() const;
+
+  // Check whether |pref| is in the set of preferences being observed.
+  bool IsObserved(const std::string& pref);
+
+  // Check whether any of the observed preferences has the managed bit set.
+  bool IsManaged();
+
+ private:
+  typedef std::pair<std::string, PrefObserver*> ObserverRegistration;
+
+  std::set<ObserverRegistration> observers_;
+  PrefServiceBase* service_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefChangeRegistrar);
+};
+
+#endif  // BASE_PREFS_PUBLIC_PREF_CHANGE_REGISTRAR_H_
diff --git a/base/prefs/public/pref_change_registrar_unittest.cc b/base/prefs/public/pref_change_registrar_unittest.cc
new file mode 100644
index 0000000..f860602
--- /dev/null
+++ b/base/prefs/public/pref_change_registrar_unittest.cc
@@ -0,0 +1,212 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/public/pref_change_registrar.h"
+#include "base/prefs/public/pref_observer.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_pref_service.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/test/mock_notification_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Mock;
+using testing::Eq;
+
+namespace {
+
+// TODO(joi): Use PrefObserverMock once it moves to base/prefs/.
+class MockPrefObserver : public PrefObserver {
+ public:
+  virtual ~MockPrefObserver() {}
+
+  MOCK_METHOD2(OnPreferenceChanged, void(PrefServiceBase*, const std::string&));
+};
+
+// A mock provider that allows us to capture pref observer changes.
+class MockPrefService : public TestingPrefService {
+ public:
+  MockPrefService() {}
+  virtual ~MockPrefService() {}
+
+  MOCK_METHOD2(AddPrefObserver,
+               void(const char*, PrefObserver*));
+  MOCK_METHOD2(RemovePrefObserver,
+               void(const char*, PrefObserver*));
+};
+
+}  // namespace
+
+class PrefChangeRegistrarTest : public testing::Test {
+ public:
+  PrefChangeRegistrarTest() {}
+  virtual ~PrefChangeRegistrarTest() {}
+
+ protected:
+  virtual void SetUp();
+
+  PrefObserver* observer() const { return observer_.get(); }
+  MockPrefService* service() const { return service_.get(); }
+
+ private:
+  scoped_ptr<MockPrefService> service_;
+  scoped_ptr<MockPrefObserver> observer_;
+};
+
+void PrefChangeRegistrarTest::SetUp() {
+  service_.reset(new MockPrefService());
+  observer_.reset(new MockPrefObserver());
+}
+
+TEST_F(PrefChangeRegistrarTest, AddAndRemove) {
+  PrefChangeRegistrar registrar;
+  registrar.Init(service());
+
+  // Test adding.
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.1")), observer()));
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.2")), observer()));
+  registrar.Add("test.pref.1", observer());
+  registrar.Add("test.pref.2", observer());
+  EXPECT_FALSE(registrar.IsEmpty());
+
+  // Test removing.
+  Mock::VerifyAndClearExpectations(service());
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.1")), observer()));
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.2")), observer()));
+  registrar.Remove("test.pref.1", observer());
+  registrar.Remove("test.pref.2", observer());
+  EXPECT_TRUE(registrar.IsEmpty());
+
+  // Explicitly check the expectations now to make sure that the Removes
+  // worked (rather than the registrar destructor doing the work).
+  Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(PrefChangeRegistrarTest, AutoRemove) {
+  PrefChangeRegistrar registrar;
+  registrar.Init(service());
+
+  // Setup of auto-remove.
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.1")), observer()));
+  registrar.Add("test.pref.1", observer());
+  Mock::VerifyAndClearExpectations(service());
+  EXPECT_FALSE(registrar.IsEmpty());
+
+  // Test auto-removing.
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.1")), observer()));
+}
+
+TEST_F(PrefChangeRegistrarTest, RemoveAll) {
+  PrefChangeRegistrar registrar;
+  registrar.Init(service());
+
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.1")), observer()));
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.2")), observer()));
+  registrar.Add("test.pref.1", observer());
+  registrar.Add("test.pref.2", observer());
+  Mock::VerifyAndClearExpectations(service());
+
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.1")), observer()));
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.2")), observer()));
+  registrar.RemoveAll();
+  EXPECT_TRUE(registrar.IsEmpty());
+
+  // Explicitly check the expectations now to make sure that the RemoveAll
+  // worked (rather than the registrar destructor doing the work).
+  Mock::VerifyAndClearExpectations(service());
+}
+
+class ObserveSetOfPreferencesTest : public testing::Test {
+ public:
+  virtual void SetUp() {
+    pref_service_.reset(new TestingPrefService);
+    pref_service_->RegisterStringPref(prefs::kHomePage,
+                                      "http://google.com",
+                                      PrefService::UNSYNCABLE_PREF);
+    pref_service_->RegisterBooleanPref(prefs::kHomePageIsNewTabPage,
+                                       false,
+                                       PrefService::UNSYNCABLE_PREF);
+    pref_service_->RegisterStringPref(prefs::kApplicationLocale,
+                                      "",
+                                      PrefService::UNSYNCABLE_PREF);
+  }
+
+  PrefChangeRegistrar* CreatePrefChangeRegistrar(
+      PrefObserver* observer) {
+    PrefChangeRegistrar* pref_set = new PrefChangeRegistrar();
+    pref_set->Init(pref_service_.get());
+    pref_set->Add(prefs::kHomePage, observer);
+    pref_set->Add(prefs::kHomePageIsNewTabPage, observer);
+    return pref_set;
+  }
+
+  scoped_ptr<TestingPrefService> pref_service_;
+};
+
+TEST_F(ObserveSetOfPreferencesTest, IsObserved) {
+  scoped_ptr<PrefChangeRegistrar> pref_set(CreatePrefChangeRegistrar(NULL));
+  EXPECT_TRUE(pref_set->IsObserved(prefs::kHomePage));
+  EXPECT_TRUE(pref_set->IsObserved(prefs::kHomePageIsNewTabPage));
+  EXPECT_FALSE(pref_set->IsObserved(prefs::kApplicationLocale));
+}
+
+TEST_F(ObserveSetOfPreferencesTest, IsManaged) {
+  scoped_ptr<PrefChangeRegistrar> pref_set(CreatePrefChangeRegistrar(NULL));
+  EXPECT_FALSE(pref_set->IsManaged());
+  pref_service_->SetManagedPref(prefs::kHomePage,
+                                Value::CreateStringValue("http://crbug.com"));
+  EXPECT_TRUE(pref_set->IsManaged());
+  pref_service_->SetManagedPref(prefs::kHomePageIsNewTabPage,
+                                Value::CreateBooleanValue(true));
+  EXPECT_TRUE(pref_set->IsManaged());
+  pref_service_->RemoveManagedPref(prefs::kHomePage);
+  EXPECT_TRUE(pref_set->IsManaged());
+  pref_service_->RemoveManagedPref(prefs::kHomePageIsNewTabPage);
+  EXPECT_FALSE(pref_set->IsManaged());
+}
+
+MATCHER_P(PrefNameDetails, name, "details references named preference") {
+  std::string* pstr =
+      reinterpret_cast<const content::Details<std::string>&>(arg).ptr();
+  return pstr && *pstr == name;
+}
+
+TEST_F(ObserveSetOfPreferencesTest, Observe) {
+  using testing::_;
+  using testing::Mock;
+
+  MockPrefObserver observer;
+  scoped_ptr<PrefChangeRegistrar> pref_set(
+      CreatePrefChangeRegistrar(&observer));
+
+  EXPECT_CALL(observer, OnPreferenceChanged(pref_service_.get(),
+                                            prefs::kHomePage));
+  pref_service_->SetUserPref(prefs::kHomePage,
+                             Value::CreateStringValue("http://crbug.com"));
+  Mock::VerifyAndClearExpectations(&observer);
+
+  EXPECT_CALL(observer, OnPreferenceChanged(pref_service_.get(),
+                                            prefs::kHomePageIsNewTabPage));
+  pref_service_->SetUserPref(prefs::kHomePageIsNewTabPage,
+                             Value::CreateBooleanValue(true));
+  Mock::VerifyAndClearExpectations(&observer);
+
+  EXPECT_CALL(observer, OnPreferenceChanged(_, _)).Times(0);
+  pref_service_->SetUserPref(prefs::kApplicationLocale,
+                             Value::CreateStringValue("en_US.utf8"));
+  Mock::VerifyAndClearExpectations(&observer);
+}
diff --git a/base/prefs/public/pref_observer.h b/base/prefs/public/pref_observer.h
new file mode 100644
index 0000000..2692243
--- /dev/null
+++ b/base/prefs/public/pref_observer.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 BASE_PREFS_PUBLIC_PREF_OBSERVER_H_
+#define BASE_PREFS_PUBLIC_PREF_OBSERVER_H_
+
+#include <string>
+
+class PrefServiceBase;
+
+// TODO(joi): Switch to base::Callback and remove this.
+class PrefObserver {
+ public:
+  virtual void OnPreferenceChanged(PrefServiceBase* service,
+                                   const std::string& pref_name) = 0;
+};
+
+#endif  // BASE_PREFS_PUBLIC_PREF_OBSERVER_H_
diff --git a/base/prefs/public/pref_service_base.h b/base/prefs/public/pref_service_base.h
new file mode 100644
index 0000000..131d221
--- /dev/null
+++ b/base/prefs/public/pref_service_base.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.
+
+// This is the base interface for a preference services that provides
+// a way to access the application's current preferences.
+//
+// This base interface assumes all preferences are local.  See
+// SyncablePrefServiceBase for the interface to a preference service
+// that stores preferences that can be synced.
+//
+// Chromium settings and storage represent user-selected preferences and
+// information and MUST not be extracted, overwritten or modified except
+// through Chromium defined APIs.
+
+#ifndef BASE_PREFS_PUBLIC_PREF_SERVICE_BASE_H_
+#define BASE_PREFS_PUBLIC_PREF_SERVICE_BASE_H_
+
+#include "base/values.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace subtle {
+class PrefMemberBase;
+}
+
+class FilePath;
+class PrefObserver;
+class Profile;
+class TabContents;
+
+class PrefServiceBase {
+ public:
+  // Retrieves a PrefServiceBase for the given context.
+  static PrefServiceBase* FromBrowserContext(content::BrowserContext* context);
+
+  virtual ~PrefServiceBase() {}
+
+  // Enum used when registering preferences to determine if it should be synced
+  // or not. This is only used for profile prefs, not local state prefs.
+  // See the Register*Pref methods for profile prefs below.
+  enum PrefSyncStatus {
+    UNSYNCABLE_PREF,
+    SYNCABLE_PREF
+  };
+
+  // Interface to a single preference.
+  class Preference {
+   public:
+    virtual ~Preference() {}
+
+    // Returns the name of the Preference (i.e., the key, e.g.,
+    // browser.window_placement).
+    virtual const std::string name() const = 0;
+
+    // Returns the registered type of the preference.
+    virtual base::Value::Type GetType() const = 0;
+
+    // Returns the value of the Preference, falling back to the registered
+    // default value if no other has been set.
+    virtual const base::Value* GetValue() const = 0;
+
+    // Returns the value recommended by the admin, if any.
+    virtual const base::Value* GetRecommendedValue() const = 0;
+
+    // Returns true if the Preference is managed, i.e. set by an admin policy.
+    // Since managed prefs have the highest priority, this also indicates
+    // whether the pref is actually being controlled by the policy setting.
+    virtual bool IsManaged() const = 0;
+
+    // Returns true if the Preference is recommended, i.e. set by an admin
+    // policy but the user is allowed to change it.
+    virtual bool IsRecommended() const = 0;
+
+    // Returns true if the Preference has a value set by an extension, even if
+    // that value is being overridden by a higher-priority source.
+    virtual bool HasExtensionSetting() const = 0;
+
+    // Returns true if the Preference has a user setting, even if that value is
+    // being overridden by a higher-priority source.
+    virtual bool HasUserSetting() const = 0;
+
+    // Returns true if the Preference value is currently being controlled by an
+    // extension, and not by any higher-priority source.
+    virtual bool IsExtensionControlled() const = 0;
+
+    // Returns true if the Preference value is currently being controlled by a
+    // user setting, and not by any higher-priority source.
+    virtual bool IsUserControlled() const = 0;
+
+    // Returns true if the Preference is currently using its default value,
+    // and has not been set by any higher-priority source (even with the same
+    // value).
+    virtual bool IsDefaultValue() const = 0;
+
+    // Returns true if the user can change the Preference value, which is the
+    // case if no higher-priority source than the user store controls the
+    // Preference.
+    virtual bool IsUserModifiable() const = 0;
+
+    // Returns true if an extension can change the Preference value, which is
+    // the case if no higher-priority source than the extension store controls
+    // the Preference.
+    virtual bool IsExtensionModifiable() const = 0;
+  };
+
+  // Returns true if the preference for the given preference name is available
+  // and is managed.
+  virtual bool IsManagedPreference(const char* pref_name) const = 0;
+
+  // Returns |true| if a preference with the given name is available and its
+  // value can be changed by the user.
+  virtual bool IsUserModifiablePreference(const char* pref_name) const = 0;
+
+  // Make the PrefService aware of a pref.
+  // TODO(zea): split local state and profile prefs into their own subclasses.
+  // ---------- Local state prefs  ----------
+  virtual void RegisterBooleanPref(const char* path,
+                                   bool default_value) = 0;
+  virtual void RegisterIntegerPref(const char* path,
+                                   int default_value) = 0;
+  virtual void RegisterDoublePref(const char* path,
+                                  double default_value) = 0;
+  virtual void RegisterStringPref(const char* path,
+                                  const std::string& default_value) = 0;
+  virtual void RegisterFilePathPref(const char* path,
+                                    const FilePath& default_value) = 0;
+  virtual void RegisterListPref(const char* path) = 0;
+  virtual void RegisterDictionaryPref(const char* path) = 0;
+  // These take ownership of the default_value:
+  virtual void RegisterListPref(const char* path,
+                                base::ListValue* default_value) = 0;
+  virtual void RegisterDictionaryPref(
+      const char* path, base::DictionaryValue* default_value) = 0;
+  // These variants use a default value from the locale dll instead.
+  virtual void RegisterLocalizedBooleanPref(
+      const char* path, int locale_default_message_id) = 0;
+  virtual void RegisterLocalizedIntegerPref(
+      const char* path, int locale_default_message_id) = 0;
+  virtual void RegisterLocalizedDoublePref(
+      const char* path, int locale_default_message_id) = 0;
+  virtual void RegisterLocalizedStringPref(
+      const char* path, int locale_default_message_id) = 0;
+  virtual void RegisterInt64Pref(const char* path,
+                                 int64 default_value) = 0;
+
+  //  ---------- Profile prefs  ----------
+  // Profile prefs must specify whether the pref should be synchronized across
+  // machines or not (see PrefSyncStatus enum above).
+  virtual void RegisterBooleanPref(const char* path,
+                                   bool default_value,
+                                   PrefSyncStatus sync_status) = 0;
+  virtual void RegisterIntegerPref(const char* path,
+                                   int default_value,
+                                   PrefSyncStatus sync_status) = 0;
+  virtual void RegisterDoublePref(const char* path,
+                                  double default_value,
+                                  PrefSyncStatus sync_status) = 0;
+  virtual void RegisterStringPref(const char* path,
+                                  const std::string& default_value,
+                                  PrefSyncStatus sync_status) = 0;
+  virtual void RegisterFilePathPref(const char* path,
+                                    const FilePath& default_value,
+                                    PrefSyncStatus sync_status) = 0;
+  virtual void RegisterListPref(const char* path,
+                                PrefSyncStatus sync_status) = 0;
+  virtual void RegisterDictionaryPref(const char* path,
+                                      PrefSyncStatus sync_status) = 0;
+  // These take ownership of the default_value:
+  virtual void RegisterListPref(const char* path,
+                                base::ListValue* default_value,
+                                PrefSyncStatus sync_status) = 0;
+  virtual void RegisterDictionaryPref(const char* path,
+                                      base::DictionaryValue* default_value,
+                                      PrefSyncStatus sync_status) = 0;
+  // These variants use a default value from the locale dll instead.
+  virtual void RegisterLocalizedBooleanPref(
+      const char* path,
+      int locale_default_message_id,
+      PrefSyncStatus sync_status) = 0;
+  virtual void RegisterLocalizedIntegerPref(
+      const char* path,
+      int locale_default_message_id,
+      PrefSyncStatus sync_status) = 0;
+  virtual void RegisterLocalizedDoublePref(
+      const char* path,
+      int locale_default_message_id,
+      PrefSyncStatus sync_status) = 0;
+  virtual void RegisterLocalizedStringPref(
+      const char* path,
+      int locale_default_message_id,
+      PrefSyncStatus sync_status) = 0;
+  virtual void RegisterInt64Pref(const char* path,
+                                 int64 default_value,
+                                 PrefSyncStatus sync_status) = 0;
+  virtual void RegisterUint64Pref(const char* path,
+                                  uint64 default_value,
+                                  PrefSyncStatus sync_status) = 0;
+  // Unregisters a preference.
+  virtual void UnregisterPreference(const char* path) = 0;
+
+  // Look up a preference.  Returns NULL if the preference is not
+  // registered.
+  virtual const Preference* FindPreference(const char* pref_name) const = 0;
+
+  // If the path is valid and the value at the end of the path matches the type
+  // specified, it will return the specified value.  Otherwise, the default
+  // value (set when the pref was registered) will be returned.
+  virtual bool GetBoolean(const char* path) const = 0;
+  virtual int GetInteger(const char* path) const = 0;
+  virtual double GetDouble(const char* path) const = 0;
+  virtual std::string GetString(const char* path) const = 0;
+  virtual FilePath GetFilePath(const char* path) const = 0;
+
+  // Returns the branch if it exists, or the registered default value otherwise.
+  // Note that |path| must point to a registered preference. In that case, these
+  // functions will never return NULL.
+  virtual const base::DictionaryValue* GetDictionary(
+      const char* path) const = 0;
+  virtual const base::ListValue* GetList(const char* path) const = 0;
+
+  // Removes a user pref and restores the pref to its default value.
+  virtual void ClearPref(const char* path) = 0;
+
+  // If the path is valid (i.e., registered), update the pref value in the user
+  // prefs.
+  // To set the value of dictionary or list values in the pref tree use
+  // Set(), but to modify the value of a dictionary or list use either
+  // ListPrefUpdate or DictionaryPrefUpdate from scoped_user_pref_update.h.
+  virtual void Set(const char* path, const base::Value& value) = 0;
+  virtual void SetBoolean(const char* path, bool value) = 0;
+  virtual void SetInteger(const char* path, int value) = 0;
+  virtual void SetDouble(const char* path, double value) = 0;
+  virtual void SetString(const char* path, const std::string& value) = 0;
+  virtual void SetFilePath(const char* path, const FilePath& value) = 0;
+
+  // Int64 helper methods that actually store the given value as a string.
+  // Note that if obtaining the named value via GetDictionary or GetList, the
+  // Value type will be TYPE_STRING.
+  virtual void SetInt64(const char* path, int64 value) = 0;
+  virtual int64 GetInt64(const char* path) const = 0;
+
+  // As above, but for unsigned values.
+  virtual void SetUint64(const char* path, uint64 value) = 0;
+  virtual uint64 GetUint64(const char* path) const = 0;
+
+ protected:
+  // Registration of pref change observers must be done using the
+  // PrefChangeRegistrar, which is declared as a friend here to grant it
+  // access to the otherwise protected members Add/RemovePrefObserver.
+  // PrefMember registers for preferences changes notification directly to
+  // avoid the storage overhead of the registrar, so its base class must be
+  // declared as a friend, too.
+  friend class PrefChangeRegistrar;
+  friend class subtle::PrefMemberBase;
+
+  // These are protected so they can only be accessed by the friend
+  // classes listed above.
+  //
+  // If the pref at the given path changes, we call the observer's
+  // OnPreferenceChanged method. Note that observers should not call
+  // these methods directly but rather use a PrefChangeRegistrar to
+  // make sure the observer gets cleaned up properly.
+  virtual void AddPrefObserver(const char* path, PrefObserver* obs) = 0;
+  virtual void RemovePrefObserver(const char* path, PrefObserver* obs) = 0;
+};
+
+#endif  // BASE_PREFS_PUBLIC_PREF_SERVICE_BASE_H_
diff --git a/base/prefs/testing_pref_store.cc b/base/prefs/testing_pref_store.cc
new file mode 100644
index 0000000..d40fb8a
--- /dev/null
+++ b/base/prefs/testing_pref_store.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/testing_pref_store.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+TestingPrefStore::TestingPrefStore()
+    : read_only_(true),
+      init_complete_(false) {
+}
+
+bool TestingPrefStore::GetValue(const std::string& key,
+                                const Value** value) const {
+  return prefs_.GetValue(key, value);
+}
+
+bool TestingPrefStore::GetMutableValue(const std::string& key,
+                                       Value** value) {
+  return prefs_.GetValue(key, value);
+}
+
+void TestingPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void TestingPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+size_t TestingPrefStore::NumberOfObservers() const {
+  return observers_.size();
+}
+
+bool TestingPrefStore::IsInitializationComplete() const {
+  return init_complete_;
+}
+
+void TestingPrefStore::SetValue(const std::string& key, Value* value) {
+  if (prefs_.SetValue(key, value))
+    NotifyPrefValueChanged(key);
+}
+
+void TestingPrefStore::SetValueSilently(const std::string& key, Value* value) {
+  prefs_.SetValue(key, value);
+}
+
+void TestingPrefStore::RemoveValue(const std::string& key) {
+  if (prefs_.RemoveValue(key))
+    NotifyPrefValueChanged(key);
+}
+
+void TestingPrefStore::MarkNeedsEmptyValue(const std::string& key) {
+}
+
+bool TestingPrefStore::ReadOnly() const {
+  return read_only_;
+}
+
+PersistentPrefStore::PrefReadError TestingPrefStore::GetReadError() const {
+  return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+PersistentPrefStore::PrefReadError TestingPrefStore::ReadPrefs() {
+  NotifyInitializationCompleted();
+  return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+void TestingPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate_raw) {
+  scoped_ptr<ReadErrorDelegate> error_delegate(error_delegate_raw);
+  NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::SetInitializationCompleted() {
+  init_complete_ = true;
+  NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::NotifyPrefValueChanged(const std::string& key) {
+  FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void TestingPrefStore::NotifyInitializationCompleted() {
+  FOR_EACH_OBSERVER(Observer, observers_, OnInitializationCompleted(true));
+}
+
+void TestingPrefStore::ReportValueChanged(const std::string& key) {
+  FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void TestingPrefStore::SetString(const std::string& key,
+                                 const std::string& value) {
+  SetValue(key, Value::CreateStringValue(value));
+}
+
+void TestingPrefStore::SetInteger(const std::string& key, int value) {
+  SetValue(key, Value::CreateIntegerValue(value));
+}
+
+void TestingPrefStore::SetBoolean(const std::string& key, bool value) {
+  SetValue(key, Value::CreateBooleanValue(value));
+}
+
+bool TestingPrefStore::GetString(const std::string& key,
+                                 std::string* value) const {
+  const Value* stored_value;
+  if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+    return false;
+
+  return stored_value->GetAsString(value);
+}
+
+bool TestingPrefStore::GetInteger(const std::string& key, int* value) const {
+  const Value* stored_value;
+  if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+    return false;
+
+  return stored_value->GetAsInteger(value);
+}
+
+bool TestingPrefStore::GetBoolean(const std::string& key, bool* value) const {
+  const Value* stored_value;
+  if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+    return false;
+
+  return stored_value->GetAsBoolean(value);
+}
+
+void TestingPrefStore::set_read_only(bool read_only) {
+  read_only_ = read_only;
+}
+
+TestingPrefStore::~TestingPrefStore() {}
diff --git a/base/prefs/testing_pref_store.h b/base/prefs/testing_pref_store.h
new file mode 100644
index 0000000..a9f1e92
--- /dev/null
+++ b/base/prefs/testing_pref_store.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_TESTING_PREF_STORE_H_
+#define BASE_PREFS_TESTING_PREF_STORE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/observer_list.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/prefs/pref_value_map.h"
+
+// |TestingPrefStore| is a preference store implementation that allows tests to
+// explicitly manipulate the contents of the store, triggering notifications
+// where appropriate.
+class TestingPrefStore : public PersistentPrefStore {
+ public:
+  TestingPrefStore();
+
+  // Overriden from PrefStore.
+  virtual bool GetValue(const std::string& key,
+                        const base::Value** result) const OVERRIDE;
+  virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE;
+  virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE;
+  virtual size_t NumberOfObservers() const OVERRIDE;
+  virtual bool IsInitializationComplete() const OVERRIDE;
+
+  // PersistentPrefStore overrides:
+  virtual bool GetMutableValue(const std::string& key,
+                               base::Value** result) OVERRIDE;
+  virtual void ReportValueChanged(const std::string& key) OVERRIDE;
+  virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE;
+  virtual void SetValueSilently(const std::string& key,
+                                base::Value* value) OVERRIDE;
+  virtual void RemoveValue(const std::string& key) OVERRIDE;
+  virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE;
+  virtual bool ReadOnly() const OVERRIDE;
+  virtual PrefReadError GetReadError() const OVERRIDE;
+  virtual PersistentPrefStore::PrefReadError ReadPrefs() OVERRIDE;
+  virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) OVERRIDE;
+  virtual void CommitPendingWrite() OVERRIDE {}
+
+  // Marks the store as having completed initialization.
+  void SetInitializationCompleted();
+
+  // Used for tests to trigger notifications explicitly.
+  void NotifyPrefValueChanged(const std::string& key);
+  void NotifyInitializationCompleted();
+
+  // Some convenience getters/setters.
+  void SetString(const std::string& key, const std::string& value);
+  void SetInteger(const std::string& key, int value);
+  void SetBoolean(const std::string& key, bool value);
+
+  bool GetString(const std::string& key, std::string* value) const;
+  bool GetInteger(const std::string& key, int* value) const;
+  bool GetBoolean(const std::string& key, bool* value) const;
+
+  // Getter and Setter methods for setting and getting the state of the
+  // |TestingPrefStore|.
+  virtual void set_read_only(bool read_only);
+
+ protected:
+  virtual ~TestingPrefStore();
+
+ private:
+  // Stores the preference values.
+  PrefValueMap prefs_;
+
+  // Flag that indicates if the PrefStore is read-only
+  bool read_only_;
+
+  // Whether initialization has been completed.
+  bool init_complete_;
+
+  ObserverList<PrefStore::Observer, true> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingPrefStore);
+};
+
+#endif  // BASE_PREFS_TESTING_PREF_STORE_H_
diff --git a/base/prefs/value_map_pref_store.cc b/base/prefs/value_map_pref_store.cc
new file mode 100644
index 0000000..1d58aa3
--- /dev/null
+++ b/base/prefs/value_map_pref_store.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/value_map_pref_store.h"
+
+#include <algorithm>
+
+#include "base/stl_util.h"
+#include "base/values.h"
+
+ValueMapPrefStore::ValueMapPrefStore() {}
+
+bool ValueMapPrefStore::GetValue(const std::string& key,
+                                 const Value** value) const {
+  return prefs_.GetValue(key, value);
+}
+
+void ValueMapPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ValueMapPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+size_t ValueMapPrefStore::NumberOfObservers() const {
+  return observers_.size();
+}
+
+ValueMapPrefStore::~ValueMapPrefStore() {}
+
+void ValueMapPrefStore::SetValue(const std::string& key, Value* value) {
+  if (prefs_.SetValue(key, value))
+    FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void ValueMapPrefStore::RemoveValue(const std::string& key) {
+  if (prefs_.RemoveValue(key))
+    FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void ValueMapPrefStore::NotifyInitializationCompleted() {
+  FOR_EACH_OBSERVER(Observer, observers_, OnInitializationCompleted(true));
+}
diff --git a/base/prefs/value_map_pref_store.h b/base/prefs/value_map_pref_store.h
new file mode 100644
index 0000000..c9c9b1c
--- /dev/null
+++ b/base/prefs/value_map_pref_store.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_VALUE_MAP_PREF_STORE_H_
+#define BASE_PREFS_VALUE_MAP_PREF_STORE_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_store.h"
+#include "base/prefs/pref_value_map.h"
+
+// A basic PrefStore implementation that uses a simple name-value map for
+// storing the preference values.
+class BASE_PREFS_EXPORT ValueMapPrefStore : public PrefStore {
+ public:
+  ValueMapPrefStore();
+
+  // PrefStore overrides:
+  virtual bool GetValue(const std::string& key,
+                        const base::Value** value) const OVERRIDE;
+  virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE;
+  virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE;
+  virtual size_t NumberOfObservers() const OVERRIDE;
+
+ protected:
+  virtual ~ValueMapPrefStore();
+
+  // Store a |value| for |key| in the store. Also generates an notification if
+  // the value changed. Assumes ownership of |value|, which must be non-NULL.
+  void SetValue(const std::string& key, base::Value* value);
+
+  // Remove the value for |key| from the store. Sends a notification if there
+  // was a value to be removed.
+  void RemoveValue(const std::string& key);
+
+  // Notify observers about the initialization completed event.
+  void NotifyInitializationCompleted();
+
+ private:
+  PrefValueMap prefs_;
+
+  ObserverList<PrefStore::Observer, true> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(ValueMapPrefStore);
+};
+
+#endif  // BASE_PREFS_VALUE_MAP_PREF_STORE_H_
diff --git a/base/process.h b/base/process.h
new file mode 100644
index 0000000..84b8579
--- /dev/null
+++ b/base/process.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_H_
+#define BASE_PROCESS_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#include <sys/types.h>
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+// ProcessHandle is a platform specific type which represents the underlying OS
+// handle to a process.
+// ProcessId is a number which identifies the process in the OS.
+#if defined(OS_WIN)
+typedef HANDLE ProcessHandle;
+typedef DWORD ProcessId;
+typedef HANDLE UserTokenHandle;
+const ProcessHandle kNullProcessHandle = NULL;
+const ProcessId kNullProcessId = 0;
+#elif defined(OS_POSIX)
+// On POSIX, our ProcessHandle will just be the PID.
+typedef pid_t ProcessHandle;
+typedef pid_t ProcessId;
+const ProcessHandle kNullProcessHandle = 0;
+const ProcessId kNullProcessId = 0;
+#endif  // defined(OS_WIN)
+
+class BASE_EXPORT Process {
+ public:
+  Process() : process_(kNullProcessHandle) {
+  }
+
+  explicit Process(ProcessHandle handle) : process_(handle) {
+  }
+
+  // A handle to the current process.
+  static Process Current();
+
+  static bool CanBackgroundProcesses();
+
+  // Get/Set the handle for this process. The handle will be 0 if the process
+  // is no longer running.
+  ProcessHandle handle() const { return process_; }
+  void set_handle(ProcessHandle handle) {
+    process_ = handle;
+  }
+
+  // Get the PID for this process.
+  ProcessId pid() const;
+
+  // Is the this process 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 result code will
+  // be the exit code of the process. If the process has already exited, this
+  // will do nothing.
+  void Terminate(int result_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;
+
+ private:
+  ProcessHandle process_;
+};
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_H_
diff --git a/base/process_info.h b/base/process_info.h
new file mode 100644
index 0000000..429d4dc
--- /dev/null
+++ b/base/process_info.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_PROCESS_INFO_H_
+#define BASE_PROCESS_INFO_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.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 or NULL if an error
+  // occurred retrieving the information.
+  static const Time* CreationTime();
+};
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_INFO_H_
diff --git a/base/process_info_mac.cc b/base/process_info_mac.cc
new file mode 100644
index 0000000..247a144
--- /dev/null
+++ b/base/process_info_mac.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process_info.h"
+
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time.h"
+
+namespace {
+
+using base::Time;
+
+// Returns the process creation time, or NULL if an error occurred.
+Time* ProcessCreationTimeInternal() {
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
+  size_t len = 0;
+  if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0)
+    return NULL;
+
+  scoped_ptr_malloc<struct kinfo_proc>
+      proc(static_cast<struct kinfo_proc*>(malloc(len)));
+  if (sysctl(mib, arraysize(mib), proc.get(), &len, NULL, 0) < 0)
+    return NULL;
+  return new Time(Time::FromTimeVal(proc->kp_proc.p_un.__p_starttime));
+}
+
+}  // namespace
+
+namespace base {
+
+//static
+const Time* CurrentProcessInfo::CreationTime() {
+  static Time* process_creation_time = ProcessCreationTimeInternal();
+  return process_creation_time;
+}
+
+}  // namespace base
diff --git a/base/process_info_win.cc b/base/process_info_win.cc
new file mode 100644
index 0000000..762961f
--- /dev/null
+++ b/base/process_info_win.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process_info.h"
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/time.h"
+
+namespace {
+
+using base::Time;
+
+// Returns the process creation time, or NULL if an error occurred.
+Time* ProcessCreationTimeInternal() {
+  FILETIME creation_time = {};
+  FILETIME ignore = {};
+  if (::GetProcessTimes(::GetCurrentProcess(), &creation_time, &ignore,
+      &ignore, &ignore) == false)
+    return NULL;
+
+  return new Time(Time::FromFileTime(creation_time));
+}
+
+}  // namespace
+
+namespace base {
+
+//static
+const Time* CurrentProcessInfo::CreationTime() {
+  static Time* process_creation_time = ProcessCreationTimeInternal();
+  return process_creation_time;
+}
+
+}  // namespace base
diff --git a/base/process_linux.cc b/base/process_linux.cc
new file mode 100644
index 0000000..9f69596
--- /dev/null
+++ b/base/process_linux.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2011 The Chromium Authors. All 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.h"
+
+#include <errno.h>
+#include <sys/resource.h>
+
+#include "base/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "base/string_split.h"
+#include "base/synchronization/lock.h"
+
+namespace {
+const int kForegroundPriority = 0;
+
+#if defined(OS_CHROMEOS)
+// We are more aggressive in our lowering of background process priority
+// for chromeos as we have much more control over other processes running
+// on the machine.
+//
+// TODO(davemoore) Refactor this by adding support for higher levels to set
+// the foregrounding / backgrounding process so we don't have to keep
+// chrome / chromeos specific logic here.
+const int kBackgroundPriority = 19;
+const char kControlPath[] = "/tmp/cgroup/cpu%s/cgroup.procs";
+const char kForeground[] = "/chrome_renderers/foreground";
+const char kBackground[] = "/chrome_renderers/background";
+const char kProcPath[] = "/proc/%d/cgroup";
+
+struct CGroups {
+  // Check for cgroups files. ChromeOS supports these by default. It creates
+  // a cgroup mount in /tmp/cgroup and then configures two cpu task groups,
+  // one contains at most a single foreground renderer and the other contains
+  // all background renderers. This allows us to limit the impact of background
+  // renderers on foreground ones to a greater level than simple renicing.
+  bool enabled;
+  FilePath foreground_file;
+  FilePath background_file;
+
+  CGroups() {
+    foreground_file = FilePath(StringPrintf(kControlPath, kForeground));
+    background_file = FilePath(StringPrintf(kControlPath, kBackground));
+    file_util::FileSystemType foreground_type;
+    file_util::FileSystemType background_type;
+    enabled =
+        file_util::GetFileSystemType(foreground_file, &foreground_type) &&
+        file_util::GetFileSystemType(background_file, &background_type) &&
+        foreground_type == file_util::FILE_SYSTEM_CGROUP &&
+        background_type == file_util::FILE_SYSTEM_CGROUP;
+  }
+};
+
+base::LazyInstance<CGroups> cgroups = LAZY_INSTANCE_INITIALIZER;
+#else
+const int kBackgroundPriority = 5;
+#endif
+}
+
+namespace base {
+
+bool Process::IsProcessBackgrounded() const {
+  DCHECK(process_);
+
+#if defined(OS_CHROMEOS)
+  if (cgroups.Get().enabled) {
+    std::string proc;
+    if (file_util::ReadFileToString(
+        FilePath(StringPrintf(kProcPath, process_)),
+        &proc)) {
+      std::vector<std::string> proc_parts;
+      base::SplitString(proc, ':', &proc_parts);
+      DCHECK(proc_parts.size() == 3);
+      bool ret = proc_parts[2] == std::string(kBackground);
+      return ret;
+    } else {
+      return false;
+    }
+  }
+#endif
+  return GetPriority() == kBackgroundPriority;
+}
+
+bool Process::SetProcessBackgrounded(bool background) {
+  DCHECK(process_);
+
+#if defined(OS_CHROMEOS)
+  if (cgroups.Get().enabled) {
+    std::string pid = StringPrintf("%d", process_);
+    const FilePath file =
+        background ?
+            cgroups.Get().background_file : cgroups.Get().foreground_file;
+    return file_util::WriteFile(file, pid.c_str(), pid.size()) > 0;
+  }
+#endif // OS_CHROMEOS
+
+  if (!CanBackgroundProcesses())
+    return false;
+
+  int priority = background ? kBackgroundPriority : kForegroundPriority;
+  int result = setpriority(PRIO_PROCESS, process_, priority);
+  DPCHECK(result == 0);
+  return result == 0;
+}
+
+struct CheckForNicePermission {
+  CheckForNicePermission() : can_reraise_priority(false) {
+    // We won't be able to raise the priority if we don't have the right rlimit.
+    // The limit may be adjusted in /etc/security/limits.conf for PAM systems.
+    struct rlimit rlim;
+    if ((getrlimit(RLIMIT_NICE, &rlim) == 0) &&
+        (20 - kForegroundPriority) <= static_cast<int>(rlim.rlim_cur)) {
+        can_reraise_priority = true;
+    }
+  };
+
+  bool can_reraise_priority;
+};
+
+// static
+bool Process::CanBackgroundProcesses() {
+#if defined(OS_CHROMEOS)
+  if (cgroups.Get().enabled)
+    return true;
+#endif
+
+  static LazyInstance<CheckForNicePermission> check_for_nice_permission =
+      LAZY_INSTANCE_INITIALIZER;
+  return check_for_nice_permission.Get().can_reraise_priority;
+}
+
+}  // namespace base
diff --git a/base/process_posix.cc b/base/process_posix.cc
new file mode 100644
index 0000000..20e623c
--- /dev/null
+++ b/base/process_posix.cc
@@ -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.
+
+#include "base/process.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include "base/process_util.h"
+#include "base/logging.h"
+
+namespace base {
+
+// static
+Process Process::Current() {
+  return Process(GetCurrentProcessHandle());
+}
+
+ProcessId Process::pid() const {
+  if (process_ == 0)
+    return 0;
+
+  return GetProcId(process_);
+}
+
+bool Process::is_current() const {
+  return process_ == GetCurrentProcessHandle();
+}
+
+void Process::Close() {
+  process_ = 0;
+  // 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.
+}
+
+void Process::Terminate(int result_code) {
+  // result_code isn't supportable.
+  if (!process_)
+    return;
+  // We don't wait here. It's the responsibility of other code to reap the
+  // child.
+  KillProcess(process_, result_code, false);
+}
+
+#if !defined(OS_LINUX)
+bool Process::IsProcessBackgrounded() const {
+  // See SetProcessBackgrounded().
+  return false;
+}
+
+bool Process::SetProcessBackgrounded(bool value) {
+  // POSIX only allows lowering the priority of a process, so if we
+  // were to lower it we wouldn't be able to raise it back to its initial
+  // priority.
+  return false;
+}
+
+// static
+bool Process::CanBackgroundProcesses() {
+  return false;
+}
+
+#endif
+
+int Process::GetPriority() const {
+  DCHECK(process_);
+  return getpriority(PRIO_PROCESS, process_);
+}
+
+}  // namspace base
diff --git a/base/process_util.cc b/base/process_util.cc
new file mode 100644
index 0000000..9979dfa
--- /dev/null
+++ b/base/process_util.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process_util.h"
+
+namespace base {
+
+#if defined(OS_POSIX)
+ProcessEntry::ProcessEntry() : pid_(0), ppid_(0), gid_(0) {}
+ProcessEntry::~ProcessEntry() {}
+#endif
+
+int GetProcessCount(const FilePath::StringType& executable_name,
+                    const ProcessFilter* filter) {
+  int count = 0;
+  NamedProcessIterator iter(executable_name, filter);
+  while (iter.NextProcessEntry())
+    ++count;
+  return count;
+}
+
+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()) {
+#if defined(OS_WIN)
+    result &= KillProcessById(entry->pid(), exit_code, true);
+#else
+    result &= KillProcess(entry->pid(), exit_code, true);
+#endif
+  }
+  return result;
+}
+
+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() {
+}
+
+}  // namespace base
diff --git a/base/process_util.h b/base/process_util.h
new file mode 100644
index 0000000..2805e42
--- /dev/null
+++ b/base/process_util.h
@@ -0,0 +1,883 @@
+// Copyright (c) 2012 The Chromium 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/namespace contains utility functions for enumerating, ending and
+// computing statistics of processes.
+
+#ifndef BASE_PROCESS_UTIL_H_
+#define BASE_PROCESS_UTIL_H_
+
+#include "base/basictypes.h"
+#include "base/time.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <tlhelp32.h>
+#elif defined(OS_MACOSX) || defined(OS_BSD)
+// kinfo_proc is defined in <sys/sysctl.h>, but this forward declaration
+// is sufficient for the vector<kinfo_proc> below.
+struct kinfo_proc;
+// malloc_zone_t is defined in <malloc/malloc.h>, but this forward declaration
+// is sufficient for GetPurgeableZone() below.
+typedef struct _malloc_zone_t malloc_zone_t;
+#if !defined(OS_BSD)
+#include <mach/mach.h>
+#endif
+#elif defined(OS_POSIX)
+#include <dirent.h>
+#include <limits.h>
+#include <sys/types.h>
+#endif
+
+#include <list>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/file_path.h"
+#include "base/process.h"
+
+#if defined(OS_POSIX)
+#include "base/posix/file_descriptor_shuffle.h"
+#endif
+
+class CommandLine;
+
+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; }
+};
+
+struct IoCounters : public IO_COUNTERS {
+};
+
+// Process access masks. These constants provide platform-independent
+// definitions for the standard Windows access masks.
+// See http://msdn.microsoft.com/en-us/library/ms684880(VS.85).aspx for
+// the specific semantics of each mask value.
+const uint32 kProcessAccessTerminate              = PROCESS_TERMINATE;
+const uint32 kProcessAccessCreateThread           = PROCESS_CREATE_THREAD;
+const uint32 kProcessAccessSetSessionId           = PROCESS_SET_SESSIONID;
+const uint32 kProcessAccessVMOperation            = PROCESS_VM_OPERATION;
+const uint32 kProcessAccessVMRead                 = PROCESS_VM_READ;
+const uint32 kProcessAccessVMWrite                = PROCESS_VM_WRITE;
+const uint32 kProcessAccessDuplicateHandle        = PROCESS_DUP_HANDLE;
+const uint32 kProcessAccessCreateProcess          = PROCESS_CREATE_PROCESS;
+const uint32 kProcessAccessSetQuota               = PROCESS_SET_QUOTA;
+const uint32 kProcessAccessSetInformation         = PROCESS_SET_INFORMATION;
+const uint32 kProcessAccessQueryInformation       = PROCESS_QUERY_INFORMATION;
+const uint32 kProcessAccessSuspendResume          = PROCESS_SUSPEND_RESUME;
+const uint32 kProcessAccessQueryLimitedInfomation =
+    PROCESS_QUERY_LIMITED_INFORMATION;
+const uint32 kProcessAccessWaitForTermination     = SYNCHRONIZE;
+#elif defined(OS_POSIX)
+
+struct ProcessEntry {
+  ProcessEntry();
+  ~ProcessEntry();
+
+  ProcessId pid() const { return pid_; }
+  ProcessId parent_pid() const { return ppid_; }
+  ProcessId gid() const { return gid_; }
+  const char* exe_file() const { return exe_file_.c_str(); }
+  const std::vector<std::string>& cmd_line_args() const {
+    return cmd_line_args_;
+  }
+
+  ProcessId pid_;
+  ProcessId ppid_;
+  ProcessId gid_;
+  std::string exe_file_;
+  std::vector<std::string> cmd_line_args_;
+};
+
+struct IoCounters {
+  uint64_t ReadOperationCount;
+  uint64_t WriteOperationCount;
+  uint64_t OtherOperationCount;
+  uint64_t ReadTransferCount;
+  uint64_t WriteTransferCount;
+  uint64_t OtherTransferCount;
+};
+
+// Process access masks. They are not used on Posix because access checking
+// does not happen during handle creation.
+const uint32 kProcessAccessTerminate              = 0;
+const uint32 kProcessAccessCreateThread           = 0;
+const uint32 kProcessAccessSetSessionId           = 0;
+const uint32 kProcessAccessVMOperation            = 0;
+const uint32 kProcessAccessVMRead                 = 0;
+const uint32 kProcessAccessVMWrite                = 0;
+const uint32 kProcessAccessDuplicateHandle        = 0;
+const uint32 kProcessAccessCreateProcess          = 0;
+const uint32 kProcessAccessSetQuota               = 0;
+const uint32 kProcessAccessSetInformation         = 0;
+const uint32 kProcessAccessQueryInformation       = 0;
+const uint32 kProcessAccessSuspendResume          = 0;
+const uint32 kProcessAccessQueryLimitedInfomation = 0;
+const uint32 kProcessAccessWaitForTermination     = 0;
+#endif  // defined(OS_POSIX)
+
+// 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
+  TERMINATION_STATUS_MAX_ENUM
+};
+
+#if defined(USE_LINUX_BREAKPAD)
+BASE_EXPORT extern size_t g_oom_size;
+#endif
+
+#if defined(OS_WIN)
+// Output multi-process printf, cout, cerr, etc to the cmd.exe console that ran
+// chrome. This is not thread-safe: only call from main thread.
+BASE_EXPORT void RouteStdioToConsole();
+#endif
+
+// Returns the id of the current process.
+BASE_EXPORT ProcessId GetCurrentProcId();
+
+// Returns the ProcessHandle of the current process.
+BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
+
+#if defined(OS_WIN)
+// Returns the module handle to which an address belongs. The reference count
+// of the module is not incremented.
+BASE_EXPORT HMODULE GetModuleFromAddress(void* address);
+#endif
+
+// Converts a PID to a process handle. This handle must be closed by
+// CloseProcessHandle when you are done with it. Returns true on success.
+BASE_EXPORT bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle);
+
+// Converts a PID to a process handle. On Windows the handle is opened
+// with more access rights and must only be used by trusted code.
+// You have to close returned handle using CloseProcessHandle. Returns true
+// on success.
+// TODO(sanjeevr): Replace all calls to OpenPrivilegedProcessHandle with the
+// more specific OpenProcessHandleWithAccess method and delete this.
+BASE_EXPORT bool OpenPrivilegedProcessHandle(ProcessId pid,
+                                             ProcessHandle* handle);
+
+// Converts a PID to a process handle using the desired access flags. Use a
+// combination of the kProcessAccess* flags defined above for |access_flags|.
+BASE_EXPORT bool OpenProcessHandleWithAccess(ProcessId pid,
+                                             uint32 access_flags,
+                                             ProcessHandle* handle);
+
+// Closes the process handle opened by OpenProcessHandle.
+BASE_EXPORT void CloseProcessHandle(ProcessHandle process);
+
+// Returns the unique ID for the specified process. This is functionally the
+// same as Windows' GetProcessId(), but works on versions of Windows before
+// Win XP SP1 as well.
+BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
+
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_BSD)
+// Returns the path to the executable of the given process.
+BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
+#endif
+
+#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);
+
+// The maximum allowed value for the OOM score.
+const int kMaxOomScore = 1000;
+
+// This adjusts /proc/<pid>/oom_score_adj so the Linux OOM killer will
+// prefer to kill certain process types over others. The range for the
+// adjustment is [-1000, 1000], with [0, 1000] being user accessible.
+// If the Linux system doesn't support the newer oom_score_adj range
+// of [0, 1000], then we revert to using the older oom_adj, and
+// translate the given value into [0, 15].  Some aliasing of values
+// may occur in that case, of course.
+BASE_EXPORT bool AdjustOOMScore(ProcessId process, int score);
+
+// /proc/self/exe refers to the current executable.
+BASE_EXPORT extern const char kProcSelfExe[];
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+#if defined(OS_POSIX)
+// Returns the ID for the parent of the given process.
+BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
+
+// 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)
+
+typedef std::vector<std::pair<std::string, std::string> > EnvironmentVector;
+typedef std::vector<std::pair<int, int> > FileHandleMappingVector;
+
+#if defined(OS_MACOSX)
+// Used with LaunchOptions::synchronize and LaunchSynchronize, a
+// LaunchSynchronizationHandle is an opaque value that LaunchProcess will
+// create and set, and that LaunchSynchronize will consume and destroy.
+typedef int* LaunchSynchronizationHandle;
+#endif  // defined(OS_MACOSX)
+
+// Options for launching a subprocess that are passed to LaunchProcess().
+// The default constructor constructs the object with default options.
+struct LaunchOptions {
+  LaunchOptions() : wait(false),
+#if defined(OS_WIN)
+                    start_hidden(false), inherit_handles(false), as_user(NULL),
+                    empty_desktop_name(false), job_handle(NULL),
+                    force_breakaway_from_job_(false)
+#else
+                    environ(NULL), fds_to_remap(NULL), maximize_rlimits(NULL),
+                    new_process_group(false)
+#if defined(OS_LINUX)
+                  , clone_flags(0)
+#endif  // OS_LINUX
+#if defined(OS_CHROMEOS)
+                  , ctrl_terminal_fd(-1)
+#endif  // OS_CHROMEOS
+#if defined(OS_MACOSX)
+                  , synchronize(NULL)
+#endif  // defined(OS_MACOSX)
+#endif  // !defined(OS_WIN)
+      {}
+
+  // If true, wait for the process to complete.
+  bool wait;
+
+#if defined(OS_WIN)
+  bool start_hidden;
+
+  // If true, the new process inherits handles from the parent.
+  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;
+
+  // 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
+  // If non-NULL, set/unset environment variables.
+  // See documentation of AlterEnvironment().
+  // This pointer is owned by the caller and must live through the
+  // call to LaunchProcess().
+  const EnvironmentVector* 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::set<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.
+  int clone_flags;
+#endif  // defined(OS_LINUX)
+
+#if defined(OS_CHROMEOS)
+  // If non-negative, the specified file descriptor will be set as the launched
+  // process' controlling terminal.
+  int ctrl_terminal_fd;
+#endif  // defined(OS_CHROMEOS)
+
+#if defined(OS_MACOSX)
+  // When non-NULL, a new LaunchSynchronizationHandle will be created and
+  // stored in *synchronize whenever LaunchProcess returns true in the parent
+  // process. The child process will have been created (with fork) but will
+  // be waiting (before exec) for the parent to call LaunchSynchronize with
+  // this handle. Only when LaunchSynchronize is called will the child be
+  // permitted to continue execution and call exec. LaunchSynchronize
+  // destroys the handle created by LaunchProcess.
+  //
+  // When synchronize is non-NULL, the parent must call LaunchSynchronize
+  // whenever LaunchProcess returns true. No exceptions.
+  //
+  // Synchronization is useful when the parent process needs to guarantee that
+  // it can take some action (such as recording the newly-forked child's
+  // process ID) before the child does something (such as using its process ID
+  // to communicate with its parent).
+  //
+  // |synchronize| and |wait| must not both be set simultaneously.
+  LaunchSynchronizationHandle* synchronize;
+#endif  // defined(OS_MACOSX)
+
+#endif  // !defined(OS_WIN)
+};
+
+// Launch a process via the command line |cmdline|.
+// See the documentation of LaunchOptions for details on |options|.
+//
+// Returns true upon success.
+//
+// Upon success, if |process_handle| is non-NULL, it will be filled in with the
+// handle of the launched process.  NOTE: In this case, the caller is
+// responsible for closing the handle so that it doesn't leak!
+// Otherwise, the process handle will be implicitly closed.
+//
+// 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 bool LaunchProcess(const CommandLine& cmdline,
+                               const LaunchOptions& options,
+                               ProcessHandle* process_handle);
+
+#if defined(OS_WIN)
+
+enum IntegrityLevel {
+  INTEGRITY_UNKNOWN,
+  LOW_INTEGRITY,
+  MEDIUM_INTEGRITY,
+  HIGH_INTEGRITY,
+};
+// Determine the integrity level of the specified process. Returns false
+// if the system does not support integrity levels (pre-Vista) or in the case
+// of an underlying system failure.
+BASE_EXPORT bool GetProcessIntegrityLevel(ProcessHandle process,
+                                          IntegrityLevel* level);
+
+// 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 bool LaunchProcess(const string16& cmdline,
+                               const LaunchOptions& options,
+                               ProcessHandle* process_handle);
+
+#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 bool LaunchProcess(const std::vector<std::string>& argv,
+                               const LaunchOptions& options,
+                               ProcessHandle* process_handle);
+
+// AlterEnvironment 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.
+//
+// The returned array is allocated using new[] and must be freed by the caller.
+BASE_EXPORT char** AlterEnvironment(const EnvironmentVector& changes,
+                                    const char* const* const env);
+
+#if defined(OS_MACOSX)
+
+// After a successful call to LaunchProcess with LaunchOptions::synchronize
+// set, the parent process must call LaunchSynchronize to allow the child
+// process to proceed, and to destroy the LaunchSynchronizationHandle.
+BASE_EXPORT void LaunchSynchronize(LaunchSynchronizationHandle handle);
+
+#endif  // defined(OS_MACOSX)
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_WIN)
+// Set JOBOBJECT_EXTENDED_LIMIT_INFORMATION to JobObject |job_object|.
+// As its limit_info.BasicLimitInformation.LimitFlags has
+// JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE.
+// When the provide JobObject |job_object| is closed, the binded process will
+// be terminated.
+BASE_EXPORT bool SetJobObjectAsKillOnJobClose(HANDLE job_object);
+#endif  // defined(OS_WIN)
+
+// Executes the application specified by |cl| and wait for it to exit. Stores
+// the output (stdout) in |output|. Redirects stderr to /dev/null. Returns true
+// on success (application launched and exited cleanly, with exit code
+// indicating success).
+BASE_EXPORT bool GetAppOutput(const CommandLine& cl, std::string* output);
+
+#if defined(OS_POSIX)
+// A POSIX-specific version of GetAppOutput that takes an argv array
+// instead of a CommandLine.  Useful for situations where you need to
+// control the command line arguments directly.
+BASE_EXPORT bool GetAppOutput(const std::vector<std::string>& argv,
+                              std::string* output);
+
+// A restricted version of |GetAppOutput()| which (a) clears the environment,
+// and (b) stores at most |max_output| bytes; also, it doesn't search the path
+// for the command.
+BASE_EXPORT bool GetAppOutputRestricted(const CommandLine& cl,
+                                        std::string* output, size_t max_output);
+
+// A version of |GetAppOutput()| which also returns the exit code of the
+// executed command. Returns true if the application runs and exits cleanly. If
+// this is the case the exit code of the application is available in
+// |*exit_code|.
+BASE_EXPORT bool GetAppOutputWithExitCode(const CommandLine& cl,
+                                          std::string* output, int* exit_code);
+#endif  // defined(OS_POSIX)
+
+// 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() {}
+};
+
+// 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);
+
+// 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);
+
+// Attempts to kill the process identified by the given process
+// entry structure, giving it the specified exit code. If |wait| is true, wait
+// for the process to be actually terminated before returning.
+// Returns true if this is successful, false otherwise.
+BASE_EXPORT bool KillProcess(ProcessHandle process, int exit_code, bool wait);
+
+#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)
+
+#if defined(OS_WIN)
+BASE_EXPORT bool KillProcessById(ProcessId process_id, int exit_code,
+                                 bool wait);
+#endif  // defined(OS_WIN)
+
+// 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);
+
+// Waits for process to exit. On POSIX systems, if the process hasn't been
+// signaled then puts the exit code in |exit_code|; otherwise it's considered
+// a failure. On Windows |exit_code| is always filled. Returns true on success,
+// and closes |handle| in any case.
+BASE_EXPORT bool WaitForExitCode(ProcessHandle handle, int* exit_code);
+
+// Waits for process to exit. If it did exit within |timeout_milliseconds|,
+// then puts the exit code in |exit_code|, and returns true.
+// In POSIX systems, if the process has been signaled then |exit_code| is set
+// to -1. Returns false on failure (the caller is then responsible for closing
+// |handle|).
+// The caller is always responsible for closing the |handle|.
+BASE_EXPORT bool WaitForExitCodeWithTimeout(ProcessHandle handle,
+                                            int* exit_code,
+                                            base::TimeDelta timeout);
+
+// 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);
+
+// Wait for a single process to exit. Return true if it exited cleanly within
+// the given time limit. On Linux |handle| must be a child process, however
+// on Mac and Windows it can be any process.
+BASE_EXPORT bool WaitForSingleProcess(ProcessHandle handle,
+                                      base::TimeDelta wait);
+
+// 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 handle must have been opened with the PROCESS_TERMINATE
+// and SYNCHRONIZE permissions.
+//
+BASE_EXPORT void EnsureProcessTerminated(ProcessHandle process_handle);
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+// The nicer version of EnsureProcessTerminated() that is patient and will
+// wait for |process_handle| to finish and then reap it.
+BASE_EXPORT void EnsureProcessGetsReaped(ProcessHandle process_handle);
+#endif
+
+// 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);
+  virtual ~NamedProcessIterator();
+
+ protected:
+  virtual bool IncludeEntry() OVERRIDE;
+
+ private:
+  FilePath::StringType executable_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(NamedProcessIterator);
+};
+
+// 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 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;
+};
+
+// 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;
+};
+
+// Free memory (Megabytes marked as free) in the 2G process address space.
+// total : total amount in megabytes marked as free. Maximum value is 2048.
+// largest : size of the largest contiguous amount of memory found. It is
+//   always smaller or equal to FreeMBytes::total.
+// largest_ptr: starting address of the largest memory block.
+struct FreeMBytes {
+  size_t total;
+  size_t largest;
+  void* largest_ptr;
+};
+
+// Convert a POSIX timeval to microseconds.
+BASE_EXPORT int64 TimeValToMicroseconds(const struct timeval& tv);
+
+// Provides performance metrics for a specified process (CPU usage, memory and
+// IO counters). To use it, invoke CreateProcessMetrics() to get an instance
+// for a specific process, then access the information with the different get
+// methods.
+class BASE_EXPORT ProcessMetrics {
+ public:
+  ~ProcessMetrics();
+
+  // Creates a ProcessMetrics for the specified process.
+  // The caller owns the returned object.
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  static ProcessMetrics* CreateProcessMetrics(ProcessHandle process);
+#else
+  class PortProvider {
+   public:
+    virtual ~PortProvider() {}
+
+    // Should return the mach task for |process| if possible, or else
+    // |MACH_PORT_NULL|. Only processes that this returns tasks for will have
+    // metrics on OS X (except for the current process, which always gets
+    // metrics).
+    virtual mach_port_t TaskForPid(ProcessHandle process) const = 0;
+  };
+
+  // The port provider needs to outlive the ProcessMetrics object returned by
+  // this function. If NULL is passed as provider, the returned object
+  // only returns valid metrics if |process| is the current process.
+  static ProcessMetrics* CreateProcessMetrics(ProcessHandle process,
+                                              PortProvider* port_provider);
+#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
+
+  // Returns the current space allocated for the pagefile, in bytes (these pages
+  // may or may not be in memory).  On Linux, this returns the total virtual
+  // memory size.
+  size_t GetPagefileUsage() const;
+  // Returns the peak space allocated for the pagefile, in bytes.
+  size_t GetPeakPagefileUsage() const;
+  // Returns the current working set size, in bytes.  On Linux, this returns
+  // the resident set size.
+  size_t GetWorkingSetSize() const;
+  // Returns the peak working set size, in bytes.
+  size_t GetPeakWorkingSetSize() const;
+  // Returns private and sharedusage, in bytes. Private bytes is the amount of
+  // memory currently allocated to a process that cannot be shared. Returns
+  // false on platform specific error conditions.  Note: |private_bytes|
+  // returns 0 on unsupported OSes: prior to XP SP2.
+  bool GetMemoryBytes(size_t* private_bytes,
+                      size_t* shared_bytes);
+  // Fills a CommittedKBytes with both resident and paged
+  // memory usage as per definition of CommittedBytes.
+  void GetCommittedKBytes(CommittedKBytes* usage) const;
+  // Fills a WorkingSetKBytes containing resident private and shared memory
+  // usage in bytes, as per definition of WorkingSetBytes.
+  bool GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const;
+
+  // Computes the current process available memory for allocation.
+  // It does a linear scan of the address space querying each memory region
+  // for its free (unallocated) status. It is useful for estimating the memory
+  // load and fragmentation.
+  bool CalculateFreeMemory(FreeMBytes* free) const;
+
+  // Returns the CPU usage in percent since the last time this method 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();
+
+  // Retrieves accounting information for all I/O operations performed by the
+  // process.
+  // If IO information is retrieved successfully, the function returns true
+  // and fills in the IO_COUNTERS passed in. The function returns false
+  // otherwise.
+  bool GetIOCounters(IoCounters* io_counters) const;
+
+ private:
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  explicit ProcessMetrics(ProcessHandle process);
+#else
+  ProcessMetrics(ProcessHandle process, PortProvider* port_provider);
+#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
+
+  ProcessHandle process_;
+
+  int processor_count_;
+
+  // Used to store the previous times and CPU usage counts so we can
+  // compute the CPU usage between calls.
+  int64 last_time_;
+  int64 last_system_time_;
+
+#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_time_ we updated.
+  int last_cpu_;
+#endif  // defined(OS_POSIX)
+#endif  // !defined(OS_IOS)
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMetrics);
+};
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+// Data from /proc/meminfo about system-wide memory consumption.
+// Values are in KB.
+struct BASE_EXPORT SystemMemoryInfoKB {
+  SystemMemoryInfoKB();
+
+  int total;
+  int free;
+  int buffers;
+  int cached;
+  int active_anon;
+  int inactive_anon;
+  int active_file;
+  int inactive_file;
+  int shmem;
+
+  // Gem data will be -1 if not supported.
+  int gem_objects;
+  long long gem_size;
+};
+// Retrieves data from /proc/meminfo about system-wide memory consumption.
+// Fills in the provided |meminfo| structure. Returns true on success.
+// Exposed for memory debugging widget.
+BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo);
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+// Returns the memory committed by the system in KBytes.
+// Returns 0 if it can't compute the commit charge.
+BASE_EXPORT size_t GetSystemCommitCharge();
+
+// Enables low fragmentation heap (LFH) for every heaps of this process. This
+// won't have any effect on heaps created after this function call. It will not
+// modify data allocated in the heaps before calling this function. So it is
+// better to call this function early in initialization and again before
+// entering the main loop.
+// Note: Returns true on Windows 2000 without doing anything.
+BASE_EXPORT bool EnableLowFragmentationHeap();
+
+// Enables 'terminate on heap corruption' flag. Helps protect against heap
+// overflow. Has no effect if the OS doesn't provide the necessary facility.
+BASE_EXPORT void EnableTerminationOnHeapCorruption();
+
+// Turns on process termination if memory runs out.
+BASE_EXPORT void EnableTerminationOnOutOfMemory();
+
+// 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)
+
+#if defined(OS_MACOSX)
+// Very large images or svg canvases can cause huge mallocs.  Skia
+// does tricks on tcmalloc-based systems to allow malloc to fail with
+// a NULL rather than hit the oom crasher.  This replicates that for
+// OSX.
+//
+// IF YOU USE THIS WITHOUT CONSULTING YOUR FRIENDLY OSX DEVELOPER,
+// YOUR CODE IS LIKELY TO BE REVERTED.  THANK YOU.
+//
+// TODO(shess): Weird place to put it, but this is where the OOM
+// killer currently lives.
+BASE_EXPORT void* UncheckedMalloc(size_t size);
+#endif  // defined(OS_MACOSX)
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_UTIL_H_
diff --git a/base/process_util_freebsd.cc b/base/process_util_freebsd.cc
new file mode 100644
index 0000000..1157fb2
--- /dev/null
+++ b/base/process_util_freebsd.cc
@@ -0,0 +1,293 @@
+// Copyright (c) 2011 The Chromium Authors. All 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_util.h"
+
+#include <ctype.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/string_tokenizer.h"
+#include "base/string_util.h"
+#include "base/sys_info.h"
+
+namespace base {
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process };
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return info.ki_ppid;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  char pathname[PATH_MAX];
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, process };
+
+  length = sizeof(pathname);
+
+  if (sysctl(mib, arraysize(mib), pathname, &length, NULL, 0) < 0 ||
+      length == 0) {
+    return FilePath();
+  }
+
+  return FilePath(std::string(pathname));
+}
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : index_of_kinfo_proc_(),
+      filter_(filter) {
+
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid() };
+
+  bool done = false;
+  int try_num = 1;
+  const int max_tries = 10;
+
+  do {
+    size_t len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) <0 ){
+      LOG(ERROR) << "failed to get the size needed for the process list";
+      kinfo_procs_.resize(0);
+      done = true;
+    } else {
+      size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+      // Leave some spare room for process table growth (more could show up
+      // between when we check and now)
+      num_of_kinfo_proc += 16;
+      kinfo_procs_.resize(num_of_kinfo_proc);
+      len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+      if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) <0) {
+        // If we get a mem error, it just means we need a bigger buffer, so
+        // loop around again.  Anything else is a real error and give up.
+        if (errno != ENOMEM) {
+          LOG(ERROR) << "failed to get the process list";
+          kinfo_procs_.resize(0);
+          done = true;
+        }
+      } else {
+        // Got the list, just make sure we're sized exactly right
+        size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+        kinfo_procs_.resize(num_of_kinfo_proc);
+        done = true;
+      }
+    }
+  } while (!done && (try_num++ < max_tries));
+
+  if (!done) {
+    LOG(ERROR) << "failed to collect the process list in a few tries";
+    kinfo_procs_.resize(0);
+  }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  std::string data;
+
+  for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++ index_of_kinfo_proc_) {
+    size_t length;
+    struct kinfo_proc kinfo = kinfo_procs_[index_of_kinfo_proc_];
+    int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.ki_pid };
+
+    if ((kinfo.ki_pid > 0) && (kinfo.ki_stat == SZOMB))
+      continue;
+
+    length = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) {
+      LOG(ERROR) << "failed to figure out the buffer size for a command line";
+      continue;
+    }
+
+    data.resize(length);
+
+    if (sysctl(mib, arraysize(mib), &data[0], &length, NULL, 0) < 0) {
+      LOG(ERROR) << "failed to fetch a commandline";
+      continue;
+    }
+
+    std::string delimiters;
+    delimiters.push_back('\0');
+    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+    size_t exec_name_end = data.find('\0');
+    if (exec_name_end == std::string::npos) {
+      LOG(ERROR) << "command line data didn't match expected format";
+      continue;
+    }
+
+    entry_.pid_ = kinfo.ki_pid;
+    entry_.ppid_ = kinfo.ki_ppid;
+    entry_.gid_ = kinfo.ki_pgid;
+
+    size_t last_slash = data.rfind('/', exec_name_end);
+    if (last_slash == std::string::npos) {
+      entry_.exe_file_.assign(data, 0, exec_name_end);
+    } else {
+      entry_.exe_file_.assign(data, last_slash + 1,
+                              exec_name_end - last_slash - 1);
+    }
+
+    // Start w/ the next entry next time through
+    ++index_of_kinfo_proc_;
+
+    return true;
+  }
+  return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  if(executable_name_ != entry().exe_file())
+    return false;
+
+  return ProcessIterator::IncludeEntry();
+}
+
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      last_time_(0),
+      last_system_time_(0),
+      last_cpu_(0) {
+  processor_count_ = base::SysInfo::NumberOfProcessors();
+}
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  struct kinfo_proc info;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ };
+  size_t length = sizeof(info);
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return info.ki_size;
+}
+
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  return 0;
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  struct kinfo_proc info;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ };
+  size_t length = sizeof(info);
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return info.ki_rssize * getpagesize();
+}
+
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  return 0;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  WorkingSetKBytes ws_usage;
+  if (!GetWorkingSetKBytes(&ws_usage))
+    return false;
+
+  if (private_bytes)
+    *private_bytes = ws_usage.priv << 10;
+
+  if (shared_bytes)
+    *shared_bytes = ws_usage.shared * 1024;
+
+  return true;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+// TODO(bapt) be sure we can't be precise
+  size_t priv = GetWorkingSetSize();
+  if (!priv)
+    return false;
+  ws_usage->priv = priv / 1024;
+  ws_usage->shareable = 0;
+  ws_usage->shared = 0;
+
+  return true;
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return false;
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  struct kinfo_proc info;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ };
+  size_t length = sizeof(info);
+
+  struct timeval now;
+  int retval = gettimeofday(&now, NULL);
+  if (retval)
+    return 0;
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return (info.ki_pctcpu / FSCALE) * 100.0;
+}
+
+size_t GetSystemCommitCharge() {
+  int mib[2], pagesize;
+  unsigned long mem_total, mem_free, mem_inactive;
+  size_t length = sizeof(mem_total);
+
+  if (sysctl(mib, arraysize(mib), &mem_total, &length, NULL, 0) < 0)
+    return 0;
+
+  length = sizeof(mem_free);
+  if (sysctlbyname("vm.stats.vm.v_free_count", &mem_free, &length, NULL, 0) < 0)
+    return 0;
+
+  length = sizeof(mem_inactive);
+  if (sysctlbyname("vm.stats.vm.v_inactive_count", &mem_inactive, &length,
+      NULL, 0) < 0) {
+    return 0;
+  }
+
+  pagesize = getpagesize();
+
+  return mem_total - (mem_free*pagesize) - (mem_inactive*pagesize);
+}
+
+void EnableTerminationOnOutOfMemory() {
+  DLOG(WARNING) << "Not feasible.";
+}
+
+void EnableTerminationOnHeapCorruption() {
+  // Nothing to do.
+}
+
+bool AdjustOOMScore(ProcessId process, int score) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace base
diff --git a/base/process_util_ios.mm b/base/process_util_ios.mm
new file mode 100644
index 0000000..161d396
--- /dev/null
+++ b/base/process_util_ios.mm
@@ -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/process_util.h"
+
+#import <Foundation/Foundation.h>
+#include <mach/task.h>
+#include <stdio.h>
+
+#include "base/logging.h"
+
+// This is just enough of a shim to let the support needed by test_support
+// link.  In general, process_util isn't valid on iOS.
+
+namespace base {
+
+namespace {
+
+bool GetTaskInfo(task_basic_info_64* task_info_data) {
+  mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
+  kern_return_t kr = task_info(mach_task_self(),
+                               TASK_BASIC_INFO_64,
+                               reinterpret_cast<task_info_t>(task_info_data),
+                               &count);
+  return kr == KERN_SUCCESS;
+}
+
+}  // namespace
+
+ProcessId GetCurrentProcId() {
+  return getpid();
+}
+
+ProcessHandle GetCurrentProcessHandle() {
+  return GetCurrentProcId();
+}
+
+void EnableTerminationOnHeapCorruption() {
+  // On iOS, there nothing to do AFAIK.
+}
+
+void EnableTerminationOnOutOfMemory() {
+  // iOS provides this for free!
+}
+
+void RaiseProcessToHighPriority() {
+  // Impossible on iOS. Do nothing.
+}
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process) {}
+
+ProcessMetrics::~ProcessMetrics() {}
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(&task_info_data))
+    return 0;
+  return task_info_data.resident_size;
+}
+
+}  // namespace base
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
new file mode 100644
index 0000000..4552574
--- /dev/null
+++ b/base/process_util_linux.cc
@@ -0,0 +1,867 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_util.h"
+
+#include <dirent.h>
+#include <malloc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/string_tokenizer.h"
+#include "base/string_util.h"
+#include "base/sys_info.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace {
+
+enum ParsingState {
+  KEY_NAME,
+  KEY_VALUE
+};
+
+const char kProcDir[] = "/proc";
+const char kStatFile[] = "stat";
+
+// Returns a FilePath to "/proc/pid".
+FilePath GetProcPidDir(pid_t pid) {
+  return FilePath(kProcDir).Append(base::IntToString(pid));
+}
+
+// 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_VSIZE          = 22,  // Virtual memory size in bytes.
+  VM_RSS            = 23,  // Resident Set Size in pages.
+};
+
+// 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) {
+  buffer->clear();
+  // Synchronously reading files in /proc is safe.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  FilePath stat_file = GetProcPidDir(pid).Append(kStatFile);
+  if (!file_util::ReadFileToString(stat_file, buffer)) {
+    DLOG(WARNING) << "Failed to get process stats.";
+    return false;
+  }
+  return !buffer->empty();
+}
+
+// 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) {
+  // |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;
+  base::SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats);
+  for (size_t i = 0; i < other_stats.size(); ++i)
+    proc_stats->push_back(other_stats[i]);
+  return true;
+}
+
+// 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.
+int GetProcStatsFieldAsInt(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());
+
+  int value;
+  return base::StringToInt(proc_stats[field_num], &value) ? value : 0;
+}
+
+// Same as GetProcStatsFieldAsInt(), but for size_t values.
+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 base::StringToSizeT(proc_stats[field_num], &value) ? value : 0;
+}
+
+// Convenience wrapper around GetProcStatsFieldAsInt(), ParseProcStats() and
+// ReadProcStats(). See GetProcStatsFieldAsInt() for details.
+int ReadProcStatsAndGetFieldAsInt(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 GetProcStatsFieldAsInt(proc_stats, field_num);
+}
+
+// Same as ReadProcStatsAndGetFieldAsInt() but for size_t values.
+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);
+}
+
+// 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,
+    ProcStatsFields field_num) {
+  if (field_num < VM_COMM || field_num > VM_STATE) {
+    NOTREACHED();
+    return "";
+  }
+
+  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.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  FilePath cmd_line_file = GetProcPidDir(pid).Append("cmdline");
+  std::string cmd_line;
+  if (!file_util::ReadFileToString(cmd_line_file, &cmd_line))
+    return false;
+  std::string delimiters;
+  delimiters.push_back('\0');
+  Tokenize(cmd_line, delimiters, proc_cmd_line_args);
+  return true;
+}
+
+// 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) {
+  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 (!base::StringToInt(pid_string, &pid)) {
+    NOTREACHED();
+    return 0;
+  }
+  return pid;
+}
+
+// Get the total CPU of a single process.  Return value is number of jiffies
+// on success or -1 on error.
+int GetProcessCPU(pid_t pid) {
+  // Use /proc/<pid>/task to find all threads and parse their /stat file.
+  FilePath task_path = 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 = ProcDirSlotToPid(ent->d_name);
+    if (!tid)
+      continue;
+
+    // Synchronously reading files in /proc is safe.
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+    std::string stat;
+    FilePath stat_path = task_path.Append(ent->d_name).Append(kStatFile);
+    if (file_util::ReadFileToString(stat_path, &stat)) {
+      int cpu = base::ParseProcStatCPU(stat);
+      if (cpu > 0)
+        total_cpu += cpu;
+    }
+  }
+  closedir(dir);
+
+  return total_cpu;
+}
+
+// Read /proc/<pid>/status and returns 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) {
+  FilePath stat_file = GetProcPidDir(pid).Append("status");
+  std::string status;
+  {
+    // Synchronously reading files in /proc is safe.
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    if (!file_util::ReadFileToString(stat_file, &status))
+      return 0;
+  }
+
+  StringTokenizer tokenizer(status, ":\n");
+  ParsingState state = KEY_NAME;
+  base::StringPiece last_key_name;
+  while (tokenizer.GetNext()) {
+    switch (state) {
+      case KEY_NAME:
+        last_key_name = tokenizer.token_piece();
+        state = KEY_VALUE;
+        break;
+      case KEY_VALUE:
+        DCHECK(!last_key_name.empty());
+        if (last_key_name == field) {
+          std::string value_str;
+          tokenizer.token_piece().CopyToString(&value_str);
+          std::string value_str_trimmed;
+          TrimWhitespaceASCII(value_str, TRIM_ALL, &value_str_trimmed);
+          std::vector<std::string> split_value_str;
+          base::SplitString(value_str_trimmed, ' ', &split_value_str);
+          if (split_value_str.size() != 2 || split_value_str[1] != "kB") {
+            NOTREACHED();
+            return 0;
+          }
+          size_t value;
+          if (!base::StringToSizeT(split_value_str[0], &value)) {
+            NOTREACHED();
+            return 0;
+          }
+          return value;
+        }
+        state = KEY_NAME;
+        break;
+    }
+  }
+  NOTREACHED();
+  return 0;
+}
+
+}  // namespace
+
+namespace base {
+
+#if defined(USE_LINUX_BREAKPAD)
+size_t g_oom_size = 0U;
+#endif
+
+const char kProcSelfExe[] = "/proc/self/exe";
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  ProcessId pid = ReadProcStatsAndGetFieldAsInt(process, VM_PPID);
+  if (pid)
+    return pid;
+  return -1;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  FilePath stat_file = GetProcPidDir(process).Append("exe");
+  FilePath exe_name;
+  if (!file_util::ReadSymbolicLink(stat_file, &exe_name)) {
+    // No such process.  Happens frequently in e.g. TerminateAllChromeProcesses
+    return FilePath();
+  }
+  return exe_name;
+}
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : filter_(filter) {
+  procfs_dir_ = opendir(kProcDir);
+}
+
+ProcessIterator::~ProcessIterator() {
+  if (procfs_dir_) {
+    closedir(procfs_dir_);
+    procfs_dir_ = NULL;
+  }
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  // TODO(port): skip processes owned by different UID
+
+  pid_t pid = kNullProcessId;
+  std::vector<std::string> cmd_line_args;
+  std::string stats_data;
+  std::vector<std::string> proc_stats;
+
+  // Arbitrarily guess that there will never be more than 200 non-process
+  // files in /proc.  Hardy has 53 and Lucid has 61.
+  int skipped = 0;
+  const int kSkipLimit = 200;
+  while (skipped < kSkipLimit) {
+    dirent* slot = readdir(procfs_dir_);
+    // all done looking through /proc?
+    if (!slot)
+      return false;
+
+    // If not a process, keep looking for one.
+    pid = ProcDirSlotToPid(slot->d_name);
+    if (!pid) {
+      skipped++;
+      continue;
+    }
+
+    if (!GetProcCmdline(pid, &cmd_line_args))
+      continue;
+
+    if (!ReadProcStats(pid, &stats_data))
+      continue;
+    if (!ParseProcStats(stats_data, &proc_stats))
+      continue;
+
+    std::string runstate = GetProcStatsFieldAsString(proc_stats, 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_ = GetProcStatsFieldAsInt(proc_stats, VM_PPID);
+  entry_.gid_ = GetProcStatsFieldAsInt(proc_stats, VM_PGRP);
+  entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end());
+
+  // TODO(port): read pid's commandline's $0, like killall does.  Using the
+  // short name between openparen and closeparen won't work for long names!
+  entry_.exe_file_ = GetProcStatsFieldAsString(proc_stats, VM_COMM);
+  return true;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  if (executable_name_ != entry().exe_file())
+    return false;
+  return ProcessIterator::IncludeEntry();
+}
+
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+// On linux, we return vsize.
+size_t ProcessMetrics::GetPagefileUsage() const {
+  return ReadProcStatsAndGetFieldAsSizeT(process_, 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 ReadProcStatsAndGetFieldAsSizeT(process_, 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;
+}
+
+// Private and Shared working set sizes are obtained from /proc/<pid>/statm.
+bool ProcessMetrics::GetWorkingSetKBytes(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 = GetProcPidDir(process_).Append("statm");
+    // Synchronously reading files in /proc is safe.
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    bool ret = file_util::ReadFileToString(statm_file, &statm);
+    if (!ret || statm.length() == 0)
+      return false;
+  }
+
+  std::vector<std::string> statm_vec;
+  base::SplitString(statm, ' ', &statm_vec);
+  if (statm_vec.size() != 7)
+    return false;  // Not the format we expect.
+
+  int statm_rss, statm_shared;
+  base::StringToInt(statm_vec[1], &statm_rss);
+  base::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;
+
+  return true;
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  // 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);
+
+  struct timeval now;
+  int retval = gettimeofday(&now, NULL);
+  if (retval)
+    return 0;
+  int64 time = TimeValToMicroseconds(now);
+
+  if (last_time_ == 0) {
+    // First call, just set the last values.
+    last_time_ = time;
+    last_cpu_ = GetProcessCPU(process_);
+    return 0;
+  }
+
+  int64 time_delta = time - last_time_;
+  DCHECK_NE(time_delta, 0);
+  if (time_delta == 0)
+    return 0;
+
+  int cpu = GetProcessCPU(process_);
+
+  // We have the number of jiffies in the time period.  Convert to percentage.
+  // Note this means we will go *over* 100 in the case where multiple threads
+  // are together adding to more than one CPU's worth.
+  int percentage = 100 * (cpu - last_cpu_) /
+      (kHertz * TimeDelta::FromMicroseconds(time_delta).InSecondsF());
+
+  last_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 is safe.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  std::string proc_io_contents;
+  FilePath io_file = GetProcPidDir(process_).Append("io");
+  if (!file_util::ReadFileToString(io_file, &proc_io_contents))
+    return false;
+
+  (*io_counters).OtherOperationCount = 0;
+  (*io_counters).OtherTransferCount = 0;
+
+  StringTokenizer tokenizer(proc_io_contents, ": \n");
+  ParsingState state = KEY_NAME;
+  StringPiece last_key_name;
+  while (tokenizer.GetNext()) {
+    switch (state) {
+      case KEY_NAME:
+        last_key_name = tokenizer.token_piece();
+        state = KEY_VALUE;
+        break;
+      case KEY_VALUE:
+        DCHECK(!last_key_name.empty());
+        if (last_key_name == "syscr") {
+          base::StringToInt64(tokenizer.token_piece(),
+              reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount));
+        } else if (last_key_name == "syscw") {
+          base::StringToInt64(tokenizer.token_piece(),
+              reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount));
+        } else if (last_key_name == "rchar") {
+          base::StringToInt64(tokenizer.token_piece(),
+              reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount));
+        } else if (last_key_name == "wchar") {
+          base::StringToInt64(tokenizer.token_piece(),
+              reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount));
+        }
+        state = KEY_NAME;
+        break;
+    }
+  }
+  return true;
+}
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      last_time_(0),
+      last_system_time_(0),
+      last_cpu_(0) {
+  processor_count_ = base::SysInfo::NumberOfProcessors();
+}
+
+
+// Exposed for testing.
+int ParseProcStatCPU(const std::string& input) {
+  std::vector<std::string> proc_stats;
+  if (!ParseProcStats(input, &proc_stats))
+    return -1;
+
+  if (proc_stats.size() <= VM_STIME)
+    return -1;
+  int utime = GetProcStatsFieldAsInt(proc_stats, VM_UTIME);
+  int stime = GetProcStatsFieldAsInt(proc_stats, VM_STIME);
+  return utime + stime;
+}
+
+namespace {
+
+// The format of /proc/meminfo is:
+//
+// MemTotal:      8235324 kB
+// MemFree:       1628304 kB
+// Buffers:        429596 kB
+// Cached:        4728232 kB
+// ...
+const size_t kMemTotalIndex = 1;
+const size_t kMemFreeIndex = 4;
+const size_t kMemBuffersIndex = 7;
+const size_t kMemCachedIndex = 10;
+const size_t kMemActiveAnonIndex = 22;
+const size_t kMemInactiveAnonIndex = 25;
+const size_t kMemActiveFileIndex = 28;
+const size_t kMemInactiveFileIndex = 31;
+
+}  // namespace
+
+SystemMemoryInfoKB::SystemMemoryInfoKB()
+    : total(0),
+      free(0),
+      buffers(0),
+      cached(0),
+      active_anon(0),
+      inactive_anon(0),
+      active_file(0),
+      inactive_file(0),
+      shmem(0) {
+}
+
+bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
+  // Synchronously reading files in /proc is safe.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  // Used memory is: total - free - buffers - caches
+  FilePath meminfo_file("/proc/meminfo");
+  std::string meminfo_data;
+  if (!file_util::ReadFileToString(meminfo_file, &meminfo_data)) {
+    DLOG(WARNING) << "Failed to open " << meminfo_file.value();
+    return false;
+  }
+  std::vector<std::string> meminfo_fields;
+  SplitStringAlongWhitespace(meminfo_data, &meminfo_fields);
+
+  if (meminfo_fields.size() < kMemCachedIndex) {
+    DLOG(WARNING) << "Failed to parse " << meminfo_file.value()
+                  << ".  Only found " << meminfo_fields.size() << " fields.";
+    return false;
+  }
+
+  DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:");
+  DCHECK_EQ(meminfo_fields[kMemFreeIndex-1], "MemFree:");
+  DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:");
+  DCHECK_EQ(meminfo_fields[kMemCachedIndex-1], "Cached:");
+  DCHECK_EQ(meminfo_fields[kMemActiveAnonIndex-1], "Active(anon):");
+  DCHECK_EQ(meminfo_fields[kMemInactiveAnonIndex-1], "Inactive(anon):");
+  DCHECK_EQ(meminfo_fields[kMemActiveFileIndex-1], "Active(file):");
+  DCHECK_EQ(meminfo_fields[kMemInactiveFileIndex-1], "Inactive(file):");
+
+  base::StringToInt(meminfo_fields[kMemTotalIndex], &meminfo->total);
+  base::StringToInt(meminfo_fields[kMemFreeIndex], &meminfo->free);
+  base::StringToInt(meminfo_fields[kMemBuffersIndex], &meminfo->buffers);
+  base::StringToInt(meminfo_fields[kMemCachedIndex], &meminfo->cached);
+  base::StringToInt(meminfo_fields[kMemActiveAnonIndex], &meminfo->active_anon);
+  base::StringToInt(meminfo_fields[kMemInactiveAnonIndex],
+                    &meminfo->inactive_anon);
+  base::StringToInt(meminfo_fields[kMemActiveFileIndex], &meminfo->active_file);
+  base::StringToInt(meminfo_fields[kMemInactiveFileIndex],
+                    &meminfo->inactive_file);
+#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.  Unfortunately, the
+  // meminfo format varies on different hardware so we have to search for the
+  // string.  It always appears after "Cached:".
+  for (size_t i = kMemCachedIndex+2; i < meminfo_fields.size(); i += 3) {
+    if (meminfo_fields[i] == "Shmem:") {
+      base::StringToInt(meminfo_fields[i+1], &meminfo->shmem);
+      break;
+    }
+  }
+#endif
+
+  // Check for gem data and report if present.
+  FilePath geminfo_file("/sys/kernel/debug/dri/0/i915_gem_objects");
+  std::string geminfo_data;
+  meminfo->gem_objects = -1;
+  meminfo->gem_size = -1;
+  if (file_util::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;
+    }
+  }
+
+  return true;
+}
+
+size_t GetSystemCommitCharge() {
+  SystemMemoryInfoKB meminfo;
+  if (!GetSystemMemoryInfo(&meminfo))
+    return 0;
+  return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached;
+}
+
+namespace {
+
+void OnNoMemorySize(size_t size) {
+#if defined(USE_LINUX_BREAKPAD)
+  g_oom_size = size;
+#endif
+
+  if (size != 0)
+    LOG(FATAL) << "Out of memory, size = " << size;
+  LOG(FATAL) << "Out of memory.";
+}
+
+void OnNoMemory() {
+  OnNoMemorySize(0);
+}
+
+}  // namespace
+
+extern "C" {
+#if !defined(USE_TCMALLOC) && !defined(ADDRESS_SANITIZER) && \
+    !defined(OS_ANDROID) && !defined(THREAD_SANITIZER)
+
+extern "C" {
+void* __libc_malloc(size_t size);
+void* __libc_realloc(void* ptr, size_t size);
+void* __libc_calloc(size_t nmemb, size_t size);
+void* __libc_valloc(size_t size);
+void* __libc_pvalloc(size_t size);
+void* __libc_memalign(size_t alignment, size_t size);
+}  // extern "C"
+
+// Overriding the system memory allocation functions:
+//
+// For security reasons, we want malloc failures to be fatal. Too much code
+// doesn't check for a NULL return value from malloc and unconditionally uses
+// the resulting pointer. If the first offset that they try to access is
+// attacker controlled, then the attacker can direct the code to access any
+// part of memory.
+//
+// Thus, we define all the standard malloc functions here and mark them as
+// visibility 'default'. This means that they replace the malloc functions for
+// all Chromium code and also for all code in shared libraries. There are tests
+// for this in process_util_unittest.cc.
+//
+// If we are using tcmalloc, then the problem is moot since tcmalloc handles
+// this for us. Thus this code is in a !defined(USE_TCMALLOC) block.
+//
+// If we are testing the binary with AddressSanitizer, we should not
+// redefine malloc and let AddressSanitizer do it instead.
+//
+// We call the real libc functions in this code by using __libc_malloc etc.
+// Previously we tried using dlsym(RTLD_NEXT, ...) but that failed depending on
+// the link order. Since ld.so needs calloc during symbol resolution, it
+// defines its own versions of several of these functions in dl-minimal.c.
+// Depending on the runtime library order, dlsym ended up giving us those
+// functions and bad things happened. See crbug.com/31809
+//
+// This means that any code which calls __libc_* gets the raw libc versions of
+// these functions.
+
+#define DIE_ON_OOM_1(function_name) \
+  void* function_name(size_t) __attribute__ ((visibility("default"))); \
+  \
+  void* function_name(size_t size) { \
+    void* ret = __libc_##function_name(size); \
+    if (ret == NULL && size != 0) \
+      OnNoMemorySize(size); \
+    return ret; \
+  }
+
+#define DIE_ON_OOM_2(function_name, arg1_type) \
+  void* function_name(arg1_type, size_t) \
+      __attribute__ ((visibility("default"))); \
+  \
+  void* function_name(arg1_type arg1, size_t size) { \
+    void* ret = __libc_##function_name(arg1, size); \
+    if (ret == NULL && size != 0) \
+      OnNoMemorySize(size); \
+    return ret; \
+  }
+
+DIE_ON_OOM_1(malloc)
+DIE_ON_OOM_1(valloc)
+DIE_ON_OOM_1(pvalloc)
+
+DIE_ON_OOM_2(calloc, size_t)
+DIE_ON_OOM_2(realloc, void*)
+DIE_ON_OOM_2(memalign, size_t)
+
+// posix_memalign has a unique signature and doesn't have a __libc_ variant.
+int posix_memalign(void** ptr, size_t alignment, size_t size)
+    __attribute__ ((visibility("default")));
+
+int posix_memalign(void** ptr, size_t alignment, size_t size) {
+  // This will use the safe version of memalign, above.
+  *ptr = memalign(alignment, size);
+  return 0;
+}
+
+#endif  // !defined(USE_TCMALLOC)
+}  // extern C
+
+void EnableTerminationOnHeapCorruption() {
+  // On Linux, there nothing to do AFAIK.
+}
+
+void EnableTerminationOnOutOfMemory() {
+#if defined(OS_ANDROID)
+  // Android doesn't support setting a new handler.
+  DLOG(WARNING) << "Not feasible.";
+#else
+  // Set the new-out of memory handler.
+  std::set_new_handler(&OnNoMemory);
+  // If we're using glibc's allocator, the above functions will override
+  // malloc and friends and make them die on out of memory.
+#endif
+}
+
+// NOTE: This is not the only version of this function in the source:
+// the setuid sandbox (in process_util_linux.c, in the sandbox source)
+// also has its own C version.
+bool AdjustOOMScore(ProcessId process, int score) {
+  if (score < 0 || score > kMaxOomScore)
+    return false;
+
+  FilePath oom_path(GetProcPidDir(process));
+
+  // Attempt to write the newer oom_score_adj file first.
+  FilePath oom_file = oom_path.AppendASCII("oom_score_adj");
+  if (file_util::PathExists(oom_file)) {
+    std::string score_str = base::IntToString(score);
+    DVLOG(1) << "Adjusting oom_score_adj of " << process << " to "
+             << score_str;
+    int score_len = static_cast<int>(score_str.length());
+    return (score_len == file_util::WriteFile(oom_file,
+                                              score_str.c_str(),
+                                              score_len));
+  }
+
+  // If the oom_score_adj file doesn't exist, then we write the old
+  // style file and translate the oom_adj score to the range 0-15.
+  oom_file = oom_path.AppendASCII("oom_adj");
+  if (file_util::PathExists(oom_file)) {
+    // Max score for the old oom_adj range.  Used for conversion of new
+    // values to old values.
+    const int kMaxOldOomScore = 15;
+
+    int converted_score = score * kMaxOldOomScore / kMaxOomScore;
+    std::string score_str = base::IntToString(converted_score);
+    DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str;
+    int score_len = static_cast<int>(score_str.length());
+    return (score_len == file_util::WriteFile(oom_file,
+                                              score_str.c_str(),
+                                              score_len));
+  }
+
+  return false;
+}
+
+}  // namespace base
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
new file mode 100644
index 0000000..1fa3dbb
--- /dev/null
+++ b/base/process_util_mac.mm
@@ -0,0 +1,1247 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_util.h"
+
+#import <Cocoa/Cocoa.h>
+#include <crt_externs.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <mach/mach.h>
+#include <mach/mach_init.h>
+#include <mach/mach_vm.h>
+#include <mach/shared_region.h>
+#include <mach/task.h>
+#include <mach-o/nlist.h>
+#include <malloc/malloc.h>
+#import <objc/runtime.h>
+#include <signal.h>
+#include <spawn.h>
+#include <sys/event.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <new>
+#include <string>
+
+#include "base/debug/debugger.h"
+#include "base/eintr_wrapper.h"
+#include "base/file_util.h"
+#include "base/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/string_util.h"
+#include "base/sys_info.h"
+#include "base/threading/thread_local.h"
+#include "third_party/apple_apsl/CFBase.h"
+#include "third_party/apple_apsl/malloc.h"
+#include "third_party/mach_override/mach_override.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);
+}
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : index_of_kinfo_proc_(0),
+      filter_(filter) {
+  // Get a snapshot of all of my processes (yes, as we loop it can go stale, but
+  // but trying to find where we were in a constantly changing list is basically
+  // impossible.
+
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, geteuid() };
+
+  // Since more processes could start between when we get the size and when
+  // we get the list, we do a loop to keep trying until we get it.
+  bool done = false;
+  int try_num = 1;
+  const int max_tries = 10;
+  do {
+    // Get the size of the buffer
+    size_t len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+      DLOG(ERROR) << "failed to get the size needed for the process list";
+      kinfo_procs_.resize(0);
+      done = true;
+    } else {
+      size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+      // Leave some spare room for process table growth (more could show up
+      // between when we check and now)
+      num_of_kinfo_proc += 16;
+      kinfo_procs_.resize(num_of_kinfo_proc);
+      len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+      // Load the list of processes
+      if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
+        // If we get a mem error, it just means we need a bigger buffer, so
+        // loop around again.  Anything else is a real error and give up.
+        if (errno != ENOMEM) {
+          DLOG(ERROR) << "failed to get the process list";
+          kinfo_procs_.resize(0);
+          done = true;
+        }
+      } else {
+        // Got the list, just make sure we're sized exactly right
+        size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+        kinfo_procs_.resize(num_of_kinfo_proc);
+        done = true;
+      }
+    }
+  } while (!done && (try_num++ < max_tries));
+
+  if (!done) {
+    DLOG(ERROR) << "failed to collect the process list in a few tries";
+    kinfo_procs_.resize(0);
+  }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  std::string data;
+  for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+    kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
+
+    // Skip processes just awaiting collection
+    if ((kinfo.kp_proc.p_pid > 0) && (kinfo.kp_proc.p_stat == SZOMB))
+      continue;
+
+    int mib[] = { CTL_KERN, KERN_PROCARGS, kinfo.kp_proc.p_pid };
+
+    // Find out what size buffer we need.
+    size_t data_len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to figure out the buffer size for a commandline";
+      continue;
+    }
+
+    data.resize(data_len);
+    if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to fetch a commandline";
+      continue;
+    }
+
+    // |data| contains all the command line parameters of the process, separated
+    // by blocks of one or more null characters. We tokenize |data| into a
+    // vector of strings using '\0' as a delimiter and populate
+    // |entry_.cmd_line_args_|.
+    std::string delimiters;
+    delimiters.push_back('\0');
+    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+    // |data| starts with the full executable path followed by a null character.
+    // We search for the first instance of '\0' and extract everything before it
+    // to populate |entry_.exe_file_|.
+    size_t exec_name_end = data.find('\0');
+    if (exec_name_end == std::string::npos) {
+      DLOG(ERROR) << "command line data didn't match expected format";
+      continue;
+    }
+
+    entry_.pid_ = kinfo.kp_proc.p_pid;
+    entry_.ppid_ = kinfo.kp_eproc.e_ppid;
+    entry_.gid_ = kinfo.kp_eproc.e_pgid;
+    size_t last_slash = data.rfind('/', exec_name_end);
+    if (last_slash == std::string::npos)
+      entry_.exe_file_.assign(data, 0, exec_name_end);
+    else
+      entry_.exe_file_.assign(data, last_slash + 1,
+                              exec_name_end - last_slash - 1);
+    // Start w/ the next entry next time through
+    ++index_of_kinfo_proc_;
+    // Done
+    return true;
+  }
+  return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  return (executable_name_ == entry().exe_file() &&
+          ProcessIterator::IncludeEntry());
+}
+
+
+// ------------------------------------------------------------------------
+// NOTE: about ProcessMetrics
+//
+// 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.
+//
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process,
+                               ProcessMetrics::PortProvider* port_provider)
+    : process_(process),
+      last_time_(0),
+      last_system_time_(0),
+      port_provider_(port_provider) {
+  processor_count_ = SysInfo::NumberOfProcessors();
+}
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(
+    ProcessHandle process,
+    ProcessMetrics::PortProvider* port_provider) {
+  return new ProcessMetrics(process, port_provider);
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return false;
+}
+
+static 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;
+}
+
+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;
+}
+
+static 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;
+}
+
+static 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;
+}
+
+// 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) {
+  kern_return_t kr;
+  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;
+    kr = mach_vm_region(task,
+                        &address,
+                        &size,
+                        VM_REGION_TOP_INFO,
+                        (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) {
+      DLOG(ERROR) << "Calling mach_vm_region failed with error: "
+                 << mach_error_string(kr);
+      return false;
+    }
+
+    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;
+    }
+  }
+
+  vm_size_t page_size;
+  kr = host_page_size(task, &page_size);
+  if (kr != KERN_SUCCESS) {
+    DLOG(ERROR) << "Failed to fetch host page size, error: "
+               << mach_error_string(kr);
+    return false;
+  }
+
+  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 {
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+  size_t priv = GetWorkingSetSize();
+  if (!priv)
+    return false;
+  ws_usage->priv = priv / 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;
+
+  kern_return_t kr;
+
+  // 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;
+  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);
+
+  struct timeval now;
+  int retval = gettimeofday(&now, NULL);
+  if (retval)
+    return 0;
+
+  int64 time = TimeValToMicroseconds(now);
+  int64 task_time = TimeValToMicroseconds(task_timeval);
+
+  if ((last_system_time_ == 0) || (last_time_ == 0)) {
+    // First call, just set the last values.
+    last_system_time_ = task_time;
+    last_time_ = time;
+    return 0;
+  }
+
+  int64 system_time_delta = task_time - last_system_time_;
+  int64 time_delta = time - last_time_;
+  DCHECK_NE(0U, time_delta);
+  if (time_delta == 0)
+    return 0;
+
+  // We add time_delta / 2 so the result is rounded.
+  double cpu = static_cast<double>((system_time_delta * 100.0) / time_delta);
+
+  last_system_time_ = task_time;
+  last_time_ = time;
+
+  return cpu;
+}
+
+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::ScopedMachPort host(mach_host_self());
+  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+  vm_statistics_data_t data;
+  kern_return_t kr = host_statistics(host, HOST_VM_INFO,
+                                     reinterpret_cast<host_info_t>(&data),
+                                     &count);
+  if (kr) {
+    DLOG(WARNING) << "Failed to fetch host statistics.";
+    return 0;
+  }
+
+  vm_size_t page_size;
+  kr = host_page_size(host, &page_size);
+  if (kr) {
+    DLOG(ERROR) << "Failed to fetch host page size.";
+    return 0;
+  }
+
+  return (data.active_count * page_size) / 1024;
+}
+
+namespace {
+
+// Finds the library path for malloc() and thus the libC part of libSystem,
+// which in Lion is in a separate image.
+const char* LookUpLibCPath() {
+  const void* addr = reinterpret_cast<void*>(&malloc);
+
+  Dl_info info;
+  if (dladdr(addr, &info))
+    return info.dli_fname;
+
+  DLOG(WARNING) << "Could not find image path for malloc()";
+  return NULL;
+}
+
+typedef void(*malloc_error_break_t)(void);
+malloc_error_break_t g_original_malloc_error_break = NULL;
+
+// Returns the function pointer for malloc_error_break. This symbol is declared
+// as __private_extern__ and cannot be dlsym()ed. Instead, use nlist() to
+// get it.
+malloc_error_break_t LookUpMallocErrorBreak() {
+#if ARCH_CPU_32_BITS
+  const char* lib_c_path = LookUpLibCPath();
+  if (!lib_c_path)
+    return NULL;
+
+  // Only need to look up two symbols, but nlist() requires a NULL-terminated
+  // array and takes no count.
+  struct nlist nl[3];
+  bzero(&nl, sizeof(nl));
+
+  // The symbol to find.
+  nl[0].n_un.n_name = const_cast<char*>("_malloc_error_break");
+
+  // A reference symbol by which the address of the desired symbol will be
+  // calculated.
+  nl[1].n_un.n_name = const_cast<char*>("_malloc");
+
+  int rv = nlist(lib_c_path, nl);
+  if (rv != 0 || nl[0].n_type == N_UNDF || nl[1].n_type == N_UNDF) {
+    return NULL;
+  }
+
+  // nlist() returns addresses as offsets in the image, not the instruction
+  // pointer in memory. Use the known in-memory address of malloc()
+  // to compute the offset for malloc_error_break().
+  uintptr_t reference_addr = reinterpret_cast<uintptr_t>(&malloc);
+  reference_addr -= nl[1].n_value;
+  reference_addr += nl[0].n_value;
+
+  return reinterpret_cast<malloc_error_break_t>(reference_addr);
+#endif  // ARCH_CPU_32_BITS
+
+  return NULL;
+}
+
+// Simple scoper that saves the current value of errno, resets it to 0, and on
+// destruction puts the old value back. This is so that CrMallocErrorBreak can
+// safely test errno free from the effects of other routines.
+class ScopedClearErrno {
+ public:
+  ScopedClearErrno() : old_errno_(errno) {
+    errno = 0;
+  }
+  ~ScopedClearErrno() {
+    if (errno == 0)
+      errno = old_errno_;
+  }
+
+ private:
+  int old_errno_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedClearErrno);
+};
+
+// Combines ThreadLocalBoolean with AutoReset.  It would be convenient
+// to compose ThreadLocalPointer<bool> with AutoReset<bool>, but that
+// would require allocating some storage for the bool.
+class ThreadLocalBooleanAutoReset {
+ public:
+  ThreadLocalBooleanAutoReset(ThreadLocalBoolean* tlb, bool new_value)
+      : scoped_tlb_(tlb),
+        original_value_(tlb->Get()) {
+    scoped_tlb_->Set(new_value);
+  }
+  ~ThreadLocalBooleanAutoReset() {
+    scoped_tlb_->Set(original_value_);
+  }
+
+ private:
+  ThreadLocalBoolean* scoped_tlb_;
+  bool original_value_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset);
+};
+
+base::LazyInstance<ThreadLocalBoolean>::Leaky
+    g_unchecked_malloc = LAZY_INSTANCE_INITIALIZER;
+
+void CrMallocErrorBreak() {
+  g_original_malloc_error_break();
+
+  // Out of memory is certainly not heap corruption, and not necessarily
+  // something for which the process should be terminated. Leave that decision
+  // to the OOM killer.  The EBADF case comes up because the malloc library
+  // attempts to log to ASL (syslog) before calling this code, which fails
+  // accessing a Unix-domain socket because of sandboxing.
+  if (errno == ENOMEM || (errno == EBADF && g_unchecked_malloc.Get().Get()))
+    return;
+
+  // A unit test checks this error message, so it needs to be in release builds.
+  PLOG(ERROR) <<
+      "Terminating process due to a potential for future heap corruption";
+
+  // Crash by writing to NULL+errno to allow analyzing errno from
+  // crash dump info (setting a breakpad key would re-enter the malloc
+  // library).  Max documented errno in intro(2) is actually 102, but
+  // it really just needs to be "small" to stay on the right vm page.
+  const int kMaxErrno = 256;
+  char* volatile death_ptr = NULL;
+  death_ptr += std::min(errno, kMaxErrno);
+  *death_ptr = '!';
+}
+
+}  // namespace
+
+void EnableTerminationOnHeapCorruption() {
+#ifdef ADDRESS_SANITIZER
+  // Don't do anything special on heap corruption, because it should be handled
+  // by AddressSanitizer.
+  return;
+#endif
+  malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak();
+  if (!malloc_error_break) {
+    DLOG(WARNING) << "Could not find malloc_error_break";
+    return;
+  }
+
+  mach_error_t err = mach_override_ptr(
+     (void*)malloc_error_break,
+     (void*)&CrMallocErrorBreak,
+     (void**)&g_original_malloc_error_break);
+
+  if (err != err_none)
+    DLOG(WARNING) << "Could not override malloc_error_break; error = " << err;
+}
+
+// ------------------------------------------------------------------------
+
+namespace {
+
+bool g_oom_killer_enabled;
+
+// === C malloc/calloc/valloc/realloc/posix_memalign ===
+
+typedef void* (*malloc_type)(struct _malloc_zone_t* zone,
+                             size_t size);
+typedef void* (*calloc_type)(struct _malloc_zone_t* zone,
+                             size_t num_items,
+                             size_t size);
+typedef void* (*valloc_type)(struct _malloc_zone_t* zone,
+                             size_t size);
+typedef void (*free_type)(struct _malloc_zone_t* zone,
+                          void* ptr);
+typedef void* (*realloc_type)(struct _malloc_zone_t* zone,
+                              void* ptr,
+                              size_t size);
+typedef void* (*memalign_type)(struct _malloc_zone_t* zone,
+                               size_t alignment,
+                               size_t size);
+
+malloc_type g_old_malloc;
+calloc_type g_old_calloc;
+valloc_type g_old_valloc;
+free_type g_old_free;
+realloc_type g_old_realloc;
+memalign_type g_old_memalign;
+
+malloc_type g_old_malloc_purgeable;
+calloc_type g_old_calloc_purgeable;
+valloc_type g_old_valloc_purgeable;
+free_type g_old_free_purgeable;
+realloc_type g_old_realloc_purgeable;
+memalign_type g_old_memalign_purgeable;
+
+void* oom_killer_malloc(struct _malloc_zone_t* zone,
+                        size_t size) {
+  ScopedClearErrno clear_errno;
+  void* result = g_old_malloc(zone, size);
+  if (!result && size)
+    debug::BreakDebugger();
+  return result;
+}
+
+void* oom_killer_calloc(struct _malloc_zone_t* zone,
+                        size_t num_items,
+                        size_t size) {
+  ScopedClearErrno clear_errno;
+  void* result = g_old_calloc(zone, num_items, size);
+  if (!result && num_items && size)
+    debug::BreakDebugger();
+  return result;
+}
+
+void* oom_killer_valloc(struct _malloc_zone_t* zone,
+                        size_t size) {
+  ScopedClearErrno clear_errno;
+  void* result = g_old_valloc(zone, size);
+  if (!result && size)
+    debug::BreakDebugger();
+  return result;
+}
+
+void oom_killer_free(struct _malloc_zone_t* zone,
+                     void* ptr) {
+  ScopedClearErrno clear_errno;
+  g_old_free(zone, ptr);
+}
+
+void* oom_killer_realloc(struct _malloc_zone_t* zone,
+                         void* ptr,
+                         size_t size) {
+  ScopedClearErrno clear_errno;
+  void* result = g_old_realloc(zone, ptr, size);
+  if (!result && size)
+    debug::BreakDebugger();
+  return result;
+}
+
+void* oom_killer_memalign(struct _malloc_zone_t* zone,
+                          size_t alignment,
+                          size_t size) {
+  ScopedClearErrno clear_errno;
+  void* result = g_old_memalign(zone, alignment, size);
+  // Only die if posix_memalign would have returned ENOMEM, since there are
+  // other reasons why NULL might be returned (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
+  if (!result && size && alignment >= sizeof(void*)
+      && (alignment & (alignment - 1)) == 0) {
+    debug::BreakDebugger();
+  }
+  return result;
+}
+
+void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone,
+                                  size_t size) {
+  ScopedClearErrno clear_errno;
+  void* result = g_old_malloc_purgeable(zone, size);
+  if (!result && size)
+    debug::BreakDebugger();
+  return result;
+}
+
+void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone,
+                                  size_t num_items,
+                                  size_t size) {
+  ScopedClearErrno clear_errno;
+  void* result = g_old_calloc_purgeable(zone, num_items, size);
+  if (!result && num_items && size)
+    debug::BreakDebugger();
+  return result;
+}
+
+void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone,
+                                  size_t size) {
+  ScopedClearErrno clear_errno;
+  void* result = g_old_valloc_purgeable(zone, size);
+  if (!result && size)
+    debug::BreakDebugger();
+  return result;
+}
+
+void oom_killer_free_purgeable(struct _malloc_zone_t* zone,
+                               void* ptr) {
+  ScopedClearErrno clear_errno;
+  g_old_free_purgeable(zone, ptr);
+}
+
+void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone,
+                                   void* ptr,
+                                   size_t size) {
+  ScopedClearErrno clear_errno;
+  void* result = g_old_realloc_purgeable(zone, ptr, size);
+  if (!result && size)
+    debug::BreakDebugger();
+  return result;
+}
+
+void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone,
+                                    size_t alignment,
+                                    size_t size) {
+  ScopedClearErrno clear_errno;
+  void* result = g_old_memalign_purgeable(zone, alignment, size);
+  // Only die if posix_memalign would have returned ENOMEM, since there are
+  // other reasons why NULL might be returned (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
+  if (!result && size && alignment >= sizeof(void*)
+      && (alignment & (alignment - 1)) == 0) {
+    debug::BreakDebugger();
+  }
+  return result;
+}
+
+// === C++ operator new ===
+
+void oom_killer_new() {
+  debug::BreakDebugger();
+}
+
+// === Core Foundation CFAllocators ===
+
+bool CanGetContextForCFAllocator() {
+  return !base::mac::IsOSLaterThanMountainLion_DontCallThis();
+}
+
+CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) {
+  if (base::mac::IsOSSnowLeopard()) {
+    ChromeCFAllocatorLeopards* our_allocator =
+        const_cast<ChromeCFAllocatorLeopards*>(
+            reinterpret_cast<const ChromeCFAllocatorLeopards*>(allocator));
+    return &our_allocator->_context;
+  } else if (base::mac::IsOSLion() || base::mac::IsOSMountainLion()) {
+    ChromeCFAllocatorLions* our_allocator =
+        const_cast<ChromeCFAllocatorLions*>(
+            reinterpret_cast<const ChromeCFAllocatorLions*>(allocator));
+    return &our_allocator->_context;
+  } else {
+    return NULL;
+  }
+}
+
+CFAllocatorAllocateCallBack g_old_cfallocator_system_default;
+CFAllocatorAllocateCallBack g_old_cfallocator_malloc;
+CFAllocatorAllocateCallBack g_old_cfallocator_malloc_zone;
+
+void* oom_killer_cfallocator_system_default(CFIndex alloc_size,
+                                            CFOptionFlags hint,
+                                            void* info) {
+  void* result = g_old_cfallocator_system_default(alloc_size, hint, info);
+  if (!result)
+    debug::BreakDebugger();
+  return result;
+}
+
+void* oom_killer_cfallocator_malloc(CFIndex alloc_size,
+                                    CFOptionFlags hint,
+                                    void* info) {
+  void* result = g_old_cfallocator_malloc(alloc_size, hint, info);
+  if (!result)
+    debug::BreakDebugger();
+  return result;
+}
+
+void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size,
+                                         CFOptionFlags hint,
+                                         void* info) {
+  void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info);
+  if (!result)
+    debug::BreakDebugger();
+  return result;
+}
+
+// === Cocoa NSObject allocation ===
+
+typedef id (*allocWithZone_t)(id, SEL, NSZone*);
+allocWithZone_t g_old_allocWithZone;
+
+id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone)
+{
+  id result = g_old_allocWithZone(self, _cmd, zone);
+  if (!result)
+    debug::BreakDebugger();
+  return result;
+}
+
+}  // namespace
+
+void* UncheckedMalloc(size_t size) {
+  if (g_old_malloc) {
+    ScopedClearErrno clear_errno;
+    ThreadLocalBooleanAutoReset flag(g_unchecked_malloc.Pointer(), true);
+    return g_old_malloc(malloc_default_zone(), size);
+  }
+  return malloc(size);
+}
+
+void EnableTerminationOnOutOfMemory() {
+  if (g_oom_killer_enabled)
+    return;
+
+  g_oom_killer_enabled = true;
+
+  // === C malloc/calloc/valloc/realloc/posix_memalign ===
+
+  // This approach is not perfect, as requests for amounts of memory larger than
+  // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will
+  // still fail with a NULL rather than dying (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c for details).
+  // Unfortunately, it's the best we can do. Also note that this does not affect
+  // allocations from non-default zones.
+
+  CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc &&
+        !g_old_memalign) << "Old allocators unexpectedly non-null";
+
+  CHECK(!g_old_malloc_purgeable && !g_old_calloc_purgeable &&
+        !g_old_valloc_purgeable && !g_old_realloc_purgeable &&
+        !g_old_memalign_purgeable) << "Old allocators unexpectedly non-null";
+
+#if !defined(ADDRESS_SANITIZER)
+  // Don't do anything special on OOM for the malloc zones replaced by
+  // AddressSanitizer, as modifying or protecting them may not work correctly.
+
+  // See http://trac.webkit.org/changeset/53362/trunk/Tools/DumpRenderTree/mac
+  bool zone_allocators_protected = base::mac::IsOSLionOrLater();
+
+  ChromeMallocZone* default_zone =
+      reinterpret_cast<ChromeMallocZone*>(malloc_default_zone());
+  ChromeMallocZone* purgeable_zone =
+      reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone());
+
+  vm_address_t page_start_default = 0;
+  vm_address_t page_start_purgeable = 0;
+  vm_size_t len_default = 0;
+  vm_size_t len_purgeable = 0;
+  if (zone_allocators_protected) {
+    page_start_default = reinterpret_cast<vm_address_t>(default_zone) &
+        static_cast<vm_size_t>(~(getpagesize() - 1));
+    len_default = reinterpret_cast<vm_address_t>(default_zone) -
+        page_start_default + sizeof(ChromeMallocZone);
+    mprotect(reinterpret_cast<void*>(page_start_default), len_default,
+             PROT_READ | PROT_WRITE);
+
+    if (purgeable_zone) {
+      page_start_purgeable = reinterpret_cast<vm_address_t>(purgeable_zone) &
+          static_cast<vm_size_t>(~(getpagesize() - 1));
+      len_purgeable = reinterpret_cast<vm_address_t>(purgeable_zone) -
+          page_start_purgeable + sizeof(ChromeMallocZone);
+      mprotect(reinterpret_cast<void*>(page_start_purgeable), len_purgeable,
+               PROT_READ | PROT_WRITE);
+    }
+  }
+
+  // Default zone
+
+  g_old_malloc = default_zone->malloc;
+  g_old_calloc = default_zone->calloc;
+  g_old_valloc = default_zone->valloc;
+  g_old_free = default_zone->free;
+  g_old_realloc = default_zone->realloc;
+  CHECK(g_old_malloc && g_old_calloc && g_old_valloc && g_old_free &&
+        g_old_realloc)
+      << "Failed to get system allocation functions.";
+
+  default_zone->malloc = oom_killer_malloc;
+  default_zone->calloc = oom_killer_calloc;
+  default_zone->valloc = oom_killer_valloc;
+  default_zone->free = oom_killer_free;
+  default_zone->realloc = oom_killer_realloc;
+
+  if (default_zone->version >= 5) {
+    g_old_memalign = default_zone->memalign;
+    if (g_old_memalign)
+      default_zone->memalign = oom_killer_memalign;
+  }
+
+  // Purgeable zone (if it exists)
+
+  if (purgeable_zone) {
+    g_old_malloc_purgeable = purgeable_zone->malloc;
+    g_old_calloc_purgeable = purgeable_zone->calloc;
+    g_old_valloc_purgeable = purgeable_zone->valloc;
+    g_old_free_purgeable = purgeable_zone->free;
+    g_old_realloc_purgeable = purgeable_zone->realloc;
+    CHECK(g_old_malloc_purgeable && g_old_calloc_purgeable &&
+          g_old_valloc_purgeable && g_old_free_purgeable &&
+          g_old_realloc_purgeable)
+        << "Failed to get system allocation functions.";
+
+    purgeable_zone->malloc = oom_killer_malloc_purgeable;
+    purgeable_zone->calloc = oom_killer_calloc_purgeable;
+    purgeable_zone->valloc = oom_killer_valloc_purgeable;
+    purgeable_zone->free = oom_killer_free_purgeable;
+    purgeable_zone->realloc = oom_killer_realloc_purgeable;
+
+    if (purgeable_zone->version >= 5) {
+      g_old_memalign_purgeable = purgeable_zone->memalign;
+      if (g_old_memalign_purgeable)
+        purgeable_zone->memalign = oom_killer_memalign_purgeable;
+    }
+  }
+
+  if (zone_allocators_protected) {
+    mprotect(reinterpret_cast<void*>(page_start_default), len_default,
+             PROT_READ);
+    if (purgeable_zone) {
+      mprotect(reinterpret_cast<void*>(page_start_purgeable), len_purgeable,
+               PROT_READ);
+    }
+  }
+#endif
+
+  // === C malloc_zone_batch_malloc ===
+
+  // batch_malloc is omitted because the default malloc zone's implementation
+  // only supports batch_malloc for "tiny" allocations from the free list. It
+  // will fail for allocations larger than "tiny", and will only allocate as
+  // many blocks as it's able to from the free list. These factors mean that it
+  // can return less than the requested memory even in a non-out-of-memory
+  // situation. There's no good way to detect whether a batch_malloc failure is
+  // due to these other factors, or due to genuine memory or address space
+  // exhaustion. The fact that it only allocates space from the "tiny" free list
+  // means that it's likely that a failure will not be due to memory exhaustion.
+  // Similarly, these constraints on batch_malloc mean that callers must always
+  // be expecting to receive less memory than was requested, even in situations
+  // where memory pressure is not a concern. Finally, the only public interface
+  // to batch_malloc is malloc_zone_batch_malloc, which is specific to the
+  // system's malloc implementation. It's unlikely that anyone's even heard of
+  // it.
+
+  // === C++ operator new ===
+
+  // Yes, operator new does call through to malloc, but this will catch failures
+  // that our imperfect handling of malloc cannot.
+
+  std::set_new_handler(oom_killer_new);
+
+#ifndef ADDRESS_SANITIZER
+  // === Core Foundation CFAllocators ===
+
+  // This will not catch allocation done by custom allocators, but will catch
+  // all allocation done by system-provided ones.
+
+  CHECK(!g_old_cfallocator_system_default && !g_old_cfallocator_malloc &&
+        !g_old_cfallocator_malloc_zone)
+      << "Old allocators unexpectedly non-null";
+
+  bool cf_allocator_internals_known = CanGetContextForCFAllocator();
+
+  if (cf_allocator_internals_known) {
+    CFAllocatorContext* context =
+        ContextForCFAllocator(kCFAllocatorSystemDefault);
+    CHECK(context) << "Failed to get context for kCFAllocatorSystemDefault.";
+    g_old_cfallocator_system_default = context->allocate;
+    CHECK(g_old_cfallocator_system_default)
+        << "Failed to get kCFAllocatorSystemDefault allocation function.";
+    context->allocate = oom_killer_cfallocator_system_default;
+
+    context = ContextForCFAllocator(kCFAllocatorMalloc);
+    CHECK(context) << "Failed to get context for kCFAllocatorMalloc.";
+    g_old_cfallocator_malloc = context->allocate;
+    CHECK(g_old_cfallocator_malloc)
+        << "Failed to get kCFAllocatorMalloc allocation function.";
+    context->allocate = oom_killer_cfallocator_malloc;
+
+    context = ContextForCFAllocator(kCFAllocatorMallocZone);
+    CHECK(context) << "Failed to get context for kCFAllocatorMallocZone.";
+    g_old_cfallocator_malloc_zone = context->allocate;
+    CHECK(g_old_cfallocator_malloc_zone)
+        << "Failed to get kCFAllocatorMallocZone allocation function.";
+    context->allocate = oom_killer_cfallocator_malloc_zone;
+  } else {
+    NSLog(@"Internals of CFAllocator not known; out-of-memory failures via "
+        "CFAllocator will not result in termination. http://crbug.com/45650");
+  }
+#endif
+
+  // === Cocoa NSObject allocation ===
+
+  // Note that both +[NSObject new] and +[NSObject alloc] call through to
+  // +[NSObject allocWithZone:].
+
+  CHECK(!g_old_allocWithZone)
+      << "Old allocator unexpectedly non-null";
+
+  Class nsobject_class = [NSObject class];
+  Method orig_method = class_getClassMethod(nsobject_class,
+                                            @selector(allocWithZone:));
+  g_old_allocWithZone = reinterpret_cast<allocWithZone_t>(
+      method_getImplementation(orig_method));
+  CHECK(g_old_allocWithZone)
+      << "Failed to get allocWithZone allocation function.";
+  method_setImplementation(orig_method,
+                           reinterpret_cast<IMP>(oom_killer_allocWithZone));
+}
+
+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;
+}
+
+namespace {
+
+const int kWaitBeforeKillSeconds = 2;
+
+// Reap |child| process. This call blocks until completion.
+void BlockingReap(pid_t child) {
+  const pid_t result = HANDLE_EINTR(waitpid(child, NULL, 0));
+  if (result == -1) {
+    DPLOG(ERROR) << "waitpid(" << child << ", NULL, 0)";
+  }
+}
+
+// Waits for |timeout| seconds for the given |child| to exit and reap it. If
+// the child doesn't exit within the time specified, kills it.
+//
+// This function takes two approaches: first, it tries to use kqueue to
+// observe when the process exits. kevent can monitor a kqueue with a
+// timeout, so this method is preferred to wait for a specified period of
+// time. Once the kqueue indicates the process has exited, waitpid will reap
+// the exited child. If the kqueue doesn't provide an exit event notification,
+// before the timeout expires, or if the kqueue fails or misbehaves, the
+// process will be mercilessly killed and reaped.
+//
+// A child process passed to this function may be in one of several states:
+// running, terminated and not yet reaped, and (apparently, and unfortunately)
+// terminated and already reaped. Normally, a process will at least have been
+// asked to exit before this function is called, but this is not required.
+// If a process is terminating and unreaped, there may be a window between the
+// time that kqueue will no longer recognize it and when it becomes an actual
+// zombie that a non-blocking (WNOHANG) waitpid can reap. This condition is
+// detected when kqueue indicates that the process is not running and a
+// non-blocking waitpid fails to reap the process but indicates that it is
+// still running. In this event, a blocking attempt to reap the process
+// collects the known-dying child, preventing zombies from congregating.
+//
+// In the event that the kqueue misbehaves entirely, as it might under a
+// EMFILE condition ("too many open files", or out of file descriptors), this
+// function will forcibly kill and reap the child without delay. This
+// eliminates another potential zombie vector. (If you're out of file
+// descriptors, you're probably deep into something else, but that doesn't
+// mean that zombies be allowed to kick you while you're down.)
+//
+// The fact that this function seemingly can be called to wait on a child
+// that's not only already terminated but already reaped is a bit of a
+// problem: a reaped child's pid can be reclaimed and may refer to a distinct
+// process in that case. The fact that this function can seemingly be called
+// to wait on a process that's not even a child is also a problem: kqueue will
+// work in that case, but waitpid won't, and killing a non-child might not be
+// the best approach.
+void WaitForChildToDie(pid_t child, int timeout) {
+  DCHECK(child > 0);
+  DCHECK(timeout > 0);
+
+  // DON'T ADD ANY EARLY RETURNS TO THIS FUNCTION without ensuring that
+  // |child| has been reaped. Specifically, even if a kqueue, kevent, or other
+  // call fails, this function should fall back to the last resort of trying
+  // to kill and reap the process. Not observing this rule will resurrect
+  // zombies.
+
+  int result;
+
+  int kq = HANDLE_EINTR(kqueue());
+  if (kq == -1) {
+    DPLOG(ERROR) << "kqueue()";
+  } else {
+    file_util::ScopedFD auto_close_kq(&kq);
+
+    struct kevent change = {0};
+    EV_SET(&change, child, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+    result = HANDLE_EINTR(kevent(kq, &change, 1, NULL, 0, NULL));
+
+    if (result == -1) {
+      if (errno != ESRCH) {
+        DPLOG(ERROR) << "kevent (setup " << child << ")";
+      } else {
+        // At this point, one of the following has occurred:
+        // 1. The process has died but has not yet been reaped.
+        // 2. The process has died and has already been reaped.
+        // 3. The process is in the process of dying. It's no longer
+        //    kqueueable, but it may not be waitable yet either. Mark calls
+        //    this case the "zombie death race".
+
+        result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
+
+        if (result != 0) {
+          // A positive result indicates case 1. waitpid succeeded and reaped
+          // the child. A result of -1 indicates case 2. The child has already
+          // been reaped. In both of these cases, no further action is
+          // necessary.
+          return;
+        }
+
+        // |result| is 0, indicating case 3. The process will be waitable in
+        // short order. Fall back out of the kqueue code to kill it (for good
+        // measure) and reap it.
+      }
+    } else {
+      // Keep track of the elapsed time to be able to restart kevent if it's
+      // interrupted.
+      TimeDelta remaining_delta = TimeDelta::FromSeconds(timeout);
+      Time deadline = Time::Now() + remaining_delta;
+      result = -1;
+      struct kevent event = {0};
+      while (remaining_delta.InMilliseconds() > 0) {
+        const struct timespec remaining_timespec = remaining_delta.ToTimeSpec();
+        result = kevent(kq, NULL, 0, &event, 1, &remaining_timespec);
+        if (result == -1 && errno == EINTR) {
+          remaining_delta = deadline - Time::Now();
+          result = 0;
+        } else {
+          break;
+        }
+      }
+
+      if (result == -1) {
+        DPLOG(ERROR) << "kevent (wait " << child << ")";
+      } else if (result > 1) {
+        DLOG(ERROR) << "kevent (wait " << child << "): unexpected result "
+                    << result;
+      } else if (result == 1) {
+        if ((event.fflags & NOTE_EXIT) &&
+            (event.ident == static_cast<uintptr_t>(child))) {
+          // The process is dead or dying. This won't block for long, if at
+          // all.
+          BlockingReap(child);
+          return;
+        } else {
+          DLOG(ERROR) << "kevent (wait " << child
+                      << "): unexpected event: fflags=" << event.fflags
+                      << ", ident=" << event.ident;
+        }
+      }
+    }
+  }
+
+  // The child is still alive, or is very freshly dead. Be sure by sending it
+  // a signal. This is safe even if it's freshly dead, because it will be a
+  // zombie (or on the way to zombiedom) and kill will return 0 even if the
+  // signal is not delivered to a live process.
+  result = kill(child, SIGKILL);
+  if (result == -1) {
+    DPLOG(ERROR) << "kill(" << child << ", SIGKILL)";
+  } else {
+    // The child is definitely on the way out now. BlockingReap won't need to
+    // wait for long, if at all.
+    BlockingReap(child);
+  }
+}
+
+}  // namespace
+
+void EnsureProcessTerminated(ProcessHandle process) {
+  WaitForChildToDie(process, kWaitBeforeKillSeconds);
+}
+
+}  // namespace base
diff --git a/base/process_util_openbsd.cc b/base/process_util_openbsd.cc
new file mode 100644
index 0000000..2b2bd25
--- /dev/null
+++ b/base/process_util_openbsd.cc
@@ -0,0 +1,346 @@
+// Copyright (c) 2011 The Chromium Authors. All 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_util.h"
+
+#include <ctype.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/string_tokenizer.h"
+#include "base/string_util.h"
+#include "base/sys_info.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return info.p_ppid;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  struct kinfo_proc kp;
+  size_t len;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) == -1)
+    return FilePath();
+  mib[5] = (len / sizeof(struct kinfo_proc));
+  if (sysctl(mib, arraysize(mib), &kp, &len, NULL, 0) < 0)
+    return FilePath();
+  if ((kp.p_flag & P_SYSTEM) != 0)
+    return FilePath();
+  if (strcmp(kp.p_comm, "chrome") == 0)
+    return FilePath(kp.p_comm);
+
+  return FilePath();
+}
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : index_of_kinfo_proc_(),
+      filter_(filter) {
+
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid(),
+                sizeof(struct kinfo_proc), 0 };
+
+  bool done = false;
+  int try_num = 1;
+  const int max_tries = 10;
+
+  do {
+    size_t len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+      DLOG(ERROR) << "failed to get the size needed for the process list";
+      kinfo_procs_.resize(0);
+      done = true;
+    } else {
+      size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+      // Leave some spare room for process table growth (more could show up
+      // between when we check and now)
+      num_of_kinfo_proc += 16;
+      kinfo_procs_.resize(num_of_kinfo_proc);
+      len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+      if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
+        // If we get a mem error, it just means we need a bigger buffer, so
+        // loop around again.  Anything else is a real error and give up.
+        if (errno != ENOMEM) {
+          DLOG(ERROR) << "failed to get the process list";
+          kinfo_procs_.resize(0);
+          done = true;
+        }
+      } else {
+        // Got the list, just make sure we're sized exactly right
+        size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+        kinfo_procs_.resize(num_of_kinfo_proc);
+        done = true;
+      }
+    }
+  } while (!done && (try_num++ < max_tries));
+
+  if (!done) {
+    DLOG(ERROR) << "failed to collect the process list in a few tries";
+    kinfo_procs_.resize(0);
+  }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  std::string data;
+  for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+    kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
+
+    // Skip processes just awaiting collection
+    if ((kinfo.p_pid > 0) && (kinfo.p_stat == SZOMB))
+      continue;
+
+    int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.p_pid };
+
+    // Find out what size buffer we need.
+    size_t data_len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to figure out the buffer size for a commandline";
+      continue;
+    }
+
+    data.resize(data_len);
+    if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to fetch a commandline";
+      continue;
+    }
+
+    // |data| contains all the command line parameters of the process, separated
+    // by blocks of one or more null characters. We tokenize |data| into a
+    // vector of strings using '\0' as a delimiter and populate
+    // |entry_.cmd_line_args_|.
+    std::string delimiters;
+    delimiters.push_back('\0');
+    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+    // |data| starts with the full executable path followed by a null character.
+    // We search for the first instance of '\0' and extract everything before it
+    // to populate |entry_.exe_file_|.
+    size_t exec_name_end = data.find('\0');
+    if (exec_name_end == std::string::npos) {
+      DLOG(ERROR) << "command line data didn't match expected format";
+      continue;
+    }
+
+    entry_.pid_ = kinfo.p_pid;
+    entry_.ppid_ = kinfo.p_ppid;
+    entry_.gid_ = kinfo.p__pgid;
+    size_t last_slash = data.rfind('/', exec_name_end);
+    if (last_slash == std::string::npos)
+      entry_.exe_file_.assign(data, 0, exec_name_end);
+    else
+      entry_.exe_file_.assign(data, last_slash + 1,
+                              exec_name_end - last_slash - 1);
+    // Start w/ the next entry next time through
+    ++index_of_kinfo_proc_;
+    // Done
+    return true;
+  }
+  return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  return (executable_name_ == entry().exe_file() &&
+          ProcessIterator::IncludeEntry());
+}
+
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      last_time_(0),
+      last_system_time_(0),
+      last_cpu_(0) {
+
+  processor_count_ = base::SysInfo::NumberOfProcessors();
+}
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return (info.p_vm_tsize + info.p_vm_dsize + info.p_vm_ssize);
+}
+
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+
+  return 0;
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return info.p_vm_rssize * getpagesize();
+}
+
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+
+  return 0;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  WorkingSetKBytes ws_usage;
+
+  if (!GetWorkingSetKBytes(&ws_usage))
+    return false;
+
+  if (private_bytes)
+    *private_bytes = ws_usage.priv << 10;
+
+  if (shared_bytes)
+    *shared_bytes = ws_usage.shared * 1024;
+
+  return true;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+// TODO(bapt) be sure we can't be precise
+  size_t priv = GetWorkingSetSize();
+  if (!priv)
+    return false;
+  ws_usage->priv = priv / 1024;
+  ws_usage->shareable = 0;
+  ws_usage->shared = 0;
+
+  return true;
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return false;
+}
+
+static int GetProcessCPU(pid_t pid) {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return info.p_pctcpu;
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  struct timeval now;
+
+  int retval = gettimeofday(&now, NULL);
+  if (retval)
+    return 0;
+
+  int64 time = TimeValToMicroseconds(now);
+
+  if (last_time_ == 0) {
+    // First call, just set the last values.
+    last_time_ = time;
+    last_cpu_ = GetProcessCPU(process_);
+    return 0;
+  }
+
+  int64 time_delta = time - last_time_;
+  DCHECK_NE(time_delta, 0);
+
+  if (time_delta == 0)
+    return 0;
+
+  int cpu = GetProcessCPU(process_);
+
+  last_time_ = time;
+  last_cpu_ = cpu;
+
+  double percentage = static_cast<double>((cpu * 100.0) / FSCALE);
+
+  return percentage;
+}
+
+size_t GetSystemCommitCharge() {
+  int mib[] = { CTL_VM, VM_METER };
+  int pagesize;
+  struct vmtotal vmtotal;
+  unsigned long mem_total, mem_free, mem_inactive;
+  size_t len = sizeof(vmtotal);
+
+  if (sysctl(mib, arraysize(mib), &vmtotal, &len, NULL, 0) < 0)
+    return 0;
+
+  mem_total = vmtotal.t_vm;
+  mem_free = vmtotal.t_free;
+  mem_inactive = vmtotal.t_vm - vmtotal.t_avm;
+
+  pagesize = getpagesize();
+
+  return mem_total - (mem_free*pagesize) - (mem_inactive*pagesize);
+}
+
+void EnableTerminationOnOutOfMemory() {
+}
+
+void EnableTerminationOnHeapCorruption() {
+}
+
+}  // namespace base
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
new file mode 100644
index 0000000..3d5c930
--- /dev/null
+++ b/base/process_util_posix.cc
@@ -0,0 +1,1268 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iterator>
+#include <limits>
+#include <set>
+
+#include "base/allocator/type_profiler_control.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/debug/debugger.h"
+#include "base/debug/stack_trace.h"
+#include "base/eintr_wrapper.h"
+#include "base/file_util.h"
+#include "base/files/dir_reader_posix.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process_util.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_CHROMEOS)
+#include <sys/ioctl.h>
+#endif
+
+#if defined(OS_FREEBSD)
+#include <sys/event.h>
+#include <sys/ucontext.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <crt_externs.h>
+#include <sys/event.h>
+#else
+extern char** environ;
+#endif
+
+namespace base {
+
+namespace {
+
+// Get the process's "environment" (i.e. the thing that setenv/getenv
+// work with).
+char** GetEnvironment() {
+#if defined(OS_MACOSX)
+  return *_NSGetEnviron();
+#else
+  return environ;
+#endif
+}
+
+// Set the process's "environment" (i.e. the thing that setenv/getenv
+// work with).
+void SetEnvironment(char** env) {
+#if defined(OS_MACOSX)
+  *_NSGetEnviron() = env;
+#else
+  environ = env;
+#endif
+}
+
+int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds,
+                       bool* success) {
+  // This POSIX version of this function only guarantees that we wait no less
+  // than |wait_milliseconds| 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_milliseconds, 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.
+  int status = -1;
+  pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
+  static const int64 kMaxSleepInMicroseconds = 1 << 18;  // ~256 milliseconds.
+  int64 max_sleep_time_usecs = 1 << 10;  // ~1 milliseconds.
+  int64 double_sleep_time = 0;
+
+  // If the process hasn't exited yet, then sleep and try again.
+  Time wakeup_time = Time::Now() +
+      TimeDelta::FromMilliseconds(wait_milliseconds);
+  while (ret_pid == 0) {
+    Time now = Time::Now();
+    if (now > wakeup_time)
+      break;
+    // Guaranteed to be non-negative!
+    int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
+    // Sleep for a bit while we wait for the process to finish.
+    if (sleep_time_usecs > max_sleep_time_usecs)
+      sleep_time_usecs = max_sleep_time_usecs;
+
+    // usleep() will return 0 and set errno to EINTR on receipt of a signal
+    // such as SIGCHLD.
+    usleep(sleep_time_usecs);
+    ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
+
+    if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
+        (double_sleep_time++ % 4 == 0)) {
+      max_sleep_time_usecs *= 2;
+    }
+  }
+
+  if (success)
+    *success = (ret_pid != -1);
+
+  return status;
+}
+
+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);
+}
+
+}  // anonymous namespace
+
+ProcessId GetCurrentProcId() {
+  return getpid();
+}
+
+ProcessHandle GetCurrentProcessHandle() {
+  return GetCurrentProcId();
+}
+
+bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
+  // On Posix platforms, process handles are the same as PIDs, so we
+  // don't need to do anything.
+  *handle = pid;
+  return true;
+}
+
+bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
+  // On POSIX permissions are checked for each operation on process,
+  // not when opening a "handle".
+  return OpenProcessHandle(pid, handle);
+}
+
+bool OpenProcessHandleWithAccess(ProcessId pid,
+                                 uint32 access_flags,
+                                 ProcessHandle* handle) {
+  // On POSIX permissions are checked for each operation on process,
+  // not when opening a "handle".
+  return OpenProcessHandle(pid, handle);
+}
+
+void CloseProcessHandle(ProcessHandle process) {
+  // See OpenProcessHandle, nothing to do.
+  return;
+}
+
+ProcessId GetProcId(ProcessHandle process) {
+  return process;
+}
+
+// Attempts to kill the process identified by the given process
+// entry structure.  Ignores specified exit_code; posix can't force that.
+// Returns true if this is successful, false otherwise.
+bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
+  DCHECK_GT(process_id, 1) << " tried to kill invalid process_id";
+  if (process_id <= 1)
+    return false;
+  bool result = kill(process_id, SIGTERM) == 0;
+  if (result && wait) {
+    int tries = 60;
+
+    if (RunningOnValgrind()) {
+      // Wait for some extra time when running under Valgrind since the child
+      // processes may take some time doing leak checking.
+      tries *= 2;
+    }
+
+    unsigned sleep_ms = 4;
+
+    // The process may not end immediately due to pending I/O
+    bool exited = false;
+    while (tries-- > 0) {
+      pid_t pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG));
+      if (pid == process_id) {
+        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_id;
+      }
+
+      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_id, SIGKILL) == 0;
+  }
+
+  if (!result)
+    DPLOG(ERROR) << "Unable to terminate process " << process_id;
+
+  return result;
+}
+
+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;
+}
+
+// A class to handle auto-closing of DIR*'s.
+class ScopedDIRClose {
+ public:
+  inline void operator()(DIR* x) const {
+    if (x) {
+      closedir(x);
+    }
+  }
+};
+typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR;
+
+#if defined(OS_LINUX)
+  static const rlim_t kSystemDefaultMaxFds = 8192;
+  static const char kFDDir[] = "/proc/self/fd";
+#elif defined(OS_MACOSX)
+  static const rlim_t kSystemDefaultMaxFds = 256;
+  static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_SOLARIS)
+  static const rlim_t kSystemDefaultMaxFds = 8192;
+  static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_FREEBSD)
+  static const rlim_t kSystemDefaultMaxFds = 8192;
+  static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_OPENBSD)
+  static const rlim_t kSystemDefaultMaxFds = 256;
+  static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_ANDROID)
+  static const rlim_t kSystemDefaultMaxFds = 1024;
+  static const char kFDDir[] = "/proc/self/fd";
+#endif
+
+void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
+  // DANGER: no calls to malloc are allowed from now on:
+  // http://crbug.com/36678
+
+  // Get the maximum number of FDs possible.
+  struct rlimit nofile;
+  rlim_t max_fds;
+  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;
+
+  DirReaderPosix fd_dir(kFDDir);
+
+  if (!fd_dir.IsValid()) {
+    // Fallback case: Try every possible fd.
+    for (rlim_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;
+      InjectiveMultimap::const_iterator j;
+      for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) {
+        if (fd == j->dest)
+          break;
+      }
+      if (j != saved_mapping.end())
+        continue;
+
+      // Since we're just trying to close anything we can find,
+      // ignore any error return values of close().
+      ignore_result(HANDLE_EINTR(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;
+    InjectiveMultimap::const_iterator i;
+    for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) {
+      if (fd == i->dest)
+        break;
+    }
+    if (i != saved_mapping.end())
+      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 = HANDLE_EINTR(close(fd));
+      DPCHECK(ret == 0);
+    }
+  }
+}
+
+char** AlterEnvironment(const EnvironmentVector& changes,
+                        const char* const* const env) {
+  unsigned count = 0;
+  unsigned size = 0;
+
+  // First assume that all of the current environment will be included.
+  for (unsigned i = 0; env[i]; i++) {
+    const char *const pair = env[i];
+    count++;
+    size += strlen(pair) + 1 /* terminating NUL */;
+  }
+
+  for (EnvironmentVector::const_iterator j = changes.begin();
+       j != changes.end();
+       ++j) {
+    bool found = false;
+    const char *pair;
+
+    for (unsigned i = 0; env[i]; i++) {
+      pair = env[i];
+      const char *const equals = strchr(pair, '=');
+      if (!equals)
+        continue;
+      const unsigned keylen = equals - pair;
+      if (keylen == j->first.size() &&
+          memcmp(pair, j->first.data(), keylen) == 0) {
+        found = true;
+        break;
+      }
+    }
+
+    // if found, we'll either be deleting or replacing this element.
+    if (found) {
+      count--;
+      size -= strlen(pair) + 1;
+      if (j->second.size())
+        found = false;
+    }
+
+    // if !found, then we have a new element to add.
+    if (!found && !j->second.empty()) {
+      count++;
+      size += j->first.size() + 1 /* '=' */ + j->second.size() + 1 /* NUL */;
+    }
+  }
+
+  count++;  // for the final NULL
+  uint8_t *buffer = new uint8_t[sizeof(char*) * count + size];
+  char **const ret = reinterpret_cast<char**>(buffer);
+  unsigned k = 0;
+  char *scratch = reinterpret_cast<char*>(buffer + sizeof(char*) * count);
+
+  for (unsigned i = 0; env[i]; i++) {
+    const char *const pair = env[i];
+    const char *const equals = strchr(pair, '=');
+    if (!equals) {
+      const unsigned len = strlen(pair);
+      ret[k++] = scratch;
+      memcpy(scratch, pair, len + 1);
+      scratch += len + 1;
+      continue;
+    }
+    const unsigned keylen = equals - pair;
+    bool handled = false;
+    for (EnvironmentVector::const_iterator
+         j = changes.begin(); j != changes.end(); j++) {
+      if (j->first.size() == keylen &&
+          memcmp(j->first.data(), pair, keylen) == 0) {
+        if (!j->second.empty()) {
+          ret[k++] = scratch;
+          memcpy(scratch, pair, keylen + 1);
+          scratch += keylen + 1;
+          memcpy(scratch, j->second.c_str(), j->second.size() + 1);
+          scratch += j->second.size() + 1;
+        }
+        handled = true;
+        break;
+      }
+    }
+
+    if (!handled) {
+      const unsigned len = strlen(pair);
+      ret[k++] = scratch;
+      memcpy(scratch, pair, len + 1);
+      scratch += len + 1;
+    }
+  }
+
+  // Now handle new elements
+  for (EnvironmentVector::const_iterator
+       j = changes.begin(); j != changes.end(); j++) {
+    if (j->second.empty())
+      continue;
+
+    bool found = false;
+    for (unsigned i = 0; env[i]; i++) {
+      const char *const pair = env[i];
+      const char *const equals = strchr(pair, '=');
+      if (!equals)
+        continue;
+      const unsigned keylen = equals - pair;
+      if (keylen == j->first.size() &&
+          memcmp(pair, j->first.data(), keylen) == 0) {
+        found = true;
+        break;
+      }
+    }
+
+    if (!found) {
+      ret[k++] = scratch;
+      memcpy(scratch, j->first.data(), j->first.size());
+      scratch += j->first.size();
+      *scratch++ = '=';
+      memcpy(scratch, j->second.c_str(), j->second.size() + 1);
+      scratch += j->second.size() + 1;
+     }
+  }
+
+  ret[k] = NULL;
+  return ret;
+}
+
+bool LaunchProcess(const std::vector<std::string>& argv,
+                   const LaunchOptions& options,
+                   ProcessHandle* process_handle) {
+  size_t fd_shuffle_size = 0;
+  if (options.fds_to_remap) {
+    fd_shuffle_size = options.fds_to_remap->size();
+  }
+
+#if defined(OS_MACOSX)
+  if (options.synchronize) {
+    // When synchronizing, the "read" end of the synchronization pipe needs
+    // to make it to the child process. This is handled by mapping it back to
+    // itself.
+    ++fd_shuffle_size;
+  }
+#endif  // defined(OS_MACOSX)
+
+  InjectiveMultimap fd_shuffle1;
+  InjectiveMultimap fd_shuffle2;
+  fd_shuffle1.reserve(fd_shuffle_size);
+  fd_shuffle2.reserve(fd_shuffle_size);
+
+  scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
+  scoped_array<char*> new_environ;
+  if (options.environ)
+    new_environ.reset(AlterEnvironment(*options.environ, GetEnvironment()));
+
+#if defined(OS_MACOSX)
+  int synchronization_pipe_fds[2];
+  file_util::ScopedFD synchronization_read_fd;
+  file_util::ScopedFD synchronization_write_fd;
+
+  if (options.synchronize) {
+    // wait means "don't return from LaunchProcess until the child exits", and
+    // synchronize means "return from LaunchProcess but don't let the child
+    // run until LaunchSynchronize is called". These two options are highly
+    // incompatible.
+    DCHECK(!options.wait);
+
+    // Create the pipe used for synchronization.
+    if (HANDLE_EINTR(pipe(synchronization_pipe_fds)) != 0) {
+      DPLOG(ERROR) << "pipe";
+      return false;
+    }
+
+    // The parent process will only use synchronization_write_fd as the write
+    // side of the pipe. It can close the read side as soon as the child
+    // process has forked off. The child process will only use
+    // synchronization_read_fd as the read side of the pipe. In that process,
+    // the write side can be closed as soon as it has forked.
+    synchronization_read_fd.reset(&synchronization_pipe_fds[0]);
+    synchronization_write_fd.reset(&synchronization_pipe_fds[1]);
+  }
+#endif  // OS_MACOSX
+
+  pid_t pid;
+#if defined(OS_LINUX)
+  if (options.clone_flags) {
+    pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0);
+  } else
+#endif
+  {
+    pid = fork();
+  }
+
+  if (pid < 0) {
+    DPLOG(ERROR) << "fork";
+    return false;
+  } else if (pid == 0) {
+    // Child process
+
+    // 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.
+    int null_fd = HANDLE_EINTR(open("/dev/null", O_RDONLY));
+    if (null_fd < 0) {
+      RAW_LOG(ERROR, "Failed to open /dev/null");
+      _exit(127);
+    }
+
+    file_util::ScopedFD null_fd_closer(&null_fd);
+    int new_fd = HANDLE_EINTR(dup2(null_fd, STDIN_FILENO));
+    if (new_fd != STDIN_FILENO) {
+      RAW_LOG(ERROR, "Failed to dup /dev/null for stdin");
+      _exit(127);
+    }
+
+    if (options.new_process_group) {
+      // Instead of inheriting the process group ID of the parent, the child
+      // starts off a new process group with pgid equal to its process ID.
+      if (setpgid(0, 0) < 0) {
+        RAW_LOG(ERROR, "setpgid failed");
+        _exit(127);
+      }
+    }
+
+    // Stop type-profiler.
+    // The profiler should be stopped between fork and exec since it inserts
+    // locks at new/delete expressions.  See http://crbug.com/36678.
+    base::type_profiler::Controller::Stop();
+
+    if (options.maximize_rlimits) {
+      // Some resource limits need to be maximal in this child.
+      std::set<int>::const_iterator resource;
+      for (resource = options.maximize_rlimits->begin();
+           resource != options.maximize_rlimits->end();
+           ++resource) {
+        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();
+
+#if defined(OS_MACOSX)
+    if (options.synchronize) {
+      // The "write" side of the synchronization pipe belongs to the parent.
+      synchronization_write_fd.reset();  // closes synchronization_pipe_fds[1]
+    }
+#endif  // defined(OS_MACOSX)
+
+#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
+
+    // DANGER: no calls to malloc are allowed from now on:
+    // http://crbug.com/36678
+
+#if defined(OS_CHROMEOS)
+    if (options.ctrl_terminal_fd >= 0) {
+      // Set process' controlling terminal.
+      if (HANDLE_EINTR(setsid()) != -1) {
+        if (HANDLE_EINTR(
+                ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) {
+          RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set");
+        }
+      } else {
+        RAW_LOG(WARNING, "setsid failed, ctrl terminal not set");
+      }
+    }
+#endif  // defined(OS_CHROMEOS)
+
+    if (options.fds_to_remap) {
+      for (FileHandleMappingVector::const_iterator
+               it = options.fds_to_remap->begin();
+           it != options.fds_to_remap->end(); ++it) {
+        fd_shuffle1.push_back(InjectionArc(it->first, it->second, false));
+        fd_shuffle2.push_back(InjectionArc(it->first, it->second, false));
+      }
+    }
+
+#if defined(OS_MACOSX)
+    if (options.synchronize) {
+      // Remap the read side of the synchronization pipe back onto itself,
+      // ensuring that it won't be closed by CloseSuperfluousFds.
+      int keep_fd = *synchronization_read_fd.get();
+      fd_shuffle1.push_back(InjectionArc(keep_fd, keep_fd, false));
+      fd_shuffle2.push_back(InjectionArc(keep_fd, keep_fd, false));
+    }
+#endif  // defined(OS_MACOSX)
+
+    if (options.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);
+
+#if defined(OS_MACOSX)
+    if (options.synchronize) {
+      // Do a blocking read to wait until the parent says it's OK to proceed.
+      // The byte that's read here is written by LaunchSynchronize.
+      char read_char;
+      int read_result =
+          HANDLE_EINTR(read(*synchronization_read_fd.get(), &read_char, 1));
+      if (read_result != 1) {
+        RAW_LOG(ERROR, "LaunchProcess: synchronization read: error");
+        _exit(127);
+      }
+
+      // The pipe is no longer useful. Don't let it live on in the new process
+      // after exec.
+      synchronization_read_fd.reset();  // closes synchronization_pipe_fds[0]
+    }
+#endif  // defined(OS_MACOSX)
+
+    for (size_t i = 0; i < argv.size(); i++)
+      argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+    argv_cstr[argv.size()] = NULL;
+    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);
+    }
+
+    if (process_handle)
+      *process_handle = pid;
+
+#if defined(OS_MACOSX)
+    if (options.synchronize) {
+      // The "read" side of the synchronization pipe belongs to the child.
+      synchronization_read_fd.reset();  // closes synchronization_pipe_fds[0]
+      *options.synchronize = new int(*synchronization_write_fd.release());
+    }
+#endif  // defined(OS_MACOSX)
+  }
+
+  return true;
+}
+
+
+bool LaunchProcess(const CommandLine& cmdline,
+                   const LaunchOptions& options,
+                   ProcessHandle* process_handle) {
+  return LaunchProcess(cmdline.argv(), options, process_handle);
+}
+
+#if defined(OS_MACOSX)
+void LaunchSynchronize(LaunchSynchronizationHandle handle) {
+  int synchronization_fd = *handle;
+  file_util::ScopedFD synchronization_fd_closer(&synchronization_fd);
+  delete handle;
+
+  // Write a '\0' character to the pipe.
+  if (HANDLE_EINTR(write(synchronization_fd, "", 1)) != 1) {
+    DPLOG(ERROR) << "write";
+  }
+}
+#endif  // defined(OS_MACOSX)
+
+ProcessMetrics::~ProcessMetrics() { }
+
+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.
+}
+
+TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
+  int status = 0;
+  const pid_t result = HANDLE_EINTR(waitpid(handle, &status, 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 SIGINT:
+      case SIGKILL:
+      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;
+}
+
+bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
+  int status;
+  if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) {
+    NOTREACHED();
+    return false;
+  }
+
+  if (WIFEXITED(status)) {
+    *exit_code = WEXITSTATUS(status);
+    return true;
+  }
+
+  // If it didn't exit cleanly, it must have been signaled.
+  DCHECK(WIFSIGNALED(status));
+  return false;
+}
+
+bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code,
+                                base::TimeDelta timeout) {
+  bool waitpid_success = false;
+  int status = WaitpidWithTimeout(handle, timeout.InMilliseconds(),
+                                  &waitpid_success);
+  if (status == -1)
+    return false;
+  if (!waitpid_success)
+    return false;
+  if (WIFSIGNALED(status)) {
+    *exit_code = -1;
+    return true;
+  }
+  if (WIFEXITED(status)) {
+    *exit_code = WEXITSTATUS(status);
+    return true;
+  }
+  return false;
+}
+
+#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(ProcessHandle handle,
+                                         base::TimeDelta wait) {
+  DCHECK_GT(handle, 0);
+  DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta());
+
+  int kq = kqueue();
+  if (kq == -1) {
+    DPLOG(ERROR) << "kqueue";
+    return false;
+  }
+  file_util::ScopedFD kq_closer(&kq);
+
+  struct kevent change = {0};
+  EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+  int result = HANDLE_EINTR(kevent(kq, &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.InMilliseconds() == base::kNoTimeout;
+  base::TimeDelta remaining_delta;
+  base::Time deadline;
+  if (!wait_forever) {
+    remaining_delta = wait;
+    deadline = base::Time::Now() + remaining_delta;
+  }
+
+  result = -1;
+  struct kevent event = {0};
+
+  while (wait_forever || remaining_delta > base::TimeDelta()) {
+    struct timespec remaining_timespec;
+    struct timespec* remaining_timespec_ptr;
+    if (wait_forever) {
+      remaining_timespec_ptr = NULL;
+    } else {
+      remaining_timespec = remaining_delta.ToTimeSpec();
+      remaining_timespec_ptr = &remaining_timespec;
+    }
+
+    result = kevent(kq, NULL, 0, &event, 1, remaining_timespec_ptr);
+
+    if (result == -1 && errno == EINTR) {
+      if (!wait_forever) {
+        remaining_delta = deadline - base::Time::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 WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
+  ProcessHandle parent_pid = GetParentProcessId(handle);
+  ProcessHandle our_pid = Process::Current().handle();
+  if (parent_pid != our_pid) {
+#if defined(OS_MACOSX)
+    // On Mac we can wait on non child processes.
+    return WaitForSingleNonChildProcess(handle, wait);
+#else
+    // Currently on Linux we can't handle non child processes.
+    NOTIMPLEMENTED();
+#endif  // OS_MACOSX
+  }
+
+  bool waitpid_success;
+  int status = -1;
+  if (wait.InMilliseconds() == base::kNoTimeout) {
+    waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1);
+  } else {
+    status = WaitpidWithTimeout(
+        handle, wait.InMilliseconds(), &waitpid_success);
+  }
+
+  if (status != -1) {
+    DCHECK(waitpid_success);
+    return WIFEXITED(status);
+  } else {
+    return false;
+  }
+}
+
+int64 TimeValToMicroseconds(const struct timeval& tv) {
+  static const int kMicrosecondsPerSecond = 1000000;
+  int64 ret = tv.tv_sec;  // Avoid (int * int) integer overflow.
+  ret *= kMicrosecondsPerSecond;
+  ret += tv.tv_usec;
+  return ret;
+}
+
+// Return value used by GetAppOutputInternal to encapsulate the various exit
+// scenarios from the function.
+enum GetAppOutputInternalResult {
+  EXECUTE_FAILURE,
+  EXECUTE_SUCCESS,
+  GOT_MAX_OUTPUT,
+};
+
+// Executes the application specified by |argv| and wait for it to exit. Stores
+// the output (stdout) in |output|. If |do_search_path| is set, it searches the
+// path for the application; in that case, |envp| must be null, and it will use
+// the current environment. If |do_search_path| is false, |argv[0]| should fully
+// specify the path of the application, and |envp| will be used as the
+// environment. Redirects stderr to /dev/null.
+// If we successfully start the application and get all requested output, we
+// return GOT_MAX_OUTPUT, or if there is a problem starting or exiting
+// the application we return RUN_FAILURE. Otherwise we return EXECUTE_SUCCESS.
+// The GOT_MAX_OUTPUT return value exists so a caller that asks for limited
+// output can treat this as a success, despite having an exit code of SIG_PIPE
+// due to us closing the output pipe.
+// In the case of EXECUTE_SUCCESS, the application exit code will be returned
+// in |*exit_code|, which should be checked to determine if the application
+// ran successfully.
+static GetAppOutputInternalResult GetAppOutputInternal(
+    const std::vector<std::string>& argv,
+    char* const envp[],
+    std::string* output,
+    size_t max_output,
+    bool do_search_path,
+    int* exit_code) {
+  // Doing a blocking wait for another command to finish counts as IO.
+  base::ThreadRestrictions::AssertIOAllowed();
+  // exit_code must be supplied so calling function can determine success.
+  DCHECK(exit_code);
+  *exit_code = EXIT_FAILURE;
+
+  int pipe_fd[2];
+  pid_t pid;
+  InjectiveMultimap fd_shuffle1, fd_shuffle2;
+  scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
+
+  fd_shuffle1.reserve(3);
+  fd_shuffle2.reserve(3);
+
+  // Either |do_search_path| should be false or |envp| should be null, but not
+  // both.
+  DCHECK(!do_search_path ^ !envp);
+
+  if (pipe(pipe_fd) < 0)
+    return EXECUTE_FAILURE;
+
+  switch (pid = fork()) {
+    case -1:  // error
+      close(pipe_fd[0]);
+      close(pipe_fd[1]);
+      return EXECUTE_FAILURE;
+    case 0:  // child
+      {
+#if defined(OS_MACOSX)
+        RestoreDefaultExceptionHandler();
+#endif
+        // DANGER: no calls to malloc are allowed from now on:
+        // http://crbug.com/36678
+
+        // Obscure fork() rule: in the child, if you don't end up doing exec*(),
+        // you call _exit() instead of exit(). This is because _exit() does not
+        // call any previously-registered (in the parent) exit handlers, which
+        // might do things like block waiting for threads that don't even exist
+        // in the child.
+        int dev_null = open("/dev/null", O_WRONLY);
+        if (dev_null < 0)
+          _exit(127);
+
+        // Stop type-profiler.
+        // The profiler should be stopped between fork and exec since it inserts
+        // locks at new/delete expressions.  See http://crbug.com/36678.
+        base::type_profiler::Controller::Stop();
+
+        fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
+        fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true));
+        fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
+        // Adding another element here? Remeber to increase the argument to
+        // reserve(), above.
+
+        std::copy(fd_shuffle1.begin(), fd_shuffle1.end(),
+                  std::back_inserter(fd_shuffle2));
+
+        if (!ShuffleFileDescriptors(&fd_shuffle1))
+          _exit(127);
+
+        CloseSuperfluousFds(fd_shuffle2);
+
+        for (size_t i = 0; i < argv.size(); i++)
+          argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+        argv_cstr[argv.size()] = NULL;
+        if (do_search_path)
+          execvp(argv_cstr[0], argv_cstr.get());
+        else
+          execve(argv_cstr[0], argv_cstr.get(), envp);
+        _exit(127);
+      }
+    default:  // parent
+      {
+        // Close our writing end of pipe now. Otherwise later read would not
+        // be able to detect end of child's output (in theory we could still
+        // write to the pipe).
+        close(pipe_fd[1]);
+
+        output->clear();
+        char buffer[256];
+        size_t output_buf_left = max_output;
+        ssize_t bytes_read = 1;  // A lie to properly handle |max_output == 0|
+                                 // case in the logic below.
+
+        while (output_buf_left > 0) {
+          bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer,
+                                    std::min(output_buf_left, sizeof(buffer))));
+          if (bytes_read <= 0)
+            break;
+          output->append(buffer, bytes_read);
+          output_buf_left -= static_cast<size_t>(bytes_read);
+        }
+        close(pipe_fd[0]);
+
+        // Always wait for exit code (even if we know we'll declare
+        // GOT_MAX_OUTPUT).
+        bool success = WaitForExitCode(pid, exit_code);
+
+        // If we stopped because we read as much as we wanted, we return
+        // GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|).
+        if (!output_buf_left && bytes_read > 0)
+          return GOT_MAX_OUTPUT;
+        else if (success)
+          return EXECUTE_SUCCESS;
+        return EXECUTE_FAILURE;
+      }
+  }
+}
+
+bool GetAppOutput(const CommandLine& cl, std::string* output) {
+  return GetAppOutput(cl.argv(), output);
+}
+
+bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) {
+  // Run |execve()| with the current environment and store "unlimited" data.
+  int exit_code;
+  GetAppOutputInternalResult result = GetAppOutputInternal(
+      argv, NULL, output, std::numeric_limits<std::size_t>::max(), true,
+      &exit_code);
+  return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS;
+}
+
+// TODO(viettrungluu): Conceivably, we should have a timeout as well, so we
+// don't hang if what we're calling hangs.
+bool GetAppOutputRestricted(const CommandLine& cl,
+                            std::string* output, size_t max_output) {
+  // Run |execve()| with the empty environment.
+  char* const empty_environ = NULL;
+  int exit_code;
+  GetAppOutputInternalResult result = GetAppOutputInternal(
+      cl.argv(), &empty_environ, output, max_output, false, &exit_code);
+  return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS &&
+                                      exit_code == EXIT_SUCCESS);
+}
+
+bool GetAppOutputWithExitCode(const CommandLine& cl,
+                              std::string* output,
+                              int* exit_code) {
+  // Run |execve()| with the current environment and store "unlimited" data.
+  GetAppOutputInternalResult result = GetAppOutputInternal(
+      cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true,
+      exit_code);
+  return result == EXECUTE_SUCCESS;
+}
+
+bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
+                            base::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
+
+  base::Time end_time = base::Time::Now() + wait;
+  do {
+    NamedProcessIterator iter(executable_name, filter);
+    if (!iter.NextProcessEntry()) {
+      result = true;
+      break;
+    }
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  } while ((end_time - base::Time::Now()) > base::TimeDelta());
+
+  return result;
+}
+
+bool CleanupProcesses(const FilePath::StringType& executable_name,
+                      base::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:
+  virtual 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(ProcessHandle process) {
+  // If the child is already dead, then there's nothing to do.
+  if (IsChildDead(process))
+    return;
+
+  const unsigned timeout = 2;  // seconds
+  BackgroundReaper* reaper = new BackgroundReaper(process, timeout);
+  PlatformThread::CreateNonJoinable(0, reaper);
+}
+
+void EnsureProcessGetsReaped(ProcessHandle process) {
+  // If the child is already dead, then there's nothing to do.
+  if (IsChildDead(process))
+    return;
+
+  BackgroundReaper* reaper = new BackgroundReaper(process, 0);
+  PlatformThread::CreateNonJoinable(0, reaper);
+}
+
+#endif  // !defined(OS_MACOSX)
+
+}  // namespace base
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
new file mode 100644
index 0000000..0242479
--- /dev/null
+++ b/base/process_util_unittest.cc
@@ -0,0 +1,1202 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <limits>
+
+#include "base/command_line.h"
+#include "base/debug/alias.h"
+#include "base/debug/stack_trace.h"
+#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/platform_thread.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_LINUX)
+#include <malloc.h>
+#include <glib.h>
+#include <sched.h>
+#endif
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#endif
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#if defined(OS_MACOSX)
+#include <mach/vm_param.h>
+#include <malloc/malloc.h>
+#include "base/process_util_unittest_mac.h"
+#endif
+
+namespace {
+
+#if defined(OS_WIN)
+const wchar_t kProcessName[] = L"base_unittests.exe";
+#else
+const wchar_t kProcessName[] = L"base_unittests";
+#endif  // defined(OS_WIN)
+
+#if defined(OS_ANDROID)
+const char kShellPath[] = "/system/bin/sh";
+const char kPosixShell[] = "sh";
+#else
+const char kShellPath[] = "/bin/sh";
+const char kPosixShell[] = "bash";
+#endif
+
+const char kSignalFileSlow[] = "SlowChildProcess.die";
+const char kSignalFileCrash[] = "CrashingChildProcess.die";
+const char kSignalFileKill[] = "KilledChildProcess.die";
+
+#if defined(OS_WIN)
+const int kExpectedStillRunningExitCode = 0x102;
+const int kExpectedKilledExitCode = 1;
+#else
+const int kExpectedStillRunningExitCode = 0;
+#endif
+
+// Sleeps until file filename is created.
+void WaitToDie(const char* filename) {
+  FILE* fp;
+  do {
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+    fp = fopen(filename, "r");
+  } while (!fp);
+  fclose(fp);
+}
+
+// Signals children they should die now.
+void SignalChildren(const char* filename) {
+  FILE* fp = fopen(filename, "w");
+  fclose(fp);
+}
+
+// Using a pipe to the child to wait for an event was considered, but
+// there were cases in the past where pipes caused problems (other
+// libraries closing the fds, child deadlocking). This is a simple
+// case, so it's not worth the risk.  Using wait loops is discouraged
+// in most instances.
+base::TerminationStatus WaitForChildTermination(base::ProcessHandle handle,
+                                                int* exit_code) {
+  // Now we wait until the result is something other than STILL_RUNNING.
+  base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING;
+  const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(20);
+  base::TimeDelta waited;
+  do {
+    status = base::GetTerminationStatus(handle, exit_code);
+    base::PlatformThread::Sleep(kInterval);
+    waited += kInterval;
+  } while (status == base::TERMINATION_STATUS_STILL_RUNNING &&
+// Waiting for more time for process termination on android devices.
+#if defined(OS_ANDROID)
+           waited < TestTimeouts::large_test_timeout());
+#else
+           waited < TestTimeouts::action_max_timeout());
+#endif
+
+  return status;
+}
+
+}  // namespace
+
+class ProcessUtilTest : public base::MultiProcessTest {
+ public:
+#if defined(OS_POSIX)
+  // Spawn a child process that counts how many file descriptors are open.
+  int CountOpenFDsInChild();
+#endif
+  // Converts the filename to a platform specific filepath.
+  // On Android files can not be created in arbitrary directories.
+  static std::string GetSignalFilePath(const char* filename);
+};
+
+std::string ProcessUtilTest::GetSignalFilePath(const char* filename) {
+#if !defined(OS_ANDROID)
+  return filename;
+#else
+  FilePath tmp_dir;
+  PathService::Get(base::DIR_CACHE, &tmp_dir);
+  tmp_dir = tmp_dir.Append(filename);
+  return tmp_dir.value();
+#endif
+}
+
+MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
+  return 0;
+}
+
+TEST_F(ProcessUtilTest, SpawnChild) {
+  base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
+  ASSERT_NE(base::kNullProcessHandle, handle);
+  EXPECT_TRUE(base::WaitForSingleProcess(
+                  handle, TestTimeouts::action_max_timeout()));
+  base::CloseProcessHandle(handle);
+}
+
+MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileSlow).c_str());
+  return 0;
+}
+
+TEST_F(ProcessUtilTest, KillSlowChild) {
+  const std::string signal_file =
+      ProcessUtilTest::GetSignalFilePath(kSignalFileSlow);
+  remove(signal_file.c_str());
+  base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
+  ASSERT_NE(base::kNullProcessHandle, handle);
+  SignalChildren(signal_file.c_str());
+  EXPECT_TRUE(base::WaitForSingleProcess(
+                  handle, TestTimeouts::action_max_timeout()));
+  base::CloseProcessHandle(handle);
+  remove(signal_file.c_str());
+}
+
+// Times out on Linux and Win, flakes on other platforms, http://crbug.com/95058
+TEST_F(ProcessUtilTest, DISABLED_GetTerminationStatusExit) {
+  const std::string signal_file =
+      ProcessUtilTest::GetSignalFilePath(kSignalFileSlow);
+  remove(signal_file.c_str());
+  base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
+  ASSERT_NE(base::kNullProcessHandle, handle);
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(handle, &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(handle, &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status);
+  EXPECT_EQ(0, exit_code);
+  base::CloseProcessHandle(handle);
+  remove(signal_file.c_str());
+}
+
+#if defined(OS_WIN)
+// TODO(cpu): figure out how to test this in other platforms.
+TEST_F(ProcessUtilTest, GetProcId) {
+  base::ProcessId id1 = base::GetProcId(GetCurrentProcess());
+  EXPECT_NE(0ul, id1);
+  base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
+  ASSERT_NE(base::kNullProcessHandle, handle);
+  base::ProcessId id2 = base::GetProcId(handle);
+  EXPECT_NE(0ul, id2);
+  EXPECT_NE(id1, id2);
+  base::CloseProcessHandle(handle);
+}
+
+TEST_F(ProcessUtilTest, GetModuleFromAddress) {
+  // Since the unit tests are their own EXE, this should be
+  // equivalent to the EXE's HINSTANCE.
+  //
+  // kExpectedKilledExitCode is a constant in this file and
+  // therefore within the unit test EXE.
+  EXPECT_EQ(::GetModuleHandle(NULL),
+            base::GetModuleFromAddress(
+                const_cast<int*>(&kExpectedKilledExitCode)));
+
+  // Any address within the kernel32 module should return
+  // kernel32's HMODULE.  Our only assumption here is that
+  // kernel32 is larger than 4 bytes.
+  HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll");
+  HMODULE kernel32_from_address =
+      base::GetModuleFromAddress(reinterpret_cast<DWORD*>(kernel32) + 1);
+  EXPECT_EQ(kernel32, kernel32_from_address);
+}
+#endif
+
+#if !defined(OS_MACOSX)
+// This test is disabled on Mac, since it's flaky due to ReportCrash
+// taking a variable amount of time to parse and load the debug and
+// symbol data for this unit test's executable before firing the
+// signal handler.
+//
+// TODO(gspencer): turn this test process into a very small program
+// with no symbols (instead of using the multiprocess testing
+// framework) to reduce the ReportCrash overhead.
+
+MULTIPROCESS_TEST_MAIN(CrashingChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileCrash).c_str());
+#if defined(OS_POSIX)
+  // Have to disable to signal handler for segv so we can get a crash
+  // instead of an abnormal termination through the crash dump handler.
+  ::signal(SIGSEGV, SIG_DFL);
+#endif
+  // Make this process have a segmentation fault.
+  volatile int* oops = NULL;
+  *oops = 0xDEAD;
+  return 1;
+}
+
+// This test intentionally crashes, so we don't need to run it under
+// AddressSanitizer.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_GetTerminationStatusCrash DISABLED_GetTerminationStatusCrash
+#else
+#define MAYBE_GetTerminationStatusCrash GetTerminationStatusCrash
+#endif
+TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) {
+  const std::string signal_file =
+    ProcessUtilTest::GetSignalFilePath(kSignalFileCrash);
+  remove(signal_file.c_str());
+  base::ProcessHandle handle = this->SpawnChild("CrashingChildProcess",
+                                                false);
+  ASSERT_NE(base::kNullProcessHandle, handle);
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(handle, &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(handle, &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
+
+#if defined(OS_WIN)
+  EXPECT_EQ(0xc0000005, exit_code);
+#elif defined(OS_POSIX)
+  int signaled = WIFSIGNALED(exit_code);
+  EXPECT_NE(0, signaled);
+  int signal = WTERMSIG(exit_code);
+  EXPECT_EQ(SIGSEGV, signal);
+#endif
+  base::CloseProcessHandle(handle);
+
+  // Reset signal handlers back to "normal".
+  base::debug::EnableInProcessStackDumping();
+  remove(signal_file.c_str());
+}
+#endif  // !defined(OS_MACOSX)
+
+MULTIPROCESS_TEST_MAIN(KilledChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileKill).c_str());
+#if defined(OS_WIN)
+  // Kill ourselves.
+  HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId());
+  ::TerminateProcess(handle, kExpectedKilledExitCode);
+#elif defined(OS_POSIX)
+  // Send a SIGKILL to this process, just like the OOM killer would.
+  ::kill(getpid(), SIGKILL);
+#endif
+  return 1;
+}
+
+TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
+  const std::string signal_file =
+    ProcessUtilTest::GetSignalFilePath(kSignalFileKill);
+  remove(signal_file.c_str());
+  base::ProcessHandle handle = this->SpawnChild("KilledChildProcess",
+                                                false);
+  ASSERT_NE(base::kNullProcessHandle, handle);
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(handle, &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(handle, &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
+#if defined(OS_WIN)
+  EXPECT_EQ(kExpectedKilledExitCode, exit_code);
+#elif defined(OS_POSIX)
+  int signaled = WIFSIGNALED(exit_code);
+  EXPECT_NE(0, signaled);
+  int signal = WTERMSIG(exit_code);
+  EXPECT_EQ(SIGKILL, signal);
+#endif
+  base::CloseProcessHandle(handle);
+  remove(signal_file.c_str());
+}
+
+// Ensure that the priority of a process is restored correctly after
+// backgrounding and restoring.
+// Note: a platform may not be willing or able to lower the priority of
+// a process. The calls to SetProcessBackground should be noops then.
+TEST_F(ProcessUtilTest, SetProcessBackgrounded) {
+  base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
+  base::Process process(handle);
+  int old_priority = process.GetPriority();
+#if defined(OS_WIN)
+  EXPECT_TRUE(process.SetProcessBackgrounded(true));
+  EXPECT_TRUE(process.IsProcessBackgrounded());
+  EXPECT_TRUE(process.SetProcessBackgrounded(false));
+  EXPECT_FALSE(process.IsProcessBackgrounded());
+#else
+  process.SetProcessBackgrounded(true);
+  process.SetProcessBackgrounded(false);
+#endif
+  int new_priority = process.GetPriority();
+  EXPECT_EQ(old_priority, new_priority);
+}
+
+// Same as SetProcessBackgrounded but to this very process. It uses
+// a different code path at least for Windows.
+TEST_F(ProcessUtilTest, SetProcessBackgroundedSelf) {
+  base::Process process(base::Process::Current().handle());
+  int old_priority = process.GetPriority();
+#if defined(OS_WIN)
+  EXPECT_TRUE(process.SetProcessBackgrounded(true));
+  EXPECT_TRUE(process.IsProcessBackgrounded());
+  EXPECT_TRUE(process.SetProcessBackgrounded(false));
+  EXPECT_FALSE(process.IsProcessBackgrounded());
+#else
+  process.SetProcessBackgrounded(true);
+  process.SetProcessBackgrounded(false);
+#endif
+  int new_priority = process.GetPriority();
+  EXPECT_EQ(old_priority, new_priority);
+}
+
+// TODO(estade): if possible, port these 2 tests.
+#if defined(OS_WIN)
+TEST_F(ProcessUtilTest, EnableLFH) {
+  ASSERT_TRUE(base::EnableLowFragmentationHeap());
+  if (IsDebuggerPresent()) {
+    // Under these conditions, LFH can't be enabled. There's no point to test
+    // anything.
+    const char* no_debug_env = getenv("_NO_DEBUG_HEAP");
+    if (!no_debug_env || strcmp(no_debug_env, "1"))
+      return;
+  }
+  HANDLE heaps[1024] = { 0 };
+  unsigned number_heaps = GetProcessHeaps(1024, heaps);
+  EXPECT_GT(number_heaps, 0u);
+  for (unsigned i = 0; i < number_heaps; ++i) {
+    ULONG flag = 0;
+    SIZE_T length;
+    ASSERT_NE(0, HeapQueryInformation(heaps[i],
+                                      HeapCompatibilityInformation,
+                                      &flag,
+                                      sizeof(flag),
+                                      &length));
+    // If flag is 0, the heap is a standard heap that does not support
+    // look-asides. If flag is 1, the heap supports look-asides. If flag is 2,
+    // the heap is a low-fragmentation heap (LFH). Note that look-asides are not
+    // supported on the LFH.
+
+    // We don't have any documented way of querying the HEAP_NO_SERIALIZE flag.
+    EXPECT_LE(flag, 2u);
+    EXPECT_NE(flag, 1u);
+  }
+}
+
+TEST_F(ProcessUtilTest, CalcFreeMemory) {
+  scoped_ptr<base::ProcessMetrics> metrics(
+      base::ProcessMetrics::CreateProcessMetrics(::GetCurrentProcess()));
+  ASSERT_TRUE(NULL != metrics.get());
+
+  // Typical values here is ~1900 for total and ~1000 for largest. Obviously
+  // it depends in what other tests have done to this process.
+  base::FreeMBytes free_mem1 = {0};
+  EXPECT_TRUE(metrics->CalculateFreeMemory(&free_mem1));
+  EXPECT_LT(10u, free_mem1.total);
+  EXPECT_LT(10u, free_mem1.largest);
+  EXPECT_GT(2048u, free_mem1.total);
+  EXPECT_GT(2048u, free_mem1.largest);
+  EXPECT_GE(free_mem1.total, free_mem1.largest);
+  EXPECT_TRUE(NULL != free_mem1.largest_ptr);
+
+  // Allocate 20M and check again. It should have gone down.
+  const int kAllocMB = 20;
+  scoped_array<char> alloc(new char[kAllocMB * 1024 * 1024]);
+  size_t expected_total = free_mem1.total - kAllocMB;
+  size_t expected_largest = free_mem1.largest;
+
+  base::FreeMBytes free_mem2 = {0};
+  EXPECT_TRUE(metrics->CalculateFreeMemory(&free_mem2));
+  EXPECT_GE(free_mem2.total, free_mem2.largest);
+  EXPECT_GE(expected_total, free_mem2.total);
+  EXPECT_GE(expected_largest, free_mem2.largest);
+  EXPECT_TRUE(NULL != free_mem2.largest_ptr);
+}
+
+TEST_F(ProcessUtilTest, GetAppOutput) {
+  // Let's create a decently long message.
+  std::string message;
+  for (int i = 0; i < 1025; i++) {  // 1025 so it does not end on a kilo-byte
+                                    // boundary.
+    message += "Hello!";
+  }
+  // cmd.exe's echo always adds a \r\n to its output.
+  std::string expected(message);
+  expected += "\r\n";
+
+  FilePath cmd(L"cmd.exe");
+  CommandLine cmd_line(cmd);
+  cmd_line.AppendArg("/c");
+  cmd_line.AppendArg("echo " + message + "");
+  std::string output;
+  ASSERT_TRUE(base::GetAppOutput(cmd_line, &output));
+  EXPECT_EQ(expected, output);
+
+  // Let's make sure stderr is ignored.
+  CommandLine other_cmd_line(cmd);
+  other_cmd_line.AppendArg("/c");
+  // http://msdn.microsoft.com/library/cc772622.aspx
+  cmd_line.AppendArg("echo " + message + " >&2");
+  output.clear();
+  ASSERT_TRUE(base::GetAppOutput(other_cmd_line, &output));
+  EXPECT_EQ("", output);
+}
+
+TEST_F(ProcessUtilTest, LaunchAsUser) {
+  base::UserTokenHandle token;
+  ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token));
+  std::wstring cmdline =
+      this->MakeCmdLine("SimpleChildProcess", false).GetCommandLineString();
+  base::LaunchOptions options;
+  options.as_user = token;
+  EXPECT_TRUE(base::LaunchProcess(cmdline, options, NULL));
+}
+
+#endif  // defined(OS_WIN)
+
+#if defined(OS_MACOSX)
+
+// For the following Mac tests:
+// Note that base::EnableTerminationOnHeapCorruption() is called as part of
+// test suite setup and does not need to be done again, else mach_override
+// will fail.
+
+#if !defined(ADDRESS_SANITIZER)
+// The following code tests the system implementation of malloc() thus no need
+// to test it under AddressSanitizer.
+TEST_F(ProcessUtilTest, MacMallocFailureDoesNotTerminate) {
+  // Install the OOM killer.
+  base::EnableTerminationOnOutOfMemory();
+
+  // Test that ENOMEM doesn't crash via CrMallocErrorBreak two ways: the exit
+  // code and lack of the error string. The number of bytes is one less than
+  // MALLOC_ABSOLUTE_MAX_SIZE, more than which the system early-returns NULL and
+  // does not call through malloc_error_break(). See the comment at
+  // EnableTerminationOnOutOfMemory() for more information.
+  void* buf = NULL;
+  ASSERT_EXIT(
+      buf = malloc(std::numeric_limits<size_t>::max() - (2 * PAGE_SIZE) - 1),
+      testing::KilledBySignal(SIGTRAP),
+      "\\*\\*\\* error: can't allocate region.*"
+          "(Terminating process due to a potential for future heap "
+          "corruption){0}");
+
+  base::debug::Alias(buf);
+}
+#endif  // !defined(ADDRESS_SANITIZER)
+
+TEST_F(ProcessUtilTest, MacTerminateOnHeapCorruption) {
+  // Assert that freeing an unallocated pointer will crash the process.
+  char buf[3];
+  asm("" : "=r" (buf));  // Prevent clang from being too smart.
+#if !defined(ADDRESS_SANITIZER)
+  ASSERT_DEATH(free(buf), "being freed.*"
+      "\\*\\*\\* set a breakpoint in malloc_error_break to debug.*"
+      "Terminating process due to a potential for future heap corruption");
+#else
+  // AddressSanitizer replaces malloc() and prints a different error message on
+  // heap corruption.
+  ASSERT_DEATH(free(buf), "attempting free on address which "
+      "was not malloc\\(\\)-ed");
+#endif  // !defined(ADDRESS_SANITIZER)
+}
+
+#endif  // defined(OS_MACOSX)
+
+#if defined(OS_POSIX)
+
+namespace {
+
+// Returns the maximum number of files that a process can have open.
+// Returns 0 on error.
+int GetMaxFilesOpenInProcess() {
+  struct rlimit rlim;
+  if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+    return 0;
+  }
+
+  // rlim_t is a uint64 - clip to maxint. We do this since FD #s are ints
+  // which are all 32 bits on the supported platforms.
+  rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32>::max());
+  if (rlim.rlim_cur > max_int) {
+    return max_int;
+  }
+
+  return rlim.rlim_cur;
+}
+
+const int kChildPipe = 20;  // FD # for write end of pipe in child process.
+
+}  // namespace
+
+MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess) {
+  // This child process counts the number of open FDs, it then writes that
+  // number out to a pipe connected to the parent.
+  int num_open_files = 0;
+  int write_pipe = kChildPipe;
+  int max_files = GetMaxFilesOpenInProcess();
+  for (int i = STDERR_FILENO + 1; i < max_files; i++) {
+    if (i != kChildPipe) {
+      int fd;
+      if ((fd = HANDLE_EINTR(dup(i))) != -1) {
+        close(fd);
+        num_open_files += 1;
+      }
+    }
+  }
+
+  int written = HANDLE_EINTR(write(write_pipe, &num_open_files,
+                                   sizeof(num_open_files)));
+  DCHECK_EQ(static_cast<size_t>(written), sizeof(num_open_files));
+  int ret = HANDLE_EINTR(close(write_pipe));
+  DPCHECK(ret == 0);
+
+  return 0;
+}
+
+int ProcessUtilTest::CountOpenFDsInChild() {
+  int fds[2];
+  if (pipe(fds) < 0)
+    NOTREACHED();
+
+  base::FileHandleMappingVector fd_mapping_vec;
+  fd_mapping_vec.push_back(std::pair<int, int>(fds[1], kChildPipe));
+  base::ProcessHandle handle = this->SpawnChild(
+      "ProcessUtilsLeakFDChildProcess", fd_mapping_vec, false);
+  CHECK(handle);
+  int ret = HANDLE_EINTR(close(fds[1]));
+  DPCHECK(ret == 0);
+
+  // Read number of open files in client process from pipe;
+  int num_open_files = -1;
+  ssize_t bytes_read =
+      HANDLE_EINTR(read(fds[0], &num_open_files, sizeof(num_open_files)));
+  CHECK_EQ(bytes_read, static_cast<ssize_t>(sizeof(num_open_files)));
+
+#if defined(THREAD_SANITIZER)
+  // Compiler-based ThreadSanitizer makes this test slow.
+  CHECK(base::WaitForSingleProcess(handle, base::TimeDelta::FromSeconds(3)));
+#else
+  CHECK(base::WaitForSingleProcess(handle, base::TimeDelta::FromSeconds(1)));
+#endif
+  base::CloseProcessHandle(handle);
+  ret = HANDLE_EINTR(close(fds[0]));
+  DPCHECK(ret == 0);
+
+  return num_open_files;
+}
+
+TEST_F(ProcessUtilTest, FDRemapping) {
+  int fds_before = CountOpenFDsInChild();
+
+  // open some dummy fds to make sure they don't propagate over to the
+  // child process.
+  int dev_null = open("/dev/null", O_RDONLY);
+  int sockets[2];
+  socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
+
+  int fds_after = CountOpenFDsInChild();
+
+  ASSERT_EQ(fds_after, fds_before);
+
+  int ret;
+  ret = HANDLE_EINTR(close(sockets[0]));
+  DPCHECK(ret == 0);
+  ret = HANDLE_EINTR(close(sockets[1]));
+  DPCHECK(ret == 0);
+  ret = HANDLE_EINTR(close(dev_null));
+  DPCHECK(ret == 0);
+}
+
+namespace {
+
+std::string TestLaunchProcess(const base::EnvironmentVector& env_changes,
+                              const int clone_flags) {
+  std::vector<std::string> args;
+  base::FileHandleMappingVector fds_to_remap;
+
+  args.push_back(kPosixShell);
+  args.push_back("-c");
+  args.push_back("echo $BASE_TEST");
+
+  int fds[2];
+  PCHECK(pipe(fds) == 0);
+
+  fds_to_remap.push_back(std::make_pair(fds[1], 1));
+  base::LaunchOptions options;
+  options.wait = true;
+  options.environ = &env_changes;
+  options.fds_to_remap = &fds_to_remap;
+#if defined(OS_LINUX)
+  options.clone_flags = clone_flags;
+#else
+  CHECK_EQ(0, clone_flags);
+#endif  // OS_LINUX
+  EXPECT_TRUE(base::LaunchProcess(args, options, NULL));
+  PCHECK(HANDLE_EINTR(close(fds[1])) == 0);
+
+  char buf[512];
+  const ssize_t n = HANDLE_EINTR(read(fds[0], buf, sizeof(buf)));
+  PCHECK(n > 0);
+
+  PCHECK(HANDLE_EINTR(close(fds[0])) == 0);
+
+  return std::string(buf, n);
+}
+
+const char kLargeString[] =
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789";
+
+}  // namespace
+
+TEST_F(ProcessUtilTest, LaunchProcess) {
+  base::EnvironmentVector env_changes;
+  const int no_clone_flags = 0;
+
+  env_changes.push_back(std::make_pair(std::string("BASE_TEST"),
+                                       std::string("bar")));
+  EXPECT_EQ("bar\n", TestLaunchProcess(env_changes, no_clone_flags));
+  env_changes.clear();
+
+  EXPECT_EQ(0, setenv("BASE_TEST", "testing", 1 /* override */));
+  EXPECT_EQ("testing\n", TestLaunchProcess(env_changes, no_clone_flags));
+
+  env_changes.push_back(std::make_pair(std::string("BASE_TEST"),
+                                       std::string("")));
+  EXPECT_EQ("\n", TestLaunchProcess(env_changes, no_clone_flags));
+
+  env_changes[0].second = "foo";
+  EXPECT_EQ("foo\n", TestLaunchProcess(env_changes, no_clone_flags));
+
+  env_changes.clear();
+  EXPECT_EQ(0, setenv("BASE_TEST", kLargeString, 1 /* override */));
+  EXPECT_EQ(std::string(kLargeString) + "\n",
+            TestLaunchProcess(env_changes, no_clone_flags));
+
+  env_changes.push_back(std::make_pair(std::string("BASE_TEST"),
+                                       std::string("wibble")));
+  EXPECT_EQ("wibble\n", TestLaunchProcess(env_changes, no_clone_flags));
+
+#if defined(OS_LINUX)
+  // Test a non-trival value for clone_flags.
+  // Don't test on Valgrind as it has limited support for clone().
+  if (!RunningOnValgrind()) {
+    EXPECT_EQ("wibble\n", TestLaunchProcess(env_changes, CLONE_FS | SIGCHLD));
+  }
+#endif
+}
+
+TEST_F(ProcessUtilTest, AlterEnvironment) {
+  const char* const empty[] = { NULL };
+  const char* const a2[] = { "A=2", NULL };
+  base::EnvironmentVector changes;
+  char** e;
+
+  e = base::AlterEnvironment(changes, empty);
+  EXPECT_TRUE(e[0] == NULL);
+  delete[] e;
+
+  changes.push_back(std::make_pair(std::string("A"), std::string("1")));
+  e = base::AlterEnvironment(changes, empty);
+  EXPECT_EQ(std::string("A=1"), e[0]);
+  EXPECT_TRUE(e[1] == NULL);
+  delete[] e;
+
+  changes.clear();
+  changes.push_back(std::make_pair(std::string("A"), std::string("")));
+  e = base::AlterEnvironment(changes, empty);
+  EXPECT_TRUE(e[0] == NULL);
+  delete[] e;
+
+  changes.clear();
+  e = base::AlterEnvironment(changes, a2);
+  EXPECT_EQ(std::string("A=2"), e[0]);
+  EXPECT_TRUE(e[1] == NULL);
+  delete[] e;
+
+  changes.clear();
+  changes.push_back(std::make_pair(std::string("A"), std::string("1")));
+  e = base::AlterEnvironment(changes, a2);
+  EXPECT_EQ(std::string("A=1"), e[0]);
+  EXPECT_TRUE(e[1] == NULL);
+  delete[] e;
+
+  changes.clear();
+  changes.push_back(std::make_pair(std::string("A"), std::string("")));
+  e = base::AlterEnvironment(changes, a2);
+  EXPECT_TRUE(e[0] == NULL);
+  delete[] e;
+}
+
+TEST_F(ProcessUtilTest, GetAppOutput) {
+  std::string output;
+
+#if defined(OS_ANDROID)
+  std::vector<std::string> argv;
+  argv.push_back("sh");  // Instead of /bin/sh, force path search to find it.
+  argv.push_back("-c");
+
+  argv.push_back("exit 0");
+  EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output));
+  EXPECT_STREQ("", output.c_str());
+
+  argv[2] = "exit 1";
+  EXPECT_FALSE(base::GetAppOutput(CommandLine(argv), &output));
+  EXPECT_STREQ("", output.c_str());
+
+  argv[2] = "echo foobar42";
+  EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output));
+  EXPECT_STREQ("foobar42\n", output.c_str());
+#else
+  EXPECT_TRUE(base::GetAppOutput(CommandLine(FilePath("true")), &output));
+  EXPECT_STREQ("", output.c_str());
+
+  EXPECT_FALSE(base::GetAppOutput(CommandLine(FilePath("false")), &output));
+
+  std::vector<std::string> argv;
+  argv.push_back("/bin/echo");
+  argv.push_back("-n");
+  argv.push_back("foobar42");
+  EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output));
+  EXPECT_STREQ("foobar42", output.c_str());
+#endif  // defined(OS_ANDROID)
+}
+
+TEST_F(ProcessUtilTest, GetAppOutputRestricted) {
+  // Unfortunately, since we can't rely on the path, we need to know where
+  // everything is. So let's use /bin/sh, which is on every POSIX system, and
+  // its built-ins.
+  std::vector<std::string> argv;
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");  // argv[1]
+
+  // On success, should set |output|. We use |/bin/sh -c 'exit 0'| instead of
+  // |true| since the location of the latter may be |/bin| or |/usr/bin| (and we
+  // need absolute paths).
+  argv.push_back("exit 0");   // argv[2]; equivalent to "true"
+  std::string output = "abc";
+  EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 100));
+  EXPECT_STREQ("", output.c_str());
+
+  argv[2] = "exit 1";  // equivalent to "false"
+  output = "before";
+  EXPECT_FALSE(base::GetAppOutputRestricted(CommandLine(argv),
+                                            &output, 100));
+  EXPECT_STREQ("", output.c_str());
+
+  // Amount of output exactly equal to space allowed.
+  argv[2] = "echo 123456789";  // (the sh built-in doesn't take "-n")
+  output.clear();
+  EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
+  EXPECT_STREQ("123456789\n", output.c_str());
+
+  // Amount of output greater than space allowed.
+  output.clear();
+  EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 5));
+  EXPECT_STREQ("12345", output.c_str());
+
+  // Amount of output less than space allowed.
+  output.clear();
+  EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 15));
+  EXPECT_STREQ("123456789\n", output.c_str());
+
+  // Zero space allowed.
+  output = "abc";
+  EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 0));
+  EXPECT_STREQ("", output.c_str());
+}
+
+#if !defined(OS_MACOSX) && !defined(OS_OPENBSD)
+// TODO(benwells): GetAppOutputRestricted should terminate applications
+// with SIGPIPE when we have enough output. http://crbug.com/88502
+TEST_F(ProcessUtilTest, GetAppOutputRestrictedSIGPIPE) {
+  std::vector<std::string> argv;
+  std::string output;
+
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");
+#if defined(OS_ANDROID)
+  argv.push_back("while echo 12345678901234567890; do :; done");
+  EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
+  EXPECT_STREQ("1234567890", output.c_str());
+#else
+  argv.push_back("yes");
+  EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
+  EXPECT_STREQ("y\ny\ny\ny\ny\n", output.c_str());
+#endif
+}
+#endif
+
+TEST_F(ProcessUtilTest, GetAppOutputRestrictedNoZombies) {
+  std::vector<std::string> argv;
+
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");  // argv[1]
+  argv.push_back("echo 123456789012345678901234567890");  // argv[2]
+
+  // Run |GetAppOutputRestricted()| 300 (> default per-user processes on Mac OS
+  // 10.5) times with an output buffer big enough to capture all output.
+  for (int i = 0; i < 300; i++) {
+    std::string output;
+    EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 100));
+    EXPECT_STREQ("123456789012345678901234567890\n", output.c_str());
+  }
+
+  // Ditto, but with an output buffer too small to capture all output.
+  for (int i = 0; i < 300; i++) {
+    std::string output;
+    EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
+    EXPECT_STREQ("1234567890", output.c_str());
+  }
+}
+
+TEST_F(ProcessUtilTest, GetAppOutputWithExitCode) {
+  // Test getting output from a successful application.
+  std::vector<std::string> argv;
+  std::string output;
+  int exit_code;
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");  // argv[1]
+  argv.push_back("echo foo");  // argv[2];
+  EXPECT_TRUE(base::GetAppOutputWithExitCode(CommandLine(argv), &output,
+                                             &exit_code));
+  EXPECT_STREQ("foo\n", output.c_str());
+  EXPECT_EQ(exit_code, 0);
+
+  // Test getting output from an application which fails with a specific exit
+  // code.
+  output.clear();
+  argv[2] = "echo foo; exit 2";
+  EXPECT_TRUE(base::GetAppOutputWithExitCode(CommandLine(argv), &output,
+                                             &exit_code));
+  EXPECT_STREQ("foo\n", output.c_str());
+  EXPECT_EQ(exit_code, 2);
+}
+
+TEST_F(ProcessUtilTest, GetParentProcessId) {
+  base::ProcessId ppid = base::GetParentProcessId(base::GetCurrentProcId());
+  EXPECT_EQ(ppid, getppid());
+}
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+TEST_F(ProcessUtilTest, ParseProcStatCPU) {
+  // /proc/self/stat for a process running "top".
+  const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 "
+      "4202496 471 0 0 0 "
+      "12 16 0 0 "  // <- These are the goods.
+      "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 "
+      "4246868 140733983044336 18446744073709551615 140244213071219 "
+      "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0";
+  EXPECT_EQ(12 + 16, base::ParseProcStatCPU(kTopStat));
+
+  // cat /proc/self/stat on a random other machine I have.
+  const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 "
+      "0 142 0 0 0 "
+      "0 0 0 0 "  // <- No CPU, apparently.
+      "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 "
+      "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0";
+
+  EXPECT_EQ(0, base::ParseProcStatCPU(kSelfStat));
+}
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+// TODO(port): port those unit tests.
+bool IsProcessDead(base::ProcessHandle child) {
+  // waitpid() will actually reap the process which is exactly NOT what we
+  // want to test for.  The good thing is that if it can't find the process
+  // we'll get a nice value for errno which we can test for.
+  const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
+  return result == -1 && errno == ECHILD;
+}
+
+TEST_F(ProcessUtilTest, DelayedTermination) {
+  base::ProcessHandle child_process =
+      SpawnChild("process_util_test_never_die", false);
+  ASSERT_TRUE(child_process);
+  base::EnsureProcessTerminated(child_process);
+  base::WaitForSingleProcess(child_process, base::TimeDelta::FromSeconds(5));
+
+  // Check that process was really killed.
+  EXPECT_TRUE(IsProcessDead(child_process));
+  base::CloseProcessHandle(child_process);
+}
+
+MULTIPROCESS_TEST_MAIN(process_util_test_never_die) {
+  while (1) {
+    sleep(500);
+  }
+  return 0;
+}
+
+TEST_F(ProcessUtilTest, ImmediateTermination) {
+  base::ProcessHandle child_process =
+      SpawnChild("process_util_test_die_immediately", false);
+  ASSERT_TRUE(child_process);
+  // Give it time to die.
+  sleep(2);
+  base::EnsureProcessTerminated(child_process);
+
+  // Check that process was really killed.
+  EXPECT_TRUE(IsProcessDead(child_process));
+  base::CloseProcessHandle(child_process);
+}
+
+MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) {
+  return 0;
+}
+
+#endif  // defined(OS_POSIX)
+
+// Android doesn't implement set_new_handler, so we can't use the
+// OutOfMemoryTest cases.
+// OpenBSD does not support these tests either.
+// AddressSanitizer defines the malloc()/free()/etc. functions so that they
+// don't crash if the program is out of memory, so the OOM tests aren't supposed
+// to work.
+// TODO(vandebo) make this work on Windows too.
+#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && \
+    !defined(OS_WIN) && !defined(ADDRESS_SANITIZER)
+
+#if defined(USE_TCMALLOC)
+extern "C" {
+int tc_set_new_mode(int mode);
+}
+#endif  // defined(USE_TCMALLOC)
+
+class OutOfMemoryDeathTest : public testing::Test {
+ public:
+  OutOfMemoryDeathTest()
+      : value_(NULL),
+        // Make test size as large as possible minus a few pages so
+        // that alignment or other rounding doesn't make it wrap.
+        test_size_(std::numeric_limits<std::size_t>::max() - 12 * 1024),
+        signed_test_size_(std::numeric_limits<ssize_t>::max()) {
+  }
+
+#if defined(USE_TCMALLOC)
+  virtual void SetUp() OVERRIDE {
+    tc_set_new_mode(1);
+  }
+
+  virtual void TearDown() OVERRIDE {
+    tc_set_new_mode(0);
+  }
+#endif  // defined(USE_TCMALLOC)
+
+  void SetUpInDeathAssert() {
+    // Must call EnableTerminationOnOutOfMemory() because that is called from
+    // chrome's main function and therefore hasn't been called yet.
+    // Since this call may result in another thread being created and death
+    // tests shouldn't be started in a multithread environment, this call
+    // should be done inside of the ASSERT_DEATH.
+    base::EnableTerminationOnOutOfMemory();
+  }
+
+  void* value_;
+  size_t test_size_;
+  ssize_t signed_test_size_;
+};
+
+TEST_F(OutOfMemoryDeathTest, New) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = operator new(test_size_);
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, NewArray) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = new char[test_size_];
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, Malloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc(test_size_);
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, Realloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = realloc(NULL, test_size_);
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, Calloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = calloc(1024, test_size_ / 1024L);
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, Valloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = valloc(test_size_);
+    }, "");
+}
+
+#if defined(OS_LINUX)
+TEST_F(OutOfMemoryDeathTest, Pvalloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = pvalloc(test_size_);
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, Memalign) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = memalign(4, test_size_);
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, ViaSharedLibraries) {
+  // g_try_malloc is documented to return NULL on failure. (g_malloc is the
+  // 'safe' default that crashes if allocation fails). However, since we have
+  // hopefully overridden malloc, even g_try_malloc should fail. This tests
+  // that the run-time symbol resolution is overriding malloc for shared
+  // libraries as well as for our code.
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = g_try_malloc(test_size_);
+    }, "");
+}
+#endif  // OS_LINUX
+
+// Android doesn't implement posix_memalign().
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+TEST_F(OutOfMemoryDeathTest, Posix_memalign) {
+  // Grab the return value of posix_memalign to silence a compiler warning
+  // about unused return values. We don't actually care about the return
+  // value, since we're asserting death.
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_));
+    }, "");
+}
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+#if defined(OS_MACOSX)
+
+// Purgeable zone tests
+
+TEST_F(OutOfMemoryDeathTest, MallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_malloc(zone, test_size_);
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_realloc(zone, NULL, test_size_);
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, CallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L);
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, VallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_valloc(zone, test_size_);
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_memalign(zone, 8, test_size_);
+    }, "");
+}
+
+// Since these allocation functions take a signed size, it's possible that
+// calling them just once won't be enough to exhaust memory. In the 32-bit
+// environment, it's likely that these allocation attempts will fail because
+// not enough contiguous address space is available. In the 64-bit environment,
+// it's likely that they'll fail because they would require a preposterous
+// amount of (virtual) memory.
+
+TEST_F(OutOfMemoryDeathTest, CFAllocatorSystemDefault) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ =
+              base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {}
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ =
+              base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {}
+    }, "");
+}
+
+TEST_F(OutOfMemoryDeathTest, CFAllocatorMallocZone) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ =
+              base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {}
+    }, "");
+}
+
+#if !defined(ARCH_CPU_64_BITS)
+
+// See process_util_unittest_mac.mm for an explanation of why this test isn't
+// run in the 64-bit environment.
+
+TEST_F(OutOfMemoryDeathTest, PsychoticallyBigObjCObject) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {}
+    }, "");
+}
+
+#endif  // !ARCH_CPU_64_BITS
+#endif  // OS_MACOSX
+
+#endif  // !defined(OS_ANDROID) && !defined(OS_OPENBSD) &&
+        // !defined(OS_WIN) && !defined(ADDRESS_SANITIZER)
diff --git a/base/process_util_unittest_ios.cc b/base/process_util_unittest_ios.cc
new file mode 100644
index 0000000..c82535d
--- /dev/null
+++ b/base/process_util_unittest_ios.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/memory/scoped_ptr.h"
+#include "base/process_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ProcessUtilTestIos, Memory) {
+  scoped_ptr<base::ProcessMetrics> process_metrics(
+      base::ProcessMetrics::CreateProcessMetrics(
+          base::GetCurrentProcessHandle()));
+
+  ASSERT_NE(0u, process_metrics->GetWorkingSetSize());
+}
diff --git a/base/process_util_unittest_mac.h b/base/process_util_unittest_mac.h
new file mode 100644
index 0000000..7b4fe1c
--- /dev/null
+++ b/base/process_util_unittest_mac.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains helpers for the process_util_unittest to allow it to fully
+// test the Mac code.
+
+#ifndef BASE_PROCESS_UTIL_UNITTEST_MAC_H_
+#define BASE_PROCESS_UTIL_UNITTEST_MAC_H_
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Allocates memory via system allocators. Alas, they take a _signed_ size for
+// allocation.
+void* AllocateViaCFAllocatorSystemDefault(ssize_t size);
+void* AllocateViaCFAllocatorMalloc(ssize_t size);
+void* AllocateViaCFAllocatorMallocZone(ssize_t size);
+
+#if !defined(ARCH_CPU_64_BITS)
+// See process_util_unittest_mac.mm for an explanation of why this function
+// isn't implemented for the 64-bit environment.
+
+// Allocates a huge Objective C object.
+void* AllocatePsychoticallyBigObjCObject();
+
+#endif  // !ARCH_CPU_64_BITS
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_UTIL_UNITTEST_MAC_H_
diff --git a/base/process_util_unittest_mac.mm b/base/process_util_unittest_mac.mm
new file mode 100644
index 0000000..2ef1868
--- /dev/null
+++ b/base/process_util_unittest_mac.mm
@@ -0,0 +1,59 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process_util_unittest_mac.h"
+
+#import <Foundation/Foundation.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#if !defined(ARCH_CPU_64_BITS)
+
+// In the 64-bit environment, the Objective-C 2.0 Runtime Reference states
+// that sizeof(anInstance) is constrained to 32 bits. That's not necessarily
+// "psychotically big" and in fact a 64-bit program is expected to be able to
+// successfully allocate an object that large, likely reserving a good deal of
+// swap space. The only way to test the behavior of memory exhaustion for
+// Objective-C allocation in this environment would be to loop over allocation
+// of these large objects, but that would slowly consume all available memory
+// and cause swap file proliferation. That's bad, so this behavior isn't
+// tested in the 64-bit environment.
+
+@interface PsychoticallyBigObjCObject : NSObject
+{
+  // In the 32-bit environment, the compiler limits Objective-C objects to
+  // < 2GB in size.
+  int justUnder2Gigs_[(2U * 1024 * 1024 * 1024 - 1) / sizeof(int)];
+}
+
+@end
+
+@implementation PsychoticallyBigObjCObject
+
+@end
+
+namespace base {
+
+void* AllocatePsychoticallyBigObjCObject() {
+  return [[PsychoticallyBigObjCObject alloc] init];
+}
+
+}  // namespace base
+
+#endif  // ARCH_CPU_64_BITS
+
+namespace base {
+
+void* AllocateViaCFAllocatorSystemDefault(ssize_t size) {
+  return CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0);
+}
+
+void* AllocateViaCFAllocatorMalloc(ssize_t size) {
+  return CFAllocatorAllocate(kCFAllocatorMalloc, size, 0);
+}
+
+void* AllocateViaCFAllocatorMallocZone(ssize_t size) {
+  return CFAllocatorAllocate(kCFAllocatorMallocZone, size, 0);
+}
+
+}  // namespace base
diff --git a/base/process_util_win.cc b/base/process_util_win.cc
new file mode 100644
index 0000000..a1a55ea
--- /dev/null
+++ b/base/process_util_win.cc
@@ -0,0 +1,982 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_util.h"
+
+#include <fcntl.h>
+#include <io.h>
+#include <windows.h>
+#include <userenv.h>
+#include <psapi.h>
+
+#include <ios>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/sys_info.h"
+#include "base/win/object_watcher.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/windows_version.h"
+
+// userenv.dll is required for CreateEnvironmentBlock().
+#pragma comment(lib, "userenv.lib")
+
+namespace base {
+
+namespace {
+
+// System pagesize. This value remains constant on x86/64 architectures.
+const int PAGESIZE_KB = 4;
+
+// Exit codes with special meanings on Windows.
+const DWORD kNormalTerminationExitCode = 0;
+const DWORD kDebuggerInactiveExitCode = 0xC0000354;
+const DWORD kKeyboardInterruptExitCode = 0xC000013A;
+const DWORD kDebuggerTerminatedExitCode = 0x40010004;
+
+// Maximum amount of time (in milliseconds) to wait for the process to exit.
+static const int kWaitInterval = 2000;
+
+// This exit code is used by the Windows task manager when it kills a
+// process.  It's value is obviously not that unique, and it's
+// surprising to me that the task manager uses this value, but it
+// seems to be common practice on Windows to test for it as an
+// indication that the task manager has killed something if the
+// process goes away.
+const DWORD kProcessKilledExitCode = 1;
+
+// HeapSetInformation function pointer.
+typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
+
+void OnNoMemory() {
+  // Kill the process. This is important for security, since WebKit doesn't
+  // NULL-check many memory allocations. If a malloc fails, returns NULL, and
+  // the buffer is then used, it provides a handy mapping of memory starting at
+  // address 0 for an attacker to utilize.
+  __debugbreak();
+  _exit(1);
+}
+
+class TimerExpiredTask : public win::ObjectWatcher::Delegate {
+ public:
+  explicit TimerExpiredTask(ProcessHandle process);
+  ~TimerExpiredTask();
+
+  void TimedOut();
+
+  // MessageLoop::Watcher -----------------------------------------------------
+  virtual void OnObjectSignaled(HANDLE object);
+
+ private:
+  void KillProcess();
+
+  // The process that we are watching.
+  ProcessHandle process_;
+
+  win::ObjectWatcher watcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
+};
+
+TimerExpiredTask::TimerExpiredTask(ProcessHandle process) : process_(process) {
+  watcher_.StartWatching(process_, this);
+}
+
+TimerExpiredTask::~TimerExpiredTask() {
+  TimedOut();
+  DCHECK(!process_) << "Make sure to close the handle.";
+}
+
+void TimerExpiredTask::TimedOut() {
+  if (process_)
+    KillProcess();
+}
+
+void TimerExpiredTask::OnObjectSignaled(HANDLE object) {
+  CloseHandle(process_);
+  process_ = NULL;
+}
+
+void TimerExpiredTask::KillProcess() {
+  // Stop watching the process handle since we're killing it.
+  watcher_.StopWatching();
+
+  // OK, time to get frisky.  We don't actually care when the process
+  // terminates.  We just care that it eventually terminates, and that's what
+  // TerminateProcess should do for us. Don't check for the result code since
+  // it fails quite often. This should be investigated eventually.
+  base::KillProcess(process_, kProcessKilledExitCode, false);
+
+  // Now, just cleanup as if the process exited normally.
+  OnObjectSignaled(process_);
+}
+
+}  // namespace
+
+void RouteStdioToConsole() {
+  if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
+    unsigned int result = GetLastError();
+    // Was probably already attached.
+    if (result == ERROR_ACCESS_DENIED)
+      return;
+    // Don't bother creating a new console for each child process if the
+    // parent process is invalid (eg: crashed).
+    if (result == ERROR_GEN_FAILURE)
+      return;
+    // Make a new console if attaching to parent fails with any other error.
+    // It should be ERROR_INVALID_HANDLE at this point, which means the browser
+    // was likely not started from a console.
+    AllocConsole();
+  }
+
+  // Arbitrary byte count to use when buffering output lines.  More
+  // means potential waste, less means more risk of interleaved
+  // log-lines in output.
+  enum { kOutputBufferSize = 64 * 1024 };
+
+  if (freopen("CONOUT$", "w", stdout))
+    setvbuf(stdout, NULL, _IOLBF, kOutputBufferSize);
+  if (freopen("CONOUT$", "w", stderr))
+    setvbuf(stderr, NULL, _IOLBF, kOutputBufferSize);
+
+  // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog.
+  std::ios::sync_with_stdio();
+}
+
+ProcessId GetCurrentProcId() {
+  return ::GetCurrentProcessId();
+}
+
+ProcessHandle GetCurrentProcessHandle() {
+  return ::GetCurrentProcess();
+}
+
+HMODULE GetModuleFromAddress(void* address) {
+  HMODULE instance = NULL;
+  if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                            GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                            static_cast<char*>(address),
+                            &instance)) {
+    NOTREACHED();
+  }
+  return instance;
+}
+
+bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
+  // We try to limit privileges granted to the handle. If you need this
+  // for test code, consider using OpenPrivilegedProcessHandle instead of
+  // adding more privileges here.
+  ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_TERMINATE,
+                                     FALSE, pid);
+
+  if (result == NULL)
+    return false;
+
+  *handle = result;
+  return true;
+}
+
+bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
+  ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
+                                     PROCESS_TERMINATE |
+                                     PROCESS_QUERY_INFORMATION |
+                                     PROCESS_VM_READ |
+                                     SYNCHRONIZE,
+                                     FALSE, pid);
+
+  if (result == NULL)
+    return false;
+
+  *handle = result;
+  return true;
+}
+
+bool OpenProcessHandleWithAccess(ProcessId pid,
+                                 uint32 access_flags,
+                                 ProcessHandle* handle) {
+  ProcessHandle result = OpenProcess(access_flags, FALSE, pid);
+
+  if (result == NULL)
+    return false;
+
+  *handle = result;
+  return true;
+}
+
+void CloseProcessHandle(ProcessHandle process) {
+  CloseHandle(process);
+}
+
+ProcessId GetProcId(ProcessHandle process) {
+  // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
+  HANDLE current_process = GetCurrentProcess();
+  HANDLE process_with_query_rights;
+  if (DuplicateHandle(current_process, process, current_process,
+                      &process_with_query_rights, PROCESS_QUERY_INFORMATION,
+                      false, 0)) {
+    DWORD id = GetProcessId(process_with_query_rights);
+    CloseHandle(process_with_query_rights);
+    return id;
+  }
+
+  // We're screwed.
+  NOTREACHED();
+  return 0;
+}
+
+bool GetProcessIntegrityLevel(ProcessHandle process, IntegrityLevel *level) {
+  if (!level)
+    return false;
+
+  if (win::GetVersion() < base::win::VERSION_VISTA)
+    return false;
+
+  HANDLE process_token;
+  if (!OpenProcessToken(process, TOKEN_QUERY | TOKEN_QUERY_SOURCE,
+      &process_token))
+    return false;
+
+  win::ScopedHandle scoped_process_token(process_token);
+
+  DWORD token_info_length = 0;
+  if (GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0,
+                          &token_info_length) ||
+      GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+    return false;
+
+  scoped_array<char> token_label_bytes(new char[token_info_length]);
+  if (!token_label_bytes.get())
+    return false;
+
+  TOKEN_MANDATORY_LABEL* token_label =
+      reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_label_bytes.get());
+  if (!token_label)
+    return false;
+
+  if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_label,
+                           token_info_length, &token_info_length))
+    return false;
+
+  DWORD integrity_level = *GetSidSubAuthority(token_label->Label.Sid,
+      (DWORD)(UCHAR)(*GetSidSubAuthorityCount(token_label->Label.Sid)-1));
+
+  if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID) {
+    *level = LOW_INTEGRITY;
+  } else if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID &&
+      integrity_level < SECURITY_MANDATORY_HIGH_RID) {
+    *level = MEDIUM_INTEGRITY;
+  } else if (integrity_level >= SECURITY_MANDATORY_HIGH_RID) {
+    *level = HIGH_INTEGRITY;
+  } else {
+    NOTREACHED();
+    return false;
+  }
+
+  return true;
+}
+
+bool LaunchProcess(const string16& cmdline,
+                   const LaunchOptions& options,
+                   ProcessHandle* process_handle) {
+  STARTUPINFO startup_info = {};
+  startup_info.cb = sizeof(startup_info);
+  if (options.empty_desktop_name)
+    startup_info.lpDesktop = L"";
+  startup_info.dwFlags = STARTF_USESHOWWINDOW;
+  startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW;
+
+  DWORD flags = 0;
+
+  if (options.job_handle) {
+    flags |= CREATE_SUSPENDED;
+
+    // If this code is run under a debugger, the launched process is
+    // automatically associated with a job object created by the debugger.
+    // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this.
+    flags |= CREATE_BREAKAWAY_FROM_JOB;
+  }
+
+  if (options.force_breakaway_from_job_)
+    flags |= CREATE_BREAKAWAY_FROM_JOB;
+
+  base::win::ScopedProcessInformation process_info;
+
+  if (options.as_user) {
+    flags |= CREATE_UNICODE_ENVIRONMENT;
+    void* enviroment_block = NULL;
+
+    if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE))
+      return false;
+
+    BOOL launched =
+        CreateProcessAsUser(options.as_user, NULL,
+                            const_cast<wchar_t*>(cmdline.c_str()),
+                            NULL, NULL, options.inherit_handles, flags,
+                            enviroment_block, NULL, &startup_info,
+                            process_info.Receive());
+    DestroyEnvironmentBlock(enviroment_block);
+    if (!launched)
+      return false;
+  } else {
+    if (!CreateProcess(NULL,
+                       const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
+                       options.inherit_handles, flags, NULL, NULL,
+                       &startup_info, process_info.Receive())) {
+      return false;
+    }
+  }
+
+  if (options.job_handle) {
+    if (0 == AssignProcessToJobObject(options.job_handle,
+                                      process_info.process_handle())) {
+      DLOG(ERROR) << "Could not AssignProcessToObject.";
+      KillProcess(process_info.process_handle(), kProcessKilledExitCode, true);
+      return false;
+    }
+
+    ResumeThread(process_info.thread_handle());
+  }
+
+  if (options.wait)
+    WaitForSingleObject(process_info.process_handle(), INFINITE);
+
+  // If the caller wants the process handle, we won't close it.
+  if (process_handle)
+    *process_handle = process_info.TakeProcessHandle();
+
+  return true;
+}
+
+bool LaunchProcess(const CommandLine& cmdline,
+                   const LaunchOptions& options,
+                   ProcessHandle* process_handle) {
+  return LaunchProcess(cmdline.GetCommandLineString(), options, process_handle);
+}
+
+bool SetJobObjectAsKillOnJobClose(HANDLE job_object) {
+  JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0};
+  limit_info.BasicLimitInformation.LimitFlags =
+      JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+  return 0 != SetInformationJobObject(
+      job_object,
+      JobObjectExtendedLimitInformation,
+      &limit_info,
+      sizeof(limit_info));
+}
+
+// Attempts to kill the process identified by the given process
+// entry structure, giving it the specified exit code.
+// Returns true if this is successful, false otherwise.
+bool KillProcessById(ProcessId process_id, int exit_code, bool wait) {
+  HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE,
+                               FALSE,  // Don't inherit handle
+                               process_id);
+  if (!process) {
+    DLOG(ERROR) << "Unable to open process " << process_id << " : "
+                << GetLastError();
+    return false;
+  }
+  bool ret = KillProcess(process, exit_code, wait);
+  CloseHandle(process);
+  return ret;
+}
+
+bool GetAppOutput(const CommandLine& cl, std::string* output) {
+  HANDLE out_read = NULL;
+  HANDLE out_write = NULL;
+
+  SECURITY_ATTRIBUTES sa_attr;
+  // Set the bInheritHandle flag so pipe handles are inherited.
+  sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
+  sa_attr.bInheritHandle = TRUE;
+  sa_attr.lpSecurityDescriptor = NULL;
+
+  // Create the pipe for the child process's STDOUT.
+  if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) {
+    NOTREACHED() << "Failed to create pipe";
+    return false;
+  }
+
+  // Ensure we don't leak the handles.
+  win::ScopedHandle scoped_out_read(out_read);
+  win::ScopedHandle scoped_out_write(out_write);
+
+  // Ensure the read handle to the pipe for STDOUT is not inherited.
+  if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) {
+    NOTREACHED() << "Failed to disabled pipe inheritance";
+    return false;
+  }
+
+  FilePath::StringType writable_command_line_string(cl.GetCommandLineString());
+
+  base::win::ScopedProcessInformation proc_info;
+  STARTUPINFO start_info = { 0 };
+
+  start_info.cb = sizeof(STARTUPINFO);
+  start_info.hStdOutput = out_write;
+  // Keep the normal stdin and stderr.
+  start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+  start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+  start_info.dwFlags |= STARTF_USESTDHANDLES;
+
+  // Create the child process.
+  if (!CreateProcess(NULL,
+                     &writable_command_line_string[0],
+                     NULL, NULL,
+                     TRUE,  // Handles are inherited.
+                     0, NULL, NULL, &start_info, proc_info.Receive())) {
+    NOTREACHED() << "Failed to start process";
+    return false;
+  }
+
+  // Close our writing end of pipe now. Otherwise later read would not be able
+  // to detect end of child's output.
+  scoped_out_write.Close();
+
+  // Read output from the child process's pipe for STDOUT
+  const int kBufferSize = 1024;
+  char buffer[kBufferSize];
+
+  for (;;) {
+    DWORD bytes_read = 0;
+    BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL);
+    if (!success || bytes_read == 0)
+      break;
+    output->append(buffer, bytes_read);
+  }
+
+  // Let's wait for the process to finish.
+  WaitForSingleObject(proc_info.process_handle(), INFINITE);
+
+  return true;
+}
+
+bool KillProcess(ProcessHandle process, int exit_code, bool wait) {
+  bool result = (TerminateProcess(process, exit_code) != FALSE);
+  if (result && wait) {
+    // The process may not end immediately due to pending I/O
+    if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000))
+      DLOG(ERROR) << "Error waiting for process exit: " << GetLastError();
+  } else if (!result) {
+    DLOG(ERROR) << "Unable to terminate process: " << GetLastError();
+  }
+  return result;
+}
+
+TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
+  DWORD tmp_exit_code = 0;
+
+  if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
+    NOTREACHED();
+    if (exit_code) {
+      // This really is a random number.  We haven't received any
+      // information about the exit code, presumably because this
+      // process doesn't have permission to get the exit code, or
+      // because of some other cause for GetExitCodeProcess to fail
+      // (MSDN docs don't give the possible failure error codes for
+      // this function, so it could be anything).  But we don't want
+      // to leave exit_code uninitialized, since that could cause
+      // random interpretations of the exit code.  So we assume it
+      // terminated "normally" in this case.
+      *exit_code = kNormalTerminationExitCode;
+    }
+    // Assume the child has exited normally if we can't get the exit
+    // code.
+    return TERMINATION_STATUS_NORMAL_TERMINATION;
+  }
+  if (tmp_exit_code == STILL_ACTIVE) {
+    DWORD wait_result = WaitForSingleObject(handle, 0);
+    if (wait_result == WAIT_TIMEOUT) {
+      if (exit_code)
+        *exit_code = wait_result;
+      return TERMINATION_STATUS_STILL_RUNNING;
+    }
+
+    DCHECK_EQ(WAIT_OBJECT_0, wait_result);
+
+    // Strange, the process used 0x103 (STILL_ACTIVE) as exit code.
+    NOTREACHED();
+
+    return TERMINATION_STATUS_ABNORMAL_TERMINATION;
+  }
+
+  if (exit_code)
+    *exit_code = tmp_exit_code;
+
+  switch (tmp_exit_code) {
+    case kNormalTerminationExitCode:
+      return TERMINATION_STATUS_NORMAL_TERMINATION;
+    case kDebuggerInactiveExitCode:  // STATUS_DEBUGGER_INACTIVE.
+    case kKeyboardInterruptExitCode:  // Control-C/end session.
+    case kDebuggerTerminatedExitCode:  // Debugger terminated process.
+    case kProcessKilledExitCode:  // Task manager kill.
+      return TERMINATION_STATUS_PROCESS_WAS_KILLED;
+    default:
+      // All other exit codes indicate crashes.
+      return TERMINATION_STATUS_PROCESS_CRASHED;
+  }
+}
+
+bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
+  bool success = WaitForExitCodeWithTimeout(
+      handle, exit_code, base::TimeDelta::FromMilliseconds(INFINITE));
+  CloseProcessHandle(handle);
+  return success;
+}
+
+bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code,
+                                base::TimeDelta timeout) {
+  if (::WaitForSingleObject(handle, timeout.InMilliseconds()) != WAIT_OBJECT_0)
+    return false;
+  DWORD temp_code;  // Don't clobber out-parameters in case of failure.
+  if (!::GetExitCodeProcess(handle, &temp_code))
+    return false;
+
+  *exit_code = temp_code;
+  return true;
+}
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : started_iteration_(false),
+      filter_(filter) {
+  snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+}
+
+ProcessIterator::~ProcessIterator() {
+  CloseHandle(snapshot_);
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  InitProcessEntry(&entry_);
+
+  if (!started_iteration_) {
+    started_iteration_ = true;
+    return !!Process32First(snapshot_, &entry_);
+  }
+
+  return !!Process32Next(snapshot_, &entry_);
+}
+
+void ProcessIterator::InitProcessEntry(ProcessEntry* entry) {
+  memset(entry, 0, sizeof(*entry));
+  entry->dwSize = sizeof(*entry);
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  // Case insensitive.
+  return _wcsicmp(executable_name_.c_str(), entry().exe_file()) == 0 &&
+         ProcessIterator::IncludeEntry();
+}
+
+bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
+                            base::TimeDelta wait,
+                            const ProcessFilter* filter) {
+  const ProcessEntry* entry;
+  bool result = true;
+  DWORD start_time = GetTickCount();
+
+  NamedProcessIterator iter(executable_name, filter);
+  while ((entry = iter.NextProcessEntry())) {
+    DWORD remaining_wait = std::max<int64>(
+        0, wait.InMilliseconds() - (GetTickCount() - start_time));
+    HANDLE process = OpenProcess(SYNCHRONIZE,
+                                 FALSE,
+                                 entry->th32ProcessID);
+    DWORD wait_result = WaitForSingleObject(process, remaining_wait);
+    CloseHandle(process);
+    result = result && (wait_result == WAIT_OBJECT_0);
+  }
+
+  return result;
+}
+
+bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
+  int exit_code;
+  if (!WaitForExitCodeWithTimeout(handle, &exit_code, wait))
+    return false;
+  return exit_code == 0;
+}
+
+bool CleanupProcesses(const FilePath::StringType& executable_name,
+                      base::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;
+}
+
+void EnsureProcessTerminated(ProcessHandle process) {
+  DCHECK(process != GetCurrentProcess());
+
+  // If already signaled, then we are done!
+  if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
+    CloseHandle(process);
+    return;
+  }
+
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&TimerExpiredTask::TimedOut,
+                 base::Owned(new TimerExpiredTask(process))),
+      base::TimeDelta::FromMilliseconds(kWaitInterval));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ProcesMetrics
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      processor_count_(base::SysInfo::NumberOfProcessors()),
+      last_time_(0),
+      last_system_time_(0) {
+}
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+ProcessMetrics::~ProcessMetrics() { }
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.PagefileUsage;
+  }
+  return 0;
+}
+
+// Returns the peak space allocated for the pagefile, in bytes.
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.PeakPagefileUsage;
+  }
+  return 0;
+}
+
+// Returns the current working set size, in bytes.
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.WorkingSetSize;
+  }
+  return 0;
+}
+
+// Returns the peak working set size, in bytes.
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.PeakWorkingSetSize;
+  }
+  return 0;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2.
+  // GetProcessMemoryInfo() will simply fail on prior OS. So the requested
+  // information is simply not available. Hence, we will return 0 on unsupported
+  // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member.
+  PROCESS_MEMORY_COUNTERS_EX pmcx;
+  if (private_bytes &&
+      GetProcessMemoryInfo(process_,
+                           reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx),
+                           sizeof(pmcx))) {
+    *private_bytes = pmcx.PrivateUsage;
+  }
+
+  if (shared_bytes) {
+    WorkingSetKBytes ws_usage;
+    if (!GetWorkingSetKBytes(&ws_usage))
+      return false;
+
+    *shared_bytes = ws_usage.shared * 1024;
+  }
+
+  return true;
+}
+
+void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const {
+  MEMORY_BASIC_INFORMATION mbi = {0};
+  size_t committed_private = 0;
+  size_t committed_mapped = 0;
+  size_t committed_image = 0;
+  void* base_address = NULL;
+  while (VirtualQueryEx(process_, base_address, &mbi, sizeof(mbi)) ==
+      sizeof(mbi)) {
+    if (mbi.State == MEM_COMMIT) {
+      if (mbi.Type == MEM_PRIVATE) {
+        committed_private += mbi.RegionSize;
+      } else if (mbi.Type == MEM_MAPPED) {
+        committed_mapped += mbi.RegionSize;
+      } else if (mbi.Type == MEM_IMAGE) {
+        committed_image += mbi.RegionSize;
+      } else {
+        NOTREACHED();
+      }
+    }
+    void* new_base = (static_cast<BYTE*>(mbi.BaseAddress)) + mbi.RegionSize;
+    // Avoid infinite loop by weird MEMORY_BASIC_INFORMATION.
+    // If we query 64bit processes in a 32bit process, VirtualQueryEx()
+    // returns such data.
+    if (new_base <= base_address) {
+      usage->image = 0;
+      usage->mapped = 0;
+      usage->priv = 0;
+      return;
+    }
+    base_address = new_base;
+  }
+  usage->image = committed_image / 1024;
+  usage->mapped = committed_mapped / 1024;
+  usage->priv = committed_private / 1024;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+  size_t ws_private = 0;
+  size_t ws_shareable = 0;
+  size_t ws_shared = 0;
+
+  DCHECK(ws_usage);
+  memset(ws_usage, 0, sizeof(*ws_usage));
+
+  DWORD number_of_entries = 4096;  // Just a guess.
+  PSAPI_WORKING_SET_INFORMATION* buffer = NULL;
+  int retries = 5;
+  for (;;) {
+    DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) +
+                        (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK));
+
+    // if we can't expand the buffer, don't leak the previous
+    // contents or pass a NULL pointer to QueryWorkingSet
+    PSAPI_WORKING_SET_INFORMATION* new_buffer =
+        reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>(
+            realloc(buffer, buffer_size));
+    if (!new_buffer) {
+      free(buffer);
+      return false;
+    }
+    buffer = new_buffer;
+
+    // Call the function once to get number of items
+    if (QueryWorkingSet(process_, buffer, buffer_size))
+      break;  // Success
+
+    if (GetLastError() != ERROR_BAD_LENGTH) {
+      free(buffer);
+      return false;
+    }
+
+    number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries);
+
+    // Maybe some entries are being added right now. Increase the buffer to
+    // take that into account.
+    number_of_entries = static_cast<DWORD>(number_of_entries * 1.25);
+
+    if (--retries == 0) {
+      free(buffer);  // If we're looping, eventually fail.
+      return false;
+    }
+  }
+
+  // On windows 2000 the function returns 1 even when the buffer is too small.
+  // The number of entries that we are going to parse is the minimum between the
+  // size we allocated and the real number of entries.
+  number_of_entries =
+      std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries));
+  for (unsigned int i = 0; i < number_of_entries; i++) {
+    if (buffer->WorkingSetInfo[i].Shared) {
+      ws_shareable++;
+      if (buffer->WorkingSetInfo[i].ShareCount > 1)
+        ws_shared++;
+    } else {
+      ws_private++;
+    }
+  }
+
+  ws_usage->priv = ws_private * PAGESIZE_KB;
+  ws_usage->shareable = ws_shareable * PAGESIZE_KB;
+  ws_usage->shared = ws_shared * PAGESIZE_KB;
+  free(buffer);
+  return true;
+}
+
+static uint64 FileTimeToUTC(const FILETIME& ftime) {
+  LARGE_INTEGER li;
+  li.LowPart = ftime.dwLowDateTime;
+  li.HighPart = ftime.dwHighDateTime;
+  return li.QuadPart;
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  FILETIME now;
+  FILETIME creation_time;
+  FILETIME exit_time;
+  FILETIME kernel_time;
+  FILETIME user_time;
+
+  GetSystemTimeAsFileTime(&now);
+
+  if (!GetProcessTimes(process_, &creation_time, &exit_time,
+                       &kernel_time, &user_time)) {
+    // We don't assert here because in some cases (such as in the Task Manager)
+    // we may call this function on a process that has just exited but we have
+    // not yet received the notification.
+    return 0;
+  }
+  int64 system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) /
+                        processor_count_;
+  int64 time = FileTimeToUTC(now);
+
+  if ((last_system_time_ == 0) || (last_time_ == 0)) {
+    // First call, just set the last values.
+    last_system_time_ = system_time;
+    last_time_ = time;
+    return 0;
+  }
+
+  int64 system_time_delta = system_time - last_system_time_;
+  int64 time_delta = time - last_time_;
+  DCHECK_NE(0U, time_delta);
+  if (time_delta == 0)
+    return 0;
+
+  // We add time_delta / 2 so the result is rounded.
+  int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
+                             time_delta);
+
+  last_system_time_ = system_time;
+  last_time_ = time;
+
+  return cpu;
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return GetProcessIoCounters(process_, io_counters) != FALSE;
+}
+
+bool ProcessMetrics::CalculateFreeMemory(FreeMBytes* free) const {
+  const SIZE_T kTopAddress = 0x7F000000;
+  const SIZE_T kMegabyte = 1024 * 1024;
+  SIZE_T accumulated = 0;
+
+  MEMORY_BASIC_INFORMATION largest = {0};
+  UINT_PTR scan = 0;
+  while (scan < kTopAddress) {
+    MEMORY_BASIC_INFORMATION info;
+    if (!::VirtualQueryEx(process_, reinterpret_cast<void*>(scan),
+                          &info, sizeof(info)))
+      return false;
+    if (info.State == MEM_FREE) {
+      accumulated += info.RegionSize;
+      if (info.RegionSize > largest.RegionSize)
+        largest = info;
+    }
+    scan += info.RegionSize;
+  }
+  free->largest = largest.RegionSize / kMegabyte;
+  free->largest_ptr = largest.BaseAddress;
+  free->total = accumulated / kMegabyte;
+  return true;
+}
+
+bool EnableLowFragmentationHeap() {
+  HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+  HeapSetFn heap_set = reinterpret_cast<HeapSetFn>(GetProcAddress(
+      kernel32,
+      "HeapSetInformation"));
+
+  // On Windows 2000, the function is not exported. This is not a reason to
+  // fail.
+  if (!heap_set)
+    return true;
+
+  unsigned number_heaps = GetProcessHeaps(0, NULL);
+  if (!number_heaps)
+    return false;
+
+  // Gives us some extra space in the array in case a thread is creating heaps
+  // at the same time we're querying them.
+  static const int MARGIN = 8;
+  scoped_array<HANDLE> heaps(new HANDLE[number_heaps + MARGIN]);
+  number_heaps = GetProcessHeaps(number_heaps + MARGIN, heaps.get());
+  if (!number_heaps)
+    return false;
+
+  for (unsigned i = 0; i < number_heaps; ++i) {
+    ULONG lfh_flag = 2;
+    // Don't bother with the result code. It may fails on heaps that have the
+    // HEAP_NO_SERIALIZE flag. This is expected and not a problem at all.
+    heap_set(heaps[i],
+             HeapCompatibilityInformation,
+             &lfh_flag,
+             sizeof(lfh_flag));
+  }
+  return true;
+}
+
+void EnableTerminationOnHeapCorruption() {
+  // Ignore the result code. Supported on XP SP3 and Vista.
+  HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
+}
+
+void EnableTerminationOnOutOfMemory() {
+  std::set_new_handler(&OnNoMemory);
+}
+
+void RaiseProcessToHighPriority() {
+  SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
+}
+
+// GetPerformanceInfo is not available on WIN2K.  So we'll
+// load it on-the-fly.
+const wchar_t kPsapiDllName[] = L"psapi.dll";
+typedef BOOL (WINAPI *GetPerformanceInfoFunction) (
+    PPERFORMANCE_INFORMATION pPerformanceInformation,
+    DWORD cb);
+
+// Beware of races if called concurrently from multiple threads.
+static BOOL InternalGetPerformanceInfo(
+    PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb) {
+  static GetPerformanceInfoFunction GetPerformanceInfo_func = NULL;
+  if (!GetPerformanceInfo_func) {
+    HMODULE psapi_dll = ::GetModuleHandle(kPsapiDllName);
+    if (psapi_dll)
+      GetPerformanceInfo_func = reinterpret_cast<GetPerformanceInfoFunction>(
+          GetProcAddress(psapi_dll, "GetPerformanceInfo"));
+
+    if (!GetPerformanceInfo_func) {
+      // The function could be loaded!
+      memset(pPerformanceInformation, 0, cb);
+      return FALSE;
+    }
+  }
+  return GetPerformanceInfo_func(pPerformanceInformation, cb);
+}
+
+size_t GetSystemCommitCharge() {
+  // Get the System Page Size.
+  SYSTEM_INFO system_info;
+  GetSystemInfo(&system_info);
+
+  PERFORMANCE_INFORMATION info;
+  if (!InternalGetPerformanceInfo(&info, sizeof(info))) {
+    DLOG(ERROR) << "Failed to fetch internal performance info.";
+    return 0;
+  }
+  return (info.CommitTotal * system_info.dwPageSize) / 1024;
+}
+
+}  // namespace base
diff --git a/base/process_win.cc b/base/process_win.cc
new file mode 100644
index 0000000..3f683ab
--- /dev/null
+++ b/base/process_win.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2011 The Chromium Authors. All 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.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process_util.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+void Process::Close() {
+  if (!process_)
+    return;
+
+  // Don't call CloseHandle on a pseudo-handle.
+  if (process_ != ::GetCurrentProcess())
+    ::CloseHandle(process_);
+
+  process_ = NULL;
+}
+
+void Process::Terminate(int result_code) {
+  if (!process_)
+    return;
+
+  // Call NtTerminateProcess directly, without going through the import table,
+  // which might have been hooked with a buggy replacement by third party
+  // software. http://crbug.com/81449.
+  HMODULE module = GetModuleHandle(L"ntdll.dll");
+  typedef UINT (WINAPI *TerminateProcessPtr)(HANDLE handle, UINT code);
+  TerminateProcessPtr terminate_process = reinterpret_cast<TerminateProcessPtr>(
+      GetProcAddress(module, "NtTerminateProcess"));
+  terminate_process(process_, result_code);
+}
+
+bool Process::IsProcessBackgrounded() const {
+  if (!process_)
+    return false;  // Failure case.
+  DWORD priority = GetPriority();
+  if (priority == 0)
+    return false;  // Failure case.
+  return ((priority == BELOW_NORMAL_PRIORITY_CLASS) ||
+          (priority == IDLE_PRIORITY_CLASS));
+}
+
+bool Process::SetProcessBackgrounded(bool value) {
+  if (!process_)
+    return false;
+  // Vista and above introduce a real background mode, which not only
+  // sets the priority class on the threads but also on the IO generated
+  // by it. Unfortunately it can only be set for the calling process.
+  DWORD priority;
+  if ((base::win::GetVersion() >= base::win::VERSION_VISTA) &&
+      (process_ == ::GetCurrentProcess())) {
+    priority = value ? PROCESS_MODE_BACKGROUND_BEGIN :
+                       PROCESS_MODE_BACKGROUND_END;
+  } else {
+    priority = value ? BELOW_NORMAL_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS;
+  }
+
+  return (::SetPriorityClass(process_, priority) != 0);
+}
+
+ProcessId Process::pid() const {
+  if (process_ == 0)
+    return 0;
+
+  return GetProcId(process_);
+}
+
+bool Process::is_current() const {
+  return process_ == GetCurrentProcess();
+}
+
+// static
+Process Process::Current() {
+  return Process(::GetCurrentProcess());
+}
+
+// static
+bool Process::CanBackgroundProcesses() {
+  return true;
+}
+
+int Process::GetPriority() const {
+  DCHECK(process_);
+  return ::GetPriorityClass(process_);
+}
+
+}  // namespace base
diff --git a/base/profiler/alternate_timer.cc b/base/profiler/alternate_timer.cc
new file mode 100644
index 0000000..4eba89c
--- /dev/null
+++ b/base/profiler/alternate_timer.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/alternate_timer.h"
+
+#include "base/logging.h"
+
+namespace {
+
+tracked_objects::NowFunction* g_time_function = NULL;
+tracked_objects::TimeSourceType g_time_source_type =
+    tracked_objects::TIME_SOURCE_TYPE_WALL_TIME;
+
+}  // anonymous namespace
+
+namespace tracked_objects {
+
+const char kAlternateProfilerTime[] = "CHROME_PROFILER_TIME";
+
+// Set an alternate timer function to replace the OS time function when
+// profiling.
+void SetAlternateTimeSource(NowFunction* now_function, TimeSourceType type) {
+  DCHECK_EQ(reinterpret_cast<NowFunction*>(NULL), g_time_function);
+  g_time_function = now_function;
+  g_time_source_type = type;
+}
+
+NowFunction* GetAlternateTimeSource() {
+  return g_time_function;
+}
+
+TimeSourceType GetTimeSourceType() {
+  return g_time_source_type;
+}
+
+}  // namespace tracked_objects
diff --git a/base/profiler/alternate_timer.h b/base/profiler/alternate_timer.h
new file mode 100644
index 0000000..fdc75dc
--- /dev/null
+++ b/base/profiler/alternate_timer.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a glue file, which allows third party code to call into our profiler
+// without having to include most any functions from base.
+
+#ifndef BASE_PROFILER_ALTERNATE_TIMER_H_
+#define BASE_PROFILER_ALTERNATE_TIMER_H_
+
+#include "base/base_export.h"
+
+namespace tracked_objects {
+
+enum TimeSourceType {
+  TIME_SOURCE_TYPE_WALL_TIME,
+  TIME_SOURCE_TYPE_TCMALLOC
+};
+
+// Provide type for an alternate timer function.
+typedef unsigned int NowFunction();
+
+// Environment variable name that is used to activate alternate timer profiling
+// (such as using TCMalloc allocations to provide a pseudo-timer) for tasks
+// instead of wall clock profiling.
+BASE_EXPORT extern const char kAlternateProfilerTime[];
+
+// Set an alternate timer function to replace the OS time function when
+// profiling.  Typically this is called by an allocator that is providing a
+// function that indicates how much memory has been allocated on any given
+// thread.
+BASE_EXPORT void SetAlternateTimeSource(NowFunction* now_function,
+                                        TimeSourceType type);
+
+// Gets the pointer to a function that was set via SetAlternateTimeSource().
+// Returns NULL if no set was done prior to calling GetAlternateTimeSource.
+NowFunction* GetAlternateTimeSource();
+
+// Returns the type of the currently set time source.
+BASE_EXPORT TimeSourceType GetTimeSourceType();
+
+}  // namespace tracked_objects
+
+#endif  // BASE_PROFILER_ALTERNATE_TIMER_H_
diff --git a/base/profiler/scoped_profile.cc b/base/profiler/scoped_profile.cc
new file mode 100644
index 0000000..93c86e92
--- /dev/null
+++ b/base/profiler/scoped_profile.cc
@@ -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.
+
+#include "base/profiler/scoped_profile.h"
+
+#include "base/location.h"
+#include "base/tracked_objects.h"
+
+
+namespace tracked_objects {
+
+
+ScopedProfile::ScopedProfile(const Location& location)
+    : birth_(ThreadData::TallyABirthIfActive(location)),
+      start_of_run_(ThreadData::NowForStartOfRun(birth_)) {
+}
+
+ScopedProfile::~ScopedProfile() {
+  StopClockAndTally();
+}
+
+void ScopedProfile::StopClockAndTally() {
+  if (!birth_)
+    return;
+  ThreadData::TallyRunInAScopedRegionIfTracking(birth_, start_of_run_,
+                                                ThreadData::NowForEndOfRun());
+  birth_ = NULL;
+}
+
+}  // namespace tracked_objects
diff --git a/base/profiler/scoped_profile.h b/base/profiler/scoped_profile.h
new file mode 100644
index 0000000..8b77d6d
--- /dev/null
+++ b/base/profiler/scoped_profile.h
@@ -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.
+
+
+#ifndef BASE_PROFILER_SCOPED_PROFILE_H_
+#define BASE_PROFILER_SCOPED_PROFILE_H_
+
+//------------------------------------------------------------------------------
+// ScopedProfile provides basic helper functions for profiling a short
+// region of code within a scope.  It is separate from the related ThreadData
+// class so that it can be included without much other cruft, and provide the
+// macros listed below.
+
+#include "base/base_export.h"
+#include "base/location.h"
+#include "base/profiler/tracked_time.h"
+
+#if defined(GOOGLE_CHROME_BUILD)
+
+// We don't ship these profiled regions.  This is for developer builds only.
+// It allows developers to do some profiling of their code, and see results on
+// their about:profiler page.
+#define TRACK_RUN_IN_THIS_SCOPED_REGION_FOR_DEVELOPER_BUILDS(scope_name)       \
+    ((void)0)
+
+#else
+
+#define TRACK_RUN_IN_THIS_SCOPED_REGION_FOR_DEVELOPER_BUILDS(scope_name)       \
+    ::tracked_objects::ScopedProfile  LINE_BASED_VARIABLE_NAME_FOR_PROFILING(  \
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(#scope_name))
+
+#endif
+
+
+
+#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__)
+
+#define TRACK_RUN_IN_IPC_HANDLER(dispatch_function_name)                       \
+    ::tracked_objects::ScopedProfile some_tracking_variable_name(              \
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name))
+
+
+namespace tracked_objects {
+class Births;
+
+class BASE_EXPORT ScopedProfile {
+ public:
+  explicit ScopedProfile(const Location& location);
+  ~ScopedProfile();
+
+  // Stop tracing prior to the end destruction of the instance.
+  void StopClockAndTally();
+
+ private:
+  Births* birth_;  // Place in code where tracking started.
+  const TrackedTime start_of_run_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedProfile);
+};
+
+}  // namespace tracked_objects
+
+#endif   // BASE_PROFILER_SCOPED_PROFILE_H_
diff --git a/base/profiler/tracked_time.cc b/base/profiler/tracked_time.cc
new file mode 100644
index 0000000..f1edd6d
--- /dev/null
+++ b/base/profiler/tracked_time.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/tracked_time.h"
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <mmsystem.h>  // Declare timeGetTime()... after including build_config.
+#endif
+
+namespace tracked_objects {
+
+Duration::Duration() : ms_(0) {}
+Duration::Duration(int32 duration) : ms_(duration) {}
+
+Duration& Duration::operator+=(const Duration& other) {
+  ms_ += other.ms_;
+  return *this;
+}
+
+Duration Duration::operator+(const Duration& other) const {
+  return Duration(ms_ + other.ms_);
+}
+
+bool Duration::operator==(const Duration& other) const {
+  return ms_ == other.ms_;
+}
+
+bool Duration::operator!=(const Duration& other) const {
+  return ms_ != other.ms_;
+}
+
+bool Duration::operator>(const Duration& other) const {
+  return ms_ > other.ms_;
+}
+
+// static
+Duration Duration::FromMilliseconds(int ms) { return Duration(ms); }
+
+int32 Duration::InMilliseconds() const { return ms_; }
+
+//------------------------------------------------------------------------------
+
+TrackedTime::TrackedTime() : ms_(0) {}
+TrackedTime::TrackedTime(int32 ms) : ms_(ms) {}
+TrackedTime::TrackedTime(const base::TimeTicks& time)
+    : ms_((time - base::TimeTicks()).InMilliseconds()) {
+}
+
+// static
+TrackedTime TrackedTime::Now() {
+#if defined(OS_WIN)
+  // Use lock-free accessor to 32 bit time.
+  // Note that TimeTicks::Now() is built on this, so we have "compatible"
+  // times when we down-convert a TimeTicks sample.
+  // TODO(jar): Surface this interface via something in base/time.h.
+  return TrackedTime(static_cast<int32>(timeGetTime()));
+#else
+  // Posix has nice cheap 64 bit times, so we just down-convert it.
+  return TrackedTime(base::TimeTicks::Now());
+#endif  // OS_WIN
+}
+
+Duration TrackedTime::operator-(const TrackedTime& other) const {
+  return Duration(ms_ - other.ms_);
+}
+
+TrackedTime TrackedTime::operator+(const Duration& other) const {
+  return TrackedTime(ms_ + other.ms_);
+}
+
+bool TrackedTime::is_null() const { return ms_ == 0; }
+
+}  // namespace tracked_objects
diff --git a/base/profiler/tracked_time.h b/base/profiler/tracked_time.h
new file mode 100644
index 0000000..372c753
--- /dev/null
+++ b/base/profiler/tracked_time.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROFILER_TRACKED_TIME_H_
+#define BASE_PROFILER_TRACKED_TIME_H_
+
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/time.h"
+
+namespace tracked_objects {
+
+//------------------------------------------------------------------------------
+
+// TimeTicks maintains a wasteful 64 bits of data (we need less than 32), and on
+// windows, a 64 bit timer is expensive to even obtain. We use a simple
+// millisecond counter for most of our time values, as well as millisecond units
+// of duration between those values.  This means we can only handle durations
+// up to 49 days (range), or 24 days (non-negative time durations).
+// We only define enough methods to service the needs of the tracking classes,
+// and our interfaces are modeled after what TimeTicks and TimeDelta use (so we
+// can swap them into place if we want to use the "real" classes).
+
+class BASE_EXPORT Duration {  // Similar to base::TimeDelta.
+ public:
+  Duration();
+
+  Duration& operator+=(const Duration& other);
+  Duration operator+(const Duration& other) const;
+
+  bool operator==(const Duration& other) const;
+  bool operator!=(const Duration& other) const;
+  bool operator>(const Duration& other) const;
+
+  static Duration FromMilliseconds(int ms);
+
+  int32 InMilliseconds() const;
+
+ private:
+  friend class TrackedTime;
+  explicit Duration(int32 duration);
+
+  // Internal time is stored directly in milliseconds.
+  int32 ms_;
+};
+
+class BASE_EXPORT TrackedTime {  // Similar to base::TimeTicks.
+ public:
+  TrackedTime();
+  explicit TrackedTime(const base::TimeTicks& time);
+
+  static TrackedTime Now();
+  Duration operator-(const TrackedTime& other) const;
+  TrackedTime operator+(const Duration& other) const;
+  bool is_null() const;
+
+  static TrackedTime FromMilliseconds(int32 ms) { return TrackedTime(ms); }
+
+ private:
+  friend class Duration;
+  explicit TrackedTime(int32 ms);
+
+  // Internal duration is stored directly in milliseconds.
+  uint32 ms_;
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_PROFILER_TRACKED_TIME_H_
diff --git a/base/profiler/tracked_time_unittest.cc b/base/profiler/tracked_time_unittest.cc
new file mode 100644
index 0000000..cd7f18c
--- /dev/null
+++ b/base/profiler/tracked_time_unittest.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.
+
+// Test of classes in tracked_time.cc
+
+#include "base/profiler/tracked_time.h"
+#include "base/time.h"
+#include "base/tracked_objects.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace tracked_objects {
+
+TEST(TrackedTimeTest, TrackedTimerMilliseconds) {
+  // First make sure we basicallly transfer simple milliseconds values as
+  // expected.  Most critically, things should not become null.
+  int32 kSomeMilliseconds = 243;  // Some example times.
+  int64 kReallyBigMilliseconds = (1LL << 35) + kSomeMilliseconds;
+
+  TrackedTime some = TrackedTime() +
+      Duration::FromMilliseconds(kSomeMilliseconds);
+  EXPECT_EQ(kSomeMilliseconds, (some - TrackedTime()).InMilliseconds());
+  EXPECT_FALSE(some.is_null());
+
+  // Now create a big time, to check that it is wrapped modulo 2^32.
+  base::TimeTicks big = base::TimeTicks() +
+      base::TimeDelta::FromMilliseconds(kReallyBigMilliseconds);
+  EXPECT_EQ(kReallyBigMilliseconds, (big - base::TimeTicks()).InMilliseconds());
+
+  TrackedTime wrapped_big(big);
+  // Expect wrapping at 32 bits.
+  EXPECT_EQ(kSomeMilliseconds, (wrapped_big - TrackedTime()).InMilliseconds());
+}
+
+TEST(TrackedTimeTest, TrackedTimerDuration) {
+  int kFirstMilliseconds = 793;
+  int kSecondMilliseconds = 14889;
+
+  Duration first = Duration::FromMilliseconds(kFirstMilliseconds);
+  Duration second = Duration::FromMilliseconds(kSecondMilliseconds);
+
+  EXPECT_EQ(kFirstMilliseconds, first.InMilliseconds());
+  EXPECT_EQ(kSecondMilliseconds, second.InMilliseconds());
+
+  Duration sum = first + second;
+  EXPECT_EQ(kFirstMilliseconds + kSecondMilliseconds, sum.InMilliseconds());
+}
+
+TEST(TrackedTimeTest, TrackedTimerVsTimeTicks) {
+  // Make sure that our 32 bit timer is aligned with the TimeTicks() timer.
+
+  // First get a 64 bit timer (which should not be null).
+  base::TimeTicks ticks_before = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_before.is_null());
+
+  // Then get a 32 bit timer that can be be null when it wraps.
+  TrackedTime now = TrackedTime::Now();
+
+  // Then get a bracketing time.
+  base::TimeTicks ticks_after = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_after.is_null());
+
+  // Now make sure that we bracketed our tracked time nicely.
+  Duration before = now - TrackedTime(ticks_before);
+  EXPECT_LE(0, before.InMilliseconds());
+  Duration after = now - TrackedTime(ticks_after);
+  EXPECT_GE(0, after.InMilliseconds());
+}
+
+TEST(TrackedTimeTest, TrackedTimerDisabled) {
+  // Check to be sure disabling the collection of data induces a null time
+  // (which we know will return much faster).
+  if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED))
+    return;
+  // Since we disabled tracking, we should get a null response.
+  TrackedTime track_now = ThreadData::Now();
+  EXPECT_TRUE(track_now.is_null());
+  track_now = ThreadData::NowForStartOfRun(NULL);
+  EXPECT_TRUE(track_now.is_null());
+  track_now = ThreadData::NowForEndOfRun();
+  EXPECT_TRUE(track_now.is_null());
+}
+
+TEST(TrackedTimeTest, TrackedTimerEnabled) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+      ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+  // Make sure that when we enable tracking, we get a real timer result.
+
+  // First get a 64 bit timer (which should not be null).
+  base::TimeTicks ticks_before = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_before.is_null());
+
+  // Then get a 32 bit timer that can be null when it wraps.
+  // Crtical difference from  the TrackedTimerVsTimeTicks test, is that we use
+  // ThreadData::Now().  It can sometimes return the null time.
+  TrackedTime now = ThreadData::Now();
+
+  // Then get a bracketing time.
+  base::TimeTicks ticks_after = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_after.is_null());
+
+  // Now make sure that we bracketed our tracked time nicely.
+  Duration before = now - TrackedTime(ticks_before);
+  EXPECT_LE(0, before.InMilliseconds());
+  Duration after = now - TrackedTime(ticks_after);
+  EXPECT_GE(0, after.InMilliseconds());
+}
+
+}  // namespace tracked_objects
diff --git a/base/rand_util.cc b/base/rand_util.cc
new file mode 100644
index 0000000..a9bc961
--- /dev/null
+++ b/base/rand_util.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/rand_util.h"
+
+#include <math.h>
+
+#include <limits>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+
+namespace base {
+
+int RandInt(int min, int max) {
+  DCHECK_LE(min, max);
+
+  uint64 range = static_cast<uint64>(max) - min + 1;
+  int result = min + static_cast<int>(base::RandGenerator(range));
+  DCHECK_GE(result, min);
+  DCHECK_LE(result, max);
+  return result;
+}
+
+double RandDouble() {
+  return BitsToOpenEndedUnitInterval(base::RandUint64());
+}
+
+double BitsToOpenEndedUnitInterval(uint64 bits) {
+  // We try to get maximum precision by masking out as many bits as will fit
+  // in the target type's mantissa, and raising it to an appropriate power to
+  // produce output in the range [0, 1).  For IEEE 754 doubles, the mantissa
+  // is expected to accommodate 53 bits.
+
+  COMPILE_ASSERT(std::numeric_limits<double>::radix == 2, otherwise_use_scalbn);
+  static const int kBits = std::numeric_limits<double>::digits;
+  uint64 random_bits = bits & ((GG_UINT64_C(1) << kBits) - 1);
+  double result = ldexp(static_cast<double>(random_bits), -1 * kBits);
+  DCHECK_GE(result, 0.0);
+  DCHECK_LT(result, 1.0);
+  return result;
+}
+
+uint64 RandGenerator(uint64 range) {
+  DCHECK_GT(range, 0u);
+  // We must discard random results above this number, as they would
+  // make the random generator non-uniform (consider e.g. if
+  // MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice
+  // as likely as a result of 3 or 4).
+  uint64 max_acceptable_value =
+      (std::numeric_limits<uint64>::max() / range) * range - 1;
+
+  uint64 value;
+  do {
+    value = base::RandUint64();
+  } while (value > max_acceptable_value);
+
+  return value % range;
+}
+
+void RandBytes(void* output, size_t output_length) {
+  uint64 random_int;
+  size_t random_int_size = sizeof(random_int);
+  for (size_t i = 0; i < output_length; i += random_int_size) {
+    random_int = base::RandUint64();
+    size_t copy_count = std::min(output_length - i, random_int_size);
+    memcpy(((uint8*)output) + i, &random_int, copy_count);
+  }
+}
+
+std::string RandBytesAsString(size_t length) {
+  DCHECK_GT(length, 0u);
+  std::string result;
+  RandBytes(WriteInto(&result, length + 1), length);
+  return result;
+}
+
+}  // namespace base
diff --git a/base/rand_util.h b/base/rand_util.h
new file mode 100644
index 0000000..4f4765b
--- /dev/null
+++ b/base/rand_util.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_RAND_UTIL_H_
+#define BASE_RAND_UTIL_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+// Returns a random number in range [0, kuint64max]. Thread-safe.
+BASE_EXPORT uint64 RandUint64();
+
+// Returns a random number between min and max (inclusive). Thread-safe.
+BASE_EXPORT int RandInt(int min, int max);
+
+// Returns a random number in range [0, range).  Thread-safe.
+//
+// Note that this can be used as an adapter for std::random_shuffle():
+// Given a pre-populated |std::vector<int> myvector|, shuffle it as
+//   std::random_shuffle(myvector.begin(), myvector.end(), base::RandGenerator);
+BASE_EXPORT uint64 RandGenerator(uint64 range);
+
+// Returns a random double in range [0, 1). Thread-safe.
+BASE_EXPORT double RandDouble();
+
+// Given input |bits|, convert with maximum precision to a double in
+// the range [0, 1). Thread-safe.
+BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64 bits);
+
+// Fills |output_length| bytes of |output| with random data.
+//
+// WARNING:
+// Do not use for security-sensitive purposes.
+// See crypto/ for cryptographically secure random number generation APIs.
+BASE_EXPORT void RandBytes(void* output, size_t output_length);
+
+// Fills a string of length |length| with with random data and returns it.
+// |length| should be nonzero.
+//
+// Note that this is a variation of |RandBytes| with a different return type.
+//
+// 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);
+
+#ifdef OS_POSIX
+BASE_EXPORT int GetUrandomFD();
+#endif
+
+}  // namespace base
+
+#endif  // BASE_RAND_UTIL_H_
diff --git a/base/rand_util_nacl.cc b/base/rand_util_nacl.cc
new file mode 100644
index 0000000..47450aa
--- /dev/null
+++ b/base/rand_util_nacl.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/rand_util.h"
+
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "native_client/src/untrusted/irt/irt.h"
+
+namespace {
+
+class NaclRandom {
+ public:
+  NaclRandom() {
+    size_t result = nacl_interface_query(NACL_IRT_RANDOM_v0_1,
+                                         &random_, sizeof(random_));
+    CHECK_EQ(result, sizeof(random_));
+  }
+
+  ~NaclRandom() {
+  }
+
+  void GetRandomBytes(char* buffer, uint32_t num_bytes) {
+    while (num_bytes > 0) {
+      size_t nread;
+      int error = random_.get_random_bytes(buffer, num_bytes, &nread);
+      CHECK_EQ(error, 0);
+      CHECK_LE(nread, num_bytes);
+      buffer += nread;
+      num_bytes -= nread;
+    }
+  }
+
+ private:
+  nacl_irt_random random_;
+};
+
+base::LazyInstance<NaclRandom>::Leaky g_nacl_random = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+
+uint64 RandUint64() {
+  uint64 result;
+  g_nacl_random.Pointer()->GetRandomBytes(
+      reinterpret_cast<char*>(&result), sizeof(result));
+  return result;
+}
+
+}  // namespace base
diff --git a/base/rand_util_posix.cc b/base/rand_util_posix.cc
new file mode 100644
index 0000000..d65ddae
--- /dev/null
+++ b/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 <unistd.h>
+
+#include "base/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:
+  int fd_;
+};
+
+base::LazyInstance<URandomFd> g_urandom_fd = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+
+// NOTE: This function must be cryptographically secure. http://crbug.com/140076
+uint64 RandUint64() {
+  uint64 number;
+
+  int urandom_fd = g_urandom_fd.Pointer()->fd();
+  bool success = file_util::ReadFromFD(urandom_fd,
+                                       reinterpret_cast<char*>(&number),
+                                       sizeof(number));
+  CHECK(success);
+
+  return number;
+}
+
+int GetUrandomFD(void) {
+  return g_urandom_fd.Pointer()->fd();
+}
+
+}  // namespace base
diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc
new file mode 100644
index 0000000..e0e85ec
--- /dev/null
+++ b/base/rand_util_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/rand_util.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const int kIntMin = std::numeric_limits<int>::min();
+const int kIntMax = std::numeric_limits<int>::max();
+
+}  // namespace
+
+TEST(RandUtilTest, SameMinAndMax) {
+  EXPECT_EQ(base::RandInt(0, 0), 0);
+  EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin);
+  EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax);
+}
+
+TEST(RandUtilTest, RandDouble) {
+  // Force 64-bit precision, making sure we're not in a 80-bit FPU register.
+  volatile double number = base::RandDouble();
+  EXPECT_GT(1.0, number);
+  EXPECT_LE(0.0, number);
+}
+
+TEST(RandUtilTest, RandBytes) {
+  const size_t buffer_size = 50;
+  char buffer[buffer_size];
+  memset(buffer, 0, buffer_size);
+  base::RandBytes(buffer, buffer_size);
+  std::sort(buffer, buffer + buffer_size);
+  // Probability of occurrence of less than 25 unique bytes in 50 random bytes
+  // is below 10^-25.
+  EXPECT_GT(std::unique(buffer, buffer + buffer_size) - buffer, 25);
+}
+
+TEST(RandUtilTest, RandBytesAsString) {
+  std::string random_string = base::RandBytesAsString(1);
+  EXPECT_EQ(1U, random_string.size());
+  random_string = base::RandBytesAsString(145);
+  EXPECT_EQ(145U, random_string.size());
+  char accumulator = 0;
+  for (size_t i = 0; i < random_string.size(); ++i)
+    accumulator |= random_string[i];
+  // In theory this test can fail, but it won't before the universe dies of
+  // heat death.
+  EXPECT_NE(0, accumulator);
+}
+
+// Make sure that it is still appropriate to use RandGenerator in conjunction
+// with std::random_shuffle().
+TEST(RandUtilTest, RandGeneratorForRandomShuffle) {
+  EXPECT_EQ(base::RandGenerator(1), 0U);
+  EXPECT_LE(std::numeric_limits<ptrdiff_t>::max(),
+            std::numeric_limits<int64>::max());
+}
+
+TEST(RandUtilTest, RandGeneratorIsUniform) {
+  // Verify that RandGenerator has a uniform distribution. This is a
+  // regression test that consistently failed when RandGenerator was
+  // implemented this way:
+  //
+  //   return base::RandUint64() % max;
+  //
+  // A degenerate case for such an implementation is e.g. a top of
+  // range that is 2/3rds of the way to MAX_UINT64, in which case the
+  // bottom half of the range would be twice as likely to occur as the
+  // top half. A bit of calculus care of jar@ shows that the largest
+  // measurable delta is when the top of the range is 3/4ths of the
+  // way, so that's what we use in the test.
+  const uint64 kTopOfRange = (std::numeric_limits<uint64>::max() / 4ULL) * 3ULL;
+  const uint64 kExpectedAverage = kTopOfRange / 2ULL;
+  const uint64 kAllowedVariance = kExpectedAverage / 50ULL;  // +/- 2%
+  const int kMinAttempts = 1000;
+  const int kMaxAttempts = 1000000;
+
+  double cumulative_average = 0.0;
+  int count = 0;
+  while (count < kMaxAttempts) {
+    uint64 value = base::RandGenerator(kTopOfRange);
+    cumulative_average = (count * cumulative_average + value) / (count + 1);
+
+    // Don't quit too quickly for things to start converging, or we may have
+    // a false positive.
+    if (count > kMinAttempts &&
+        kExpectedAverage - kAllowedVariance < cumulative_average &&
+        cumulative_average < kExpectedAverage + kAllowedVariance) {
+      break;
+    }
+
+    ++count;
+  }
+
+  ASSERT_LT(count, kMaxAttempts) << "Expected average was " <<
+      kExpectedAverage << ", average ended at " << cumulative_average;
+}
+
+TEST(RandUtilTest, RandUint64ProducesBothValuesOfAllBits) {
+  // This tests to see that our underlying random generator is good
+  // enough, for some value of good enough.
+  uint64 kAllZeros = 0ULL;
+  uint64 kAllOnes = ~kAllZeros;
+  uint64 found_ones = kAllZeros;
+  uint64 found_zeros = kAllOnes;
+
+  for (size_t i = 0; i < 1000; ++i) {
+    uint64 value = base::RandUint64();
+    found_ones |= value;
+    found_zeros &= value;
+
+    if (found_zeros == kAllZeros && found_ones == kAllOnes)
+      return;
+  }
+
+  FAIL() << "Didn't achieve all bit values in maximum number of tries.";
+}
diff --git a/base/rand_util_win.cc b/base/rand_util_win.cc
new file mode 100644
index 0000000..391fe5b
--- /dev/null
+++ b/base/rand_util_win.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/rand_util.h"
+
+#include <stdlib.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace {
+
+uint32 RandUint32() {
+  uint32 number;
+  CHECK_EQ(rand_s(&number), 0);
+  return number;
+}
+
+}  // namespace
+
+namespace base {
+
+// NOTE: This function must be cryptographically secure. http://crbug.com/140076
+uint64 RandUint64() {
+  uint32 first_half = RandUint32();
+  uint32 second_half = RandUint32();
+  return (static_cast<uint64>(first_half) << 32) + second_half;
+}
+
+}  // namespace base
diff --git a/base/run_loop.cc b/base/run_loop.cc
new file mode 100644
index 0000000..991571e
--- /dev/null
+++ b/base/run_loop.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/run_loop.h"
+
+#include "base/bind.h"
+
+namespace base {
+
+RunLoop::RunLoop()
+    : loop_(MessageLoop::current()),
+      weak_factory_(this),
+      previous_run_loop_(NULL),
+      run_depth_(0),
+      run_called_(false),
+      quit_called_(false),
+      running_(false),
+      quit_when_idle_received_(false) {
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+   dispatcher_ = NULL;
+#endif
+}
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+RunLoop::RunLoop(MessageLoop::Dispatcher* dispatcher)
+    : loop_(MessageLoop::current()),
+      weak_factory_(this),
+      previous_run_loop_(NULL),
+      dispatcher_(dispatcher),
+      run_depth_(0),
+      run_called_(false),
+      quit_called_(false),
+      running_(false),
+      quit_when_idle_received_(false) {
+}
+#endif
+
+RunLoop::~RunLoop() {
+}
+
+void RunLoop::Run() {
+  if (!BeforeRun())
+    return;
+  loop_->RunHandler();
+  AfterRun();
+}
+
+void RunLoop::RunUntilIdle() {
+  quit_when_idle_received_ = true;
+  Run();
+}
+
+void RunLoop::Quit() {
+  quit_called_ = true;
+  if (running_ && loop_->run_loop_ == this) {
+    // This is the inner-most RunLoop, so quit now.
+    loop_->QuitNow();
+  }
+}
+
+base::Closure RunLoop::QuitClosure() {
+  return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
+}
+
+bool RunLoop::BeforeRun() {
+  DCHECK(!run_called_);
+  run_called_ = true;
+
+  // Allow Quit to be called before Run.
+  if (quit_called_)
+    return false;
+
+  // Push RunLoop stack:
+  previous_run_loop_ = loop_->run_loop_;
+  run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1;
+  loop_->run_loop_ = this;
+
+  running_ = true;
+  return true;
+}
+
+void RunLoop::AfterRun() {
+  running_ = false;
+
+  // Pop RunLoop stack:
+  loop_->run_loop_ = previous_run_loop_;
+
+  // Execute deferred QuitNow, if any:
+  if (previous_run_loop_ && previous_run_loop_->quit_called_)
+    loop_->QuitNow();
+}
+
+}  // namespace base
diff --git a/base/run_loop.h b/base/run_loop.h
new file mode 100644
index 0000000..8314737
--- /dev/null
+++ b/base/run_loop.h
@@ -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.
+
+#ifndef BASE_RUN_LOOP_H_
+#define BASE_RUN_LOOP_H_
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop.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();
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+  explicit RunLoop(MessageLoop::Dispatcher* dispatcher);
+#endif
+  ~RunLoop();
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+  void set_dispatcher(MessageLoop::Dispatcher* dispatcher) {
+    dispatcher_ = dispatcher;
+  }
+#endif
+
+  // Run the current MessageLoop. This blocks until Quit is called. Before
+  // calling Run, be sure to grab an AsWeakPtr or the QuitClosure in order to
+  // stop the MessageLoop asynchronously. MessageLoop::Quit and QuitNow will
+  // also trigger a return from Run, but those are deprecated.
+  void Run();
+
+  // Run the current MessageLoop until it doesn't find any tasks or messages in
+  // the queue (it goes idle). WARNING: This may never return! Only use this
+  // when repeating tasks such as animated web pages have been shut down.
+  void RunUntilIdle();
+
+  bool running() const { return running_; }
+
+  // Quit an earlier call to Run(). There can be other nested RunLoops servicing
+  // the same task queue (MessageLoop); Quitting one RunLoop has no bearing on
+  // the others. Quit can be called before, during or after Run. If called
+  // before Run, Run will return immediately when called. Calling Quit after the
+  // RunLoop has already finished running has no effect.
+  //
+  // WARNING: You must NEVER assume that a call to Quit will terminate the
+  // targetted message loop. If a nested message loop continues running, the
+  // target may NEVER terminate. It is very easy to livelock (run forever) in
+  // such a case.
+  void Quit();
+
+  // Convenience method to get a closure that safely calls Quit (has no effect
+  // if the RunLoop instance is gone).
+  //
+  // Example:
+  //   RunLoop run_loop;
+  //   PostTask(run_loop.QuitClosure());
+  //   run_loop.Run();
+  base::Closure QuitClosure();
+
+ private:
+  friend class ::MessageLoop;
+#if defined(OS_ANDROID)
+  // Android doesn't support the blocking MessageLoop::Run, so it calls
+  // BeforeRun and AfterRun directly.
+  friend class base::MessagePumpForUI;
+#endif
+
+#if defined(OS_IOS)
+  // iOS doesn't support the blocking MessageLoop::Run, so it calls
+  // BeforeRun directly.
+  friend class base::MessagePumpUIApplication;
+#endif
+
+  // Return false to abort the Run.
+  bool BeforeRun();
+  void AfterRun();
+
+  MessageLoop* loop_;
+
+  // WeakPtrFactory for QuitClosure safety.
+  base::WeakPtrFactory<RunLoop> weak_factory_;
+
+  // Parent RunLoop or NULL if this is the top-most RunLoop.
+  RunLoop* previous_run_loop_;
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+  MessageLoop::Dispatcher* dispatcher_;
+#endif
+
+  // Used to count how many nested Run() invocations are on the stack.
+  int run_depth_;
+
+  bool run_called_;
+  bool quit_called_;
+  bool running_;
+
+  // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning
+  // that we should quit Run once it becomes idle.
+  bool quit_when_idle_received_;
+
+  DISALLOW_COPY_AND_ASSIGN(RunLoop);
+};
+
+}  // namespace base
+
+#endif  // BASE_RUN_LOOP_H_
diff --git a/base/safe_strerror_posix.cc b/base/safe_strerror_posix.cc
new file mode 100644
index 0000000..a91bb8d
--- /dev/null
+++ b/base/safe_strerror_posix.cc
@@ -0,0 +1,111 @@
+// 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.
+
+#include "build/build_config.h"
+#include "base/safe_strerror_posix.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define USE_HISTORICAL_STRERRO_R (defined(__GLIBC__) || defined(OS_NACL))
+
+#if USE_HISTORICAL_STRERRO_R && defined(__GNUC__)
+// GCC will complain about the unused second wrap function unless we tell it
+// that we meant for them to be potentially unused, which is exactly what this
+// attribute is for.
+#define POSSIBLY_UNUSED __attribute__((unused))
+#else
+#define POSSIBLY_UNUSED
+#endif
+
+#if USE_HISTORICAL_STRERRO_R
+// glibc has two strerror_r functions: a historical GNU-specific one that
+// returns type char *, and a POSIX.1-2001 compliant one available since 2.3.4
+// that returns int. This wraps the GNU-specific one.
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+    char *(*strerror_r_ptr)(int, char *, size_t),
+    int err,
+    char *buf,
+    size_t len) {
+  // GNU version.
+  char *rc = (*strerror_r_ptr)(err, buf, len);
+  if (rc != buf) {
+    // glibc did not use buf and returned a static string instead. Copy it
+    // into buf.
+    buf[0] = '\0';
+    strncat(buf, rc, len - 1);
+  }
+  // The GNU version never fails. Unknown errors get an "unknown error" message.
+  // The result is always null terminated.
+}
+#endif  // USE_HISTORICAL_STRERRO_R
+
+// Wrapper for strerror_r functions that implement the POSIX interface. POSIX
+// does not define the behaviour for some of the edge cases, so we wrap it to
+// guarantee that they are handled. This is compiled on all POSIX platforms, but
+// it will only be used on Linux if the POSIX strerror_r implementation is
+// being used (see below).
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+    int (*strerror_r_ptr)(int, char *, size_t),
+    int err,
+    char *buf,
+    size_t len) {
+  int old_errno = errno;
+  // Have to cast since otherwise we get an error if this is the GNU version
+  // (but in such a scenario this function is never called). Sadly we can't use
+  // C++-style casts because the appropriate one is reinterpret_cast but it's
+  // considered illegal to reinterpret_cast a type to itself, so we get an
+  // error in the opposite case.
+  int result = (*strerror_r_ptr)(err, buf, len);
+  if (result == 0) {
+    // POSIX is vague about whether the string will be terminated, although
+    // it indirectly implies that typically ERANGE will be returned, instead
+    // of truncating the string. We play it safe by always terminating the
+    // string explicitly.
+    buf[len - 1] = '\0';
+  } else {
+    // Error. POSIX is vague about whether the return value is itself a system
+    // error code or something else. On Linux currently it is -1 and errno is
+    // set. On BSD-derived systems it is a system error and errno is unchanged.
+    // We try and detect which case it is so as to put as much useful info as
+    // we can into our message.
+    int strerror_error;  // The error encountered in strerror
+    int new_errno = errno;
+    if (new_errno != old_errno) {
+      // errno was changed, so probably the return value is just -1 or something
+      // else that doesn't provide any info, and errno is the error.
+      strerror_error = new_errno;
+    } else {
+      // Either the error from strerror_r was the same as the previous value, or
+      // errno wasn't used. Assume the latter.
+      strerror_error = result;
+    }
+    // snprintf truncates and always null-terminates.
+    snprintf(buf,
+             len,
+             "Error %d while retrieving error %d",
+             strerror_error,
+             err);
+  }
+  errno = old_errno;
+}
+
+void safe_strerror_r(int err, char *buf, size_t len) {
+  if (buf == NULL || len <= 0) {
+    return;
+  }
+  // If using glibc (i.e., Linux), the compiler will automatically select the
+  // appropriate overloaded function based on the function type of strerror_r.
+  // The other one will be elided from the translation unit since both are
+  // static.
+  wrap_posix_strerror_r(&strerror_r, err, buf, len);
+}
+
+std::string safe_strerror(int err) {
+  const int buffer_size = 256;
+  char buf[buffer_size];
+  safe_strerror_r(err, buf, sizeof(buf));
+  return std::string(buf);
+}
diff --git a/base/safe_strerror_posix.h b/base/safe_strerror_posix.h
new file mode 100644
index 0000000..2f77d84
--- /dev/null
+++ b/base/safe_strerror_posix.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_SAFE_STRERROR_POSIX_H_
+#define BASE_SAFE_STRERROR_POSIX_H_
+
+#include <string>
+
+#include "base/base_export.h"
+
+// 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);
+
+#endif  // BASE_SAFE_STRERROR_POSIX_H_
diff --git a/base/scoped_native_library.cc b/base/scoped_native_library.cc
new file mode 100644
index 0000000..7290d29
--- /dev/null
+++ b/base/scoped_native_library.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/scoped_native_library.h"
+
+namespace base {
+
+ScopedNativeLibrary::ScopedNativeLibrary() : library_(NULL) {
+}
+
+ScopedNativeLibrary::ScopedNativeLibrary(NativeLibrary library)
+    : library_(library) {
+}
+
+ScopedNativeLibrary::ScopedNativeLibrary(const FilePath& library_path) {
+  library_ = base::LoadNativeLibrary(library_path, NULL);
+}
+
+ScopedNativeLibrary::~ScopedNativeLibrary() {
+  if (library_)
+    base::UnloadNativeLibrary(library_);
+}
+
+void* ScopedNativeLibrary::GetFunctionPointer(
+    const char* function_name) const {
+  if (!library_)
+    return NULL;
+  return base::GetFunctionPointerFromNativeLibrary(library_, function_name);
+}
+
+void ScopedNativeLibrary::Reset(NativeLibrary library) {
+  if (library_)
+    base::UnloadNativeLibrary(library_);
+  library_ = library;
+}
+
+NativeLibrary ScopedNativeLibrary::Release() {
+  NativeLibrary result = library_;
+  library_ = NULL;
+  return result;
+}
+
+}  // namespace base
diff --git a/base/scoped_native_library.h b/base/scoped_native_library.h
new file mode 100644
index 0000000..94380ba
--- /dev/null
+++ b/base/scoped_native_library.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SCOPED_NATIVE_LIBRARY_H_
+#define BASE_SCOPED_NATIVE_LIBRARY_H_
+
+#include "base/base_export.h"
+#include "base/native_library.h"
+
+class FilePath;
+
+namespace base {
+
+// A class which encapsulates a base::NativeLibrary object available only in a
+// scope.
+// This class automatically unloads the loaded library in its destructor.
+class BASE_EXPORT ScopedNativeLibrary {
+ public:
+  // Initializes with a NULL library.
+  ScopedNativeLibrary();
+
+  // Takes ownership of the given library handle.
+  explicit ScopedNativeLibrary(NativeLibrary library);
+
+  // Opens the given library and manages its lifetime.
+  explicit ScopedNativeLibrary(const FilePath& library_path);
+
+  ~ScopedNativeLibrary();
+
+  // Returns true if there's a valid library loaded.
+  bool is_valid() const { return !!library_; }
+
+  void* GetFunctionPointer(const char* function_name) const;
+
+  // Takes ownership of the given library handle. Any existing handle will
+  // be freed.
+  void Reset(NativeLibrary library);
+
+  // Returns the native library handle and removes it from this object. The
+  // caller must manage the lifetime of the handle.
+  NativeLibrary Release();
+
+ private:
+  NativeLibrary library_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedNativeLibrary);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_NATIVE_LIBRARY_H_
diff --git a/base/scoped_native_library_unittest.cc b/base/scoped_native_library_unittest.cc
new file mode 100644
index 0000000..7efffdd
--- /dev/null
+++ b/base/scoped_native_library_unittest.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/scoped_native_library.h"
+#if defined(OS_WIN)
+#include "base/file_path.h"
+#endif
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Tests whether or not a function pointer retrieved via ScopedNativeLibrary
+// is available only in a scope.
+TEST(ScopedNativeLibrary, Basic) {
+#if defined(OS_WIN)
+  // Get the pointer to DirectDrawCreate() from "ddraw.dll" and verify it
+  // is valid only in this scope.
+  // FreeLibrary() doesn't actually unload a DLL until its reference count
+  // becomes zero, i.e. this function pointer is still valid if the DLL used
+  // in this test is also used by another part of this executable.
+  // So, this test uses "ddraw.dll", which is not used by Chrome at all but
+  // installed on all versions of Windows.
+  FARPROC test_function;
+  {
+    FilePath path(base::GetNativeLibraryName(L"ddraw"));
+    base::ScopedNativeLibrary library(path);
+    test_function = reinterpret_cast<FARPROC>(
+        library.GetFunctionPointer("DirectDrawCreate"));
+    EXPECT_EQ(0, IsBadCodePtr(test_function));
+  }
+  EXPECT_NE(0, IsBadCodePtr(test_function));
+#endif
+}
diff --git a/base/scoped_observer.h b/base/scoped_observer.h
new file mode 100644
index 0000000..eae6367
--- /dev/null
+++ b/base/scoped_observer.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SCOPED_OBSERVER_H_
+#define BASE_SCOPED_OBSERVER_H_
+
+#include <algorithm>
+#include <vector>
+
+#include "base/basictypes.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() {
+    for (size_t i = 0; i < sources_.size(); ++i)
+      sources_[i]->RemoveObserver(observer_);
+  }
+
+  // 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) {
+    sources_.erase(std::find(sources_.begin(), sources_.end(), source));
+    source->RemoveObserver(observer_);
+  }
+
+  bool IsObserving(Source* source) const {
+    for (size_t i = 0; i < sources_.size(); ++i) {
+      if (sources_[i] == source)
+        return true;
+    }
+    return false;
+  }
+
+ private:
+  Observer* observer_;
+
+  std::vector<Source*> sources_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedObserver);
+};
+
+#endif  // BASE_SCOPED_OBSERVER_H_
diff --git a/base/scoped_temp_dir.cc b/base/scoped_temp_dir.cc
new file mode 100644
index 0000000..9f4bcf4
--- /dev/null
+++ b/base/scoped_temp_dir.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/scoped_temp_dir.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+
+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 (!file_util::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 (!file_util::CreateDirectory(base_path))
+    return false;
+
+  // Create a new, uniquely named directory under |base_path|.
+  if (!file_util::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 (!file_util::DirectoryExists(path) &&
+      !file_util::CreateDirectory(path))
+    return false;
+
+  path_ = path;
+  return true;
+}
+
+bool ScopedTempDir::Delete() {
+  if (path_.empty())
+    return false;
+
+  bool ret = file_util::Delete(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() && file_util::DirectoryExists(path_);
+}
diff --git a/base/scoped_temp_dir.h b/base/scoped_temp_dir.h
new file mode 100644
index 0000000..94acefc
--- /dev/null
+++ b/base/scoped_temp_dir.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_SCOPED_TEMP_DIR_H_
+#define BASE_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/file_path.h"
+
+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);
+};
+
+#endif  // BASE_SCOPED_TEMP_DIR_H_
diff --git a/base/scoped_temp_dir_unittest.cc b/base/scoped_temp_dir_unittest.cc
new file mode 100644
index 0000000..eddea83
--- /dev/null
+++ b/base/scoped_temp_dir_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/file_util.h"
+#include "base/platform_file.h"
+#include "base/scoped_temp_dir.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ScopedTempDir, FullPath) {
+  FilePath test_path;
+  file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("scoped_temp_dir"),
+                                    &test_path);
+
+  // Against an existing dir, it should get destroyed when leaving scope.
+  EXPECT_TRUE(file_util::DirectoryExists(test_path));
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.Set(test_path));
+    EXPECT_TRUE(dir.IsValid());
+  }
+  EXPECT_FALSE(file_util::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(file_util::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(file_util::DirectoryExists(test_path));
+
+  // Clean up.
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.Set(test_path));
+  }
+  EXPECT_FALSE(file_util::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(file_util::DirectoryExists(test_path));
+    FilePath tmp_dir;
+    EXPECT_TRUE(file_util::GetTempDir(&tmp_dir));
+    EXPECT_TRUE(test_path.value().find(tmp_dir.value()) != std::string::npos);
+  }
+  EXPECT_FALSE(file_util::DirectoryExists(test_path));
+}
+
+TEST(ScopedTempDir, UniqueTempDirUnderPath) {
+  // Create a path which will contain a unique temp path.
+  FilePath base_path;
+  ASSERT_TRUE(file_util::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(file_util::DirectoryExists(test_path));
+    EXPECT_TRUE(base_path.IsParent(test_path));
+    EXPECT_TRUE(test_path.value().find(base_path.value()) != std::string::npos);
+  }
+  EXPECT_FALSE(file_util::DirectoryExists(test_path));
+  file_util::Delete(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());
+  int file_flags = base::PLATFORM_FILE_CREATE_ALWAYS |
+                   base::PLATFORM_FILE_WRITE;
+  base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
+  FilePath file_path(dir.path().Append(FILE_PATH_LITERAL("temp")));
+  base::PlatformFile file = base::CreatePlatformFile(file_path, file_flags,
+                                                     NULL, &error_code);
+  EXPECT_NE(base::kInvalidPlatformFileValue, file);
+  EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+  EXPECT_FALSE(dir.Delete());  // We should not be able to delete.
+  EXPECT_FALSE(dir.path().empty());  // We should still have a valid path.
+  EXPECT_TRUE(base::ClosePlatformFile(file));
+  // Now, we should be able to delete.
+  EXPECT_TRUE(dir.Delete());
+}
+#endif  // defined(OS_WIN)
diff --git a/base/sequenced_task_runner.cc b/base/sequenced_task_runner.cc
new file mode 100644
index 0000000..00d4048
--- /dev/null
+++ b/base/sequenced_task_runner.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sequenced_task_runner.h"
+
+#include "base/bind.h"
+
+namespace base {
+
+bool SequencedTaskRunner::PostNonNestableTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return PostNonNestableDelayedTask(from_here, task, base::TimeDelta());
+}
+
+bool SequencedTaskRunner::DeleteSoonInternal(
+    const tracked_objects::Location& from_here,
+    void(*deleter)(const void*),
+    const void* object) {
+  return PostNonNestableTask(from_here, Bind(deleter, object));
+}
+
+bool SequencedTaskRunner::ReleaseSoonInternal(
+    const tracked_objects::Location& from_here,
+    void(*releaser)(const void*),
+    const void* object) {
+  return PostNonNestableTask(from_here, Bind(releaser, object));
+}
+
+}  // namespace base
diff --git a/base/sequenced_task_runner.h b/base/sequenced_task_runner.h
new file mode 100644
index 0000000..2e999c7
--- /dev/null
+++ b/base/sequenced_task_runner.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_SEQUENCED_TASKRUNNER_H_
+#define BASE_SEQUENCED_TASKRUNNER_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
+// -------
+// Barring delayed/non-nestable tasks, tasks posted 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;
+//       * 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 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 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:
+  virtual ~SequencedTaskRunner() {}
+
+ 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_TASKRUNNER_H_
diff --git a/base/sequenced_task_runner_helpers.h b/base/sequenced_task_runner_helpers.h
new file mode 100644
index 0000000..2d0d493
--- /dev/null
+++ b/base/sequenced_task_runner_helpers.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
+#define BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
+
+#include "base/basictypes.h"
+
+// TODO(akalin): Investigate whether it's possible to just have
+// SequencedTaskRunner use these helpers (instead of MessageLoop).
+// Then we can just move these to sequenced_task_runner.h.
+
+namespace tracked_objects {
+class Location;
+}
+
+namespace base {
+
+namespace subtle {
+template <class T, class R> class DeleteHelperInternal;
+template <class T, class R> class ReleaseHelperInternal;
+}
+
+// Template helpers which use function indirection to erase T from the
+// function signature while still remembering it so we can call the
+// correct destructor/release function.
+//
+// We use this trick so we don't need to include bind.h in a header
+// file like sequenced_task_runner.h. We also wrap the helpers in a
+// templated class to make it easier for users of DeleteSoon to
+// declare the helper as a friend.
+template <class T>
+class DeleteHelper {
+ private:
+  template <class T2, class R> friend class subtle::DeleteHelperInternal;
+
+  static void DoDelete(const void* object) {
+    delete reinterpret_cast<const T*>(object);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteHelper);
+};
+
+template <class T>
+class ReleaseHelper {
+ private:
+  template <class T2, class R> friend class subtle::ReleaseHelperInternal;
+
+  static void DoRelease(const void* object) {
+    reinterpret_cast<const T*>(object)->Release();
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ReleaseHelper);
+};
+
+namespace subtle {
+
+// An internal SequencedTaskRunner-like class helper for DeleteHelper
+// and ReleaseHelper.  We don't want to expose the Do*() functions
+// directly directly since the void* argument makes it possible to
+// pass/ an object of the wrong type to delete.  Instead, we force
+// callers to go through these internal helpers for type
+// safety. SequencedTaskRunner-like classes which expose DeleteSoon or
+// ReleaseSoon methods should friend the appropriate helper and
+// implement a corresponding *Internal method with the following
+// signature:
+//
+// bool(const tracked_objects::Location&,
+//      void(*function)(const void*),
+//      void* object)
+//
+// An implementation of this function should simply create a
+// base::Closure from (function, object) and return the result of
+// posting the task.
+template <class T, class ReturnType>
+class DeleteHelperInternal {
+ public:
+  template <class SequencedTaskRunnerType>
+  static ReturnType DeleteViaSequencedTaskRunner(
+      SequencedTaskRunnerType* sequenced_task_runner,
+      const tracked_objects::Location& from_here,
+      const T* object) {
+    return sequenced_task_runner->DeleteSoonInternal(
+        from_here, &DeleteHelper<T>::DoDelete, object);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DeleteHelperInternal);
+};
+
+template <class T, class ReturnType>
+class ReleaseHelperInternal {
+ public:
+  template <class SequencedTaskRunnerType>
+  static ReturnType ReleaseViaSequencedTaskRunner(
+      SequencedTaskRunnerType* sequenced_task_runner,
+      const tracked_objects::Location& from_here,
+      const T* object) {
+    return sequenced_task_runner->ReleaseSoonInternal(
+        from_here, &ReleaseHelper<T>::DoRelease, object);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReleaseHelperInternal);
+};
+
+}  // namespace subtle
+
+}  // namespace base
+
+#endif  // BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
diff --git a/base/sha1.h b/base/sha1.h
new file mode 100644
index 0000000..998cccb
--- /dev/null
+++ b/base/sha1.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SHA1_H_
+#define BASE_SHA1_H_
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// These functions perform SHA-1 operations.
+
+static const size_t kSHA1Length = 20;  // Length in bytes of a SHA-1 hash.
+
+// Computes the SHA-1 hash of the input string |str| and returns the full
+// hash.
+BASE_EXPORT std::string SHA1HashString(const std::string& str);
+
+// Computes the SHA-1 hash of the |len| bytes in |data| and puts the hash
+// in |hash|. |hash| must be kSHA1Length bytes long.
+BASE_EXPORT void SHA1HashBytes(const unsigned char* data, size_t len,
+                               unsigned char* hash);
+
+}  // namespace base
+
+#endif  // BASE_SHA1_H_
diff --git a/base/sha1_portable.cc b/base/sha1_portable.cc
new file mode 100644
index 0000000..529fc90
--- /dev/null
+++ b/base/sha1_portable.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 "base/sha1.h"
+
+#include <string.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Implementation of SHA-1. Only handles data in byte-sized blocks,
+// which simplifies the code a fair bit.
+
+// Identifier names follow notation in FIPS PUB 180-3, where you'll
+// also find a description of the algorithm:
+// http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf
+
+// Usage example:
+//
+// SecureHashAlgorithm sha;
+// while(there is data to hash)
+//   sha.Update(moredata, size of data);
+// sha.Final();
+// memcpy(somewhere, sha.Digest(), 20);
+//
+// to reuse the instance of sha, call sha.Init();
+
+// TODO(jhawkins): Replace this implementation with a per-platform
+// implementation using each platform's crypto library.  See
+// http://crbug.com/47218
+
+class SecureHashAlgorithm {
+ public:
+  SecureHashAlgorithm() { Init(); }
+
+  static const int kDigestSizeBytes;
+
+  void Init();
+  void Update(const void* data, size_t nbytes);
+  void Final();
+
+  // 20 bytes of message digest.
+  const unsigned char* Digest() const {
+    return reinterpret_cast<const unsigned char*>(H);
+  }
+
+ private:
+  void Pad();
+  void Process();
+
+  uint32 A, B, C, D, E;
+
+  uint32 H[5];
+
+  union {
+    uint32 W[80];
+    uint8 M[64];
+  };
+
+  uint32 cursor;
+  uint32 l;
+};
+
+static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) {
+  if (t < 20) {
+    return (B & C) | ((~B) & D);
+  } else if (t < 40) {
+    return B ^ C ^ D;
+  } else if (t < 60) {
+    return (B & C) | (B & D) | (C & D);
+  } else {
+    return B ^ C ^ D;
+  }
+}
+
+static inline uint32 S(uint32 n, uint32 X) {
+  return (X << n) | (X >> (32-n));
+}
+
+static inline uint32 K(uint32 t) {
+  if (t < 20) {
+    return 0x5a827999;
+  } else if (t < 40) {
+    return 0x6ed9eba1;
+  } else if (t < 60) {
+    return 0x8f1bbcdc;
+  } else {
+    return 0xca62c1d6;
+  }
+}
+
+static inline void swapends(uint32* t) {
+  *t = ((*t & 0xff000000) >> 24) |
+       ((*t & 0xff0000) >> 8) |
+       ((*t & 0xff00) << 8) |
+       ((*t & 0xff) << 24);
+}
+
+const int SecureHashAlgorithm::kDigestSizeBytes = 20;
+
+void SecureHashAlgorithm::Init() {
+  A = 0;
+  B = 0;
+  C = 0;
+  D = 0;
+  E = 0;
+  cursor = 0;
+  l = 0;
+  H[0] = 0x67452301;
+  H[1] = 0xefcdab89;
+  H[2] = 0x98badcfe;
+  H[3] = 0x10325476;
+  H[4] = 0xc3d2e1f0;
+}
+
+void SecureHashAlgorithm::Final() {
+  Pad();
+  Process();
+
+  for (int t = 0; t < 5; ++t)
+    swapends(&H[t]);
+}
+
+void SecureHashAlgorithm::Update(const void* data, size_t nbytes) {
+  const uint8* d = reinterpret_cast<const uint8*>(data);
+  while (nbytes--) {
+    M[cursor++] = *d++;
+    if (cursor >= 64)
+      Process();
+    l += 8;
+  }
+}
+
+void SecureHashAlgorithm::Pad() {
+  M[cursor++] = 0x80;
+
+  if (cursor > 64-8) {
+    // pad out to next block
+    while (cursor < 64)
+      M[cursor++] = 0;
+
+    Process();
+  }
+
+  while (cursor < 64-4)
+    M[cursor++] = 0;
+
+  M[64-4] = (l & 0xff000000) >> 24;
+  M[64-3] = (l & 0xff0000) >> 16;
+  M[64-2] = (l & 0xff00) >> 8;
+  M[64-1] = (l & 0xff);
+}
+
+void SecureHashAlgorithm::Process() {
+  uint32 t;
+
+  // Each a...e corresponds to a section in the FIPS 180-3 algorithm.
+
+  // a.
+  //
+  // W and M are in a union, so no need to memcpy.
+  // memcpy(W, M, sizeof(M));
+  for (t = 0; t < 16; ++t)
+    swapends(&W[t]);
+
+  // b.
+  for (t = 16; t < 80; ++t)
+    W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]);
+
+  // c.
+  A = H[0];
+  B = H[1];
+  C = H[2];
+  D = H[3];
+  E = H[4];
+
+  // d.
+  for (t = 0; t < 80; ++t) {
+    uint32 TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t);
+    E = D;
+    D = C;
+    C = S(30, B);
+    B = A;
+    A = TEMP;
+  }
+
+  // e.
+  H[0] += A;
+  H[1] += B;
+  H[2] += C;
+  H[3] += D;
+  H[4] += E;
+
+  cursor = 0;
+}
+
+std::string SHA1HashString(const std::string& str) {
+  char hash[SecureHashAlgorithm::kDigestSizeBytes];
+  SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.c_str()),
+                str.length(), reinterpret_cast<unsigned char*>(hash));
+  return std::string(hash, SecureHashAlgorithm::kDigestSizeBytes);
+}
+
+void SHA1HashBytes(const unsigned char* data, size_t len,
+                   unsigned char* hash) {
+  SecureHashAlgorithm sha;
+  sha.Update(data, len);
+  sha.Final();
+
+  memcpy(hash, sha.Digest(), SecureHashAlgorithm::kDigestSizeBytes);
+}
+
+}  // namespace base
diff --git a/base/sha1_unittest.cc b/base/sha1_unittest.cc
new file mode 100644
index 0000000..b29fe46
--- /dev/null
+++ b/base/sha1_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sha1.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SHA1Test, Test1) {
+  // Example A.1 from FIPS 180-2: one-block message.
+  std::string input = "abc";
+
+  int expected[] = { 0xa9, 0x99, 0x3e, 0x36,
+                     0x47, 0x06, 0x81, 0x6a,
+                     0xba, 0x3e, 0x25, 0x71,
+                     0x78, 0x50, 0xc2, 0x6c,
+                     0x9c, 0xd0, 0xd8, 0x9d };
+
+  std::string output = base::SHA1HashString(input);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test2) {
+  // Example A.2 from FIPS 180-2: multi-block message.
+  std::string input =
+      "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+
+  int expected[] = { 0x84, 0x98, 0x3e, 0x44,
+                     0x1c, 0x3b, 0xd2, 0x6e,
+                     0xba, 0xae, 0x4a, 0xa1,
+                     0xf9, 0x51, 0x29, 0xe5,
+                     0xe5, 0x46, 0x70, 0xf1 };
+
+  std::string output = base::SHA1HashString(input);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test3) {
+  // Example A.3 from FIPS 180-2: long message.
+  std::string input(1000000, 'a');
+
+  int expected[] = { 0x34, 0xaa, 0x97, 0x3c,
+                     0xd4, 0xc4, 0xda, 0xa4,
+                     0xf6, 0x1e, 0xeb, 0x2b,
+                     0xdb, 0xad, 0x27, 0x31,
+                     0x65, 0x34, 0x01, 0x6f };
+
+  std::string output = base::SHA1HashString(input);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test1Bytes) {
+  // Example A.1 from FIPS 180-2: one-block message.
+  std::string input = "abc";
+  unsigned char output[base::kSHA1Length];
+
+  unsigned char expected[] = { 0xa9, 0x99, 0x3e, 0x36,
+                               0x47, 0x06, 0x81, 0x6a,
+                               0xba, 0x3e, 0x25, 0x71,
+                               0x78, 0x50, 0xc2, 0x6c,
+                               0x9c, 0xd0, 0xd8, 0x9d };
+
+  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
+                      input.length(), output);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i]);
+}
+
+TEST(SHA1Test, Test2Bytes) {
+  // Example A.2 from FIPS 180-2: multi-block message.
+  std::string input =
+      "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+  unsigned char output[base::kSHA1Length];
+
+  unsigned char expected[] = { 0x84, 0x98, 0x3e, 0x44,
+                               0x1c, 0x3b, 0xd2, 0x6e,
+                               0xba, 0xae, 0x4a, 0xa1,
+                               0xf9, 0x51, 0x29, 0xe5,
+                               0xe5, 0x46, 0x70, 0xf1 };
+
+  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
+                      input.length(), output);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i]);
+}
+
+TEST(SHA1Test, Test3Bytes) {
+  // Example A.3 from FIPS 180-2: long message.
+  std::string input(1000000, 'a');
+  unsigned char output[base::kSHA1Length];
+
+  unsigned char expected[] = { 0x34, 0xaa, 0x97, 0x3c,
+                               0xd4, 0xc4, 0xda, 0xa4,
+                               0xf6, 0x1e, 0xeb, 0x2b,
+                               0xdb, 0xad, 0x27, 0x31,
+                               0x65, 0x34, 0x01, 0x6f };
+
+  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
+                      input.length(), output);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i]);
+}
diff --git a/base/sha1_win.cc b/base/sha1_win.cc
new file mode 100644
index 0000000..626f41b
--- /dev/null
+++ b/base/sha1_win.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sha1.h"
+
+#include <windows.h>
+#include <wincrypt.h>
+
+// This file is not being compiled at the moment (see bug 47218). If we keep
+// sha1 inside base, we cannot depend on src/crypto.
+// #include "crypto/scoped_capi_types.h"
+#include "base/logging.h"
+
+namespace base {
+
+std::string SHA1HashString(const std::string& str) {
+  ScopedHCRYPTPROV provider;
+  if (!CryptAcquireContext(provider.receive(), NULL, NULL, PROV_RSA_FULL,
+                           CRYPT_VERIFYCONTEXT)) {
+    DLOG(ERROR) << "CryptAcquireContext failed: " << GetLastError();
+    return std::string(kSHA1Length, '\0');
+  }
+
+  {
+    ScopedHCRYPTHASH hash;
+    if (!CryptCreateHash(provider, CALG_SHA1, 0, 0, hash.receive())) {
+      DLOG(ERROR) << "CryptCreateHash failed: " << GetLastError();
+      return std::string(kSHA1Length, '\0');
+    }
+
+    if (!CryptHashData(hash, reinterpret_cast<CONST BYTE*>(str.data()),
+                       static_cast<DWORD>(str.length()), 0)) {
+      DLOG(ERROR) << "CryptHashData failed: " << GetLastError();
+      return std::string(kSHA1Length, '\0');
+    }
+
+    DWORD hash_len = 0;
+    DWORD buffer_size = sizeof hash_len;
+    if (!CryptGetHashParam(hash, HP_HASHSIZE,
+                           reinterpret_cast<unsigned char*>(&hash_len),
+                           &buffer_size, 0)) {
+      DLOG(ERROR) << "CryptGetHashParam(HP_HASHSIZE) failed: "
+                  << GetLastError();
+      return std::string(kSHA1Length, '\0');
+    }
+
+    std::string result;
+    if (!CryptGetHashParam(hash, HP_HASHVAL,
+        // We need the + 1 here not because the call will write a trailing \0,
+        // but so that result.length() is correctly set to |hash_len|.
+        reinterpret_cast<BYTE*>(WriteInto(&result, hash_len + 1)), &hash_len,
+        0))) {
+      DLOG(ERROR) << "CryptGetHashParam(HP_HASHVAL) failed: "
+                  << GetLastError();
+      return std::string(kSHA1Length, '\0');
+    }
+
+    if (hash_len != kSHA1Length) {
+      DLOG(ERROR) << "Returned hash value is wrong length: " << hash_len
+                  << " should be " << kSHA1Length;
+      return std::string(kSHA1Length, '\0');
+    }
+
+    return result;
+  }
+}
+
+}  // namespace base
diff --git a/base/shared_memory.h b/base/shared_memory.h
new file mode 100644
index 0000000..1f8237e
--- /dev/null
+++ b/base/shared_memory.h
@@ -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.
+
+#ifndef BASE_SHARED_MEMORY_H_
+#define BASE_SHARED_MEMORY_H_
+
+#include "build/build_config.h"
+
+#include <string>
+
+#if defined(OS_POSIX)
+#include <stdio.h>
+#include <sys/types.h>
+#include <semaphore.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/process.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+class FilePath;
+
+namespace base {
+
+// SharedMemoryHandle is a platform specific type which represents
+// the underlying OS handle to a shared memory segment.
+#if defined(OS_WIN)
+typedef HANDLE SharedMemoryHandle;
+typedef HANDLE SharedMemoryLock;
+#elif defined(OS_POSIX)
+// A SharedMemoryId is sufficient to identify a given shared memory segment on a
+// system, but insufficient to map it.
+typedef FileDescriptor SharedMemoryHandle;
+typedef ino_t SharedMemoryId;
+// On POSIX, the lock is implemented as a lockf() on the mapped file,
+// so no additional member (or definition of SharedMemoryLock) is
+// needed.
+#endif
+
+// Options for creating a shared memory object.
+struct SharedMemoryCreateOptions {
+  SharedMemoryCreateOptions() : name(NULL), size(0), open_existing(false),
+                                executable(false) {}
+
+  // 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;
+
+  // Size of the shared memory object to be created.
+  // When opening an existing object, this has no effect.
+  uint32 size;
+
+  // 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 is
+  // non-NULL.
+  bool open_existing;
+
+  // If true, mappings might need to be made executable later.
+  bool executable;
+};
+
+// 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 Lock() 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.
+  SharedMemory(SharedMemoryHandle handle, bool read_only);
+
+  // Create a new SharedMemory object from an existing, open
+  // shared memory file that was created by a remote process and not shared
+  // to the current process.
+  SharedMemory(SharedMemoryHandle handle, bool read_only,
+               ProcessHandle process);
+
+  // Closes any open files.
+  ~SharedMemory();
+
+  // Return true iff the given handle is valid (i.e. not the distingished
+  // invalid value; NULL for a HANDLE and -1 for a file descriptor)
+  static bool IsHandleValid(const SharedMemoryHandle& handle);
+
+  // Returns invalid handle (see comment above for exact definition).
+  static SharedMemoryHandle NULLHandle();
+
+  // Closes a shared memory handle.
+  static void CloseHandle(const SharedMemoryHandle& handle);
+
+  // 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(uint32 size);
+
+  // Creates an anonymous shared memory segment of size size.
+  // Returns true on success and false on failure.
+  bool CreateAnonymous(uint32 size) {
+    SharedMemoryCreateOptions options;
+    options.size = size;
+    return Create(options);
+  }
+
+  // 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 CreateNamed(const std::string& name, bool open_existing, uint32 size) {
+    SharedMemoryCreateOptions options;
+    options.name = &name;
+    options.open_existing = open_existing;
+    options.size = size;
+    return Create(options);
+  }
+
+  // Deletes resources associated with a shared memory segment based on name.
+  // Not all platforms require this call.
+  bool Delete(const std::string& name);
+
+  // Opens a shared memory segment based on a name.
+  // If read_only is true, opens for read-only access.
+  // Returns true on success, false on failure.
+  bool Open(const std::string& name, bool read_only);
+
+  // Maps the shared memory into the caller's address space.
+  // Returns true on success, false otherwise.  The memory address
+  // is accessed via the memory() accessor.  The mapped address is guaranteed to
+  // have an alignment of at least MAP_MINIMUM_ALIGNMENT.
+  bool Map(uint32 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();
+
+  // Get the size of the shared memory backing file.
+  // Note:  This size is only available to the creator of the
+  // shared memory, and not to those that opened shared memory
+  // created externally.
+  // Returns 0 if not created or unknown.
+  // Deprecated method, please keep track of the size yourself if you created
+  // it.
+  // http://crbug.com/60821
+  uint32 created_size() const { return created_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;
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+  // Returns a unique identifier for this shared memory segment. Inode numbers
+  // are technically only unique to a single filesystem. However, we always
+  // allocate shared memory backing files from the same directory, so will end
+  // up on the same filesystem.
+  SharedMemoryId id() const { return inode_; }
+#endif
+
+  // Closes the open shared memory segment.
+  // 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 access the shared memory
+  // file.  new_handle is an ouput 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);
+  }
+
+  // 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);
+  }
+
+  // Locks the shared memory.
+  //
+  // WARNING: on POSIX the memory locking primitive only works across
+  // processes, not across threads.  The Lock method is not currently
+  // used in inner loops, so we protect against multiple threads in a
+  // critical section using a class global lock.
+  void Lock();
+
+#if defined(OS_WIN)
+  // A Lock() implementation with a timeout that also allows setting
+  // security attributes on the mutex. sec_attr may be NULL.
+  // Returns true if the Lock() has been acquired, false if the timeout was
+  // reached.
+  bool Lock(uint32 timeout_ms, SECURITY_ATTRIBUTES* sec_attr);
+#endif
+
+  // Releases the shared memory lock.
+  void Unlock();
+
+ private:
+#if defined(OS_POSIX) && !defined(OS_NACL)
+  bool PrepareMapFile(FILE *fp);
+  bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
+  void LockOrUnlockCommon(int function);
+#endif
+  bool ShareToProcessCommon(ProcessHandle process,
+                            SharedMemoryHandle* new_handle,
+                            bool close_self);
+
+#if defined(OS_WIN)
+  std::wstring       name_;
+  HANDLE             mapped_file_;
+#elif defined(OS_POSIX)
+  int                mapped_file_;
+  uint32             mapped_size_;
+  ino_t              inode_;
+#endif
+  void*              memory_;
+  bool               read_only_;
+  uint32             created_size_;
+#if !defined(OS_POSIX)
+  SharedMemoryLock   lock_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(SharedMemory);
+};
+
+// A helper class that acquires the shared memory lock while
+// the SharedMemoryAutoLock is in scope.
+class SharedMemoryAutoLock {
+ public:
+  explicit SharedMemoryAutoLock(SharedMemory* shared_memory)
+      : shared_memory_(shared_memory) {
+    shared_memory_->Lock();
+  }
+
+  ~SharedMemoryAutoLock() {
+    shared_memory_->Unlock();
+  }
+
+ private:
+  SharedMemory* shared_memory_;
+  DISALLOW_COPY_AND_ASSIGN(SharedMemoryAutoLock);
+};
+
+}  // namespace base
+
+#endif  // BASE_SHARED_MEMORY_H_
diff --git a/base/shared_memory_android.cc b/base/shared_memory_android.cc
new file mode 100644
index 0000000..a5beceb
--- /dev/null
+++ b/base/shared_memory_android.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/shared_memory.h"
+
+#include <sys/mman.h>
+
+#include "base/logging.h"
+#include "third_party/ashmem/ashmem.h"
+
+namespace base {
+
+// For Android, we use ashmem to implement SharedMemory. ashmem_create_region
+// will automatically pin the region. We never explicitly call pin/unpin. When
+// all the file descriptors from different processes associated with the region
+// are closed, the memory buffer will go away.
+
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  DCHECK_EQ(-1, mapped_file_ );
+
+  // "name" is just a label in ashmem. It is visible in /proc/pid/maps.
+  mapped_file_ = ashmem_create_region(
+      options.name == NULL ? "" : options.name->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;
+  }
+  created_size_ = options.size;
+
+  return true;
+}
+
+bool SharedMemory::Delete(const std::string& name) {
+  // Like on Windows, this is intentionally returning true as ashmem will
+  // automatically releases the resource when all FDs on it are closed.
+  return true;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  // ashmem doesn't support name mapping
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace base
diff --git a/base/shared_memory_nacl.cc b/base/shared_memory_nacl.cc
new file mode 100644
index 0000000..fef2937
--- /dev/null
+++ b/base/shared_memory_nacl.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/shared_memory.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+SharedMemory::SharedMemory()
+    : mapped_file_(-1),
+      mapped_size_(0),
+      inode_(0),
+      memory_(NULL),
+      read_only_(false),
+      created_size_(0) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+    : mapped_file_(handle.fd),
+      mapped_size_(0),
+      inode_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      created_size_(0) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+                           ProcessHandle process)
+    : mapped_file_(handle.fd),
+      mapped_size_(0),
+      inode_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      created_size_(0) {
+  NOTREACHED();
+}
+
+SharedMemory::~SharedMemory() {
+  Close();
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle.fd >= 0;
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return SharedMemoryHandle();
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  DCHECK_GE(handle.fd, 0);
+  if (close(handle.fd) < 0)
+    DPLOG(ERROR) << "close";
+}
+
+bool SharedMemory::CreateAndMapAnonymous(uint32 size) {
+  // Untrusted code can't create descriptors or handles.
+  return false;
+}
+
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  // Untrusted code can't create descriptors or handles.
+  return false;
+}
+
+bool SharedMemory::Delete(const std::string& name) {
+  return false;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  return false;
+}
+
+bool SharedMemory::Map(uint32 bytes) {
+  if (mapped_file_ == -1)
+    return false;
+
+  memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
+                 MAP_SHARED, mapped_file_, 0);
+
+  bool mmap_succeeded = memory_ != MAP_FAILED && memory_ != NULL;
+  if (mmap_succeeded) {
+    mapped_size_ = bytes;
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+        (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+  } else {
+    memory_ = NULL;
+  }
+
+  return mmap_succeeded;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  if (munmap(memory_, mapped_size_) < 0)
+    DPLOG(ERROR) << "munmap";
+  memory_ = NULL;
+  mapped_size_ = 0;
+  return true;
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  return FileDescriptor(mapped_file_, false);
+}
+
+void SharedMemory::Close() {
+  Unmap();
+
+  if (mapped_file_ > 0) {
+    if (close(mapped_file_) < 0)
+      DPLOG(ERROR) << "close";
+    mapped_file_ = -1;
+  }
+}
+
+void SharedMemory::Lock() {
+  NOTIMPLEMENTED();
+}
+
+void SharedMemory::Unlock() {
+  NOTIMPLEMENTED();
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle *new_handle,
+                                        bool close_self) {
+  return false;
+}
+
+}  // namespace base
diff --git a/base/shared_memory_posix.cc b/base/shared_memory_posix.cc
new file mode 100644
index 0000000..d2bb219
--- /dev/null
+++ b/base/shared_memory_posix.cc
@@ -0,0 +1,379 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/shared_memory.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+#include "base/safe_strerror_posix.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/utf_string_conversions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif  // OS_MACOSX
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#include "third_party/ashmem/ashmem.h"
+#endif
+
+namespace base {
+
+namespace {
+
+// Paranoia. Semaphores and shared memory segments should live in different
+// namespaces, but who knows what's out there.
+const char kSemaphoreSuffix[] = "-sem";
+
+LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER;
+
+}
+
+SharedMemory::SharedMemory()
+    : mapped_file_(-1),
+      mapped_size_(0),
+      inode_(0),
+      memory_(NULL),
+      read_only_(false),
+      created_size_(0) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+    : mapped_file_(handle.fd),
+      mapped_size_(0),
+      inode_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      created_size_(0) {
+  struct stat st;
+  if (fstat(handle.fd, &st) == 0) {
+    // If fstat fails, then the file descriptor is invalid and we'll learn this
+    // fact when Map() fails.
+    inode_ = st.st_ino;
+  }
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+                           ProcessHandle process)
+    : mapped_file_(handle.fd),
+      mapped_size_(0),
+      inode_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      created_size_(0) {
+  // We don't handle this case yet (note the ignored parameter); let's die if
+  // someone comes calling.
+  NOTREACHED();
+}
+
+SharedMemory::~SharedMemory() {
+  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 (HANDLE_EINTR(close(handle.fd)) < 0)
+    DPLOG(ERROR) << "close";
+}
+
+bool SharedMemory::CreateAndMapAnonymous(uint32 size) {
+  return CreateAnonymous(size) && Map(size);
+}
+
+#if !defined(OS_ANDROID)
+// 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) {
+  DCHECK_EQ(-1, mapped_file_);
+  if (options.size == 0) 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;
+
+  FILE *fp;
+  bool fix_size = true;
+
+  FilePath path;
+  if (options.name == NULL || options.name->empty()) {
+    // It doesn't make sense to have a open-existing private piece of shmem
+    DCHECK(!options.open_existing);
+    // Q: Why not use the shm_open() etc. APIs?
+    // A: Because they're limited to 4mb on OS X.  FFFFFFFUUUUUUUUUUU
+    fp = file_util::CreateAndOpenTemporaryShmemFile(&path, options.executable);
+
+    // 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)
+      file_util::Delete(path, false);
+
+  } else {
+    if (!FilePathForMemoryName(*options.name, &path))
+      return false;
+
+    fp = file_util::OpenFile(path, "w+x");
+    if (fp == NULL && options.open_existing) {
+      // "w+" will truncate if it already exists.
+      fp = file_util::OpenFile(path, "a+");
+      fix_size = false;
+    }
+  }
+  if (fp && fix_size) {
+    // Get current size.
+    struct stat stat;
+    if (fstat(fileno(fp), &stat) != 0) {
+      file_util::CloseFile(fp);
+      return false;
+    }
+    const uint32 current_size = stat.st_size;
+    if (current_size != options.size) {
+      if (HANDLE_EINTR(ftruncate(fileno(fp), options.size)) != 0) {
+        file_util::CloseFile(fp);
+        return false;
+      }
+      if (fseeko(fp, options.size, SEEK_SET) != 0) {
+        file_util::CloseFile(fp);
+        return false;
+      }
+    }
+    created_size_ = options.size;
+  }
+  if (fp == NULL) {
+#if !defined(OS_MACOSX)
+    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+    FilePath dir = path.DirName();
+    if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
+      PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
+      if (dir.value() == "/dev/shm") {
+        LOG(FATAL) << "This is frequently caused by incorrect permissions on "
+                   << "/dev/shm.  Try 'sudo chmod 1777 /dev/shm' to fix.";
+      }
+    }
+#else
+    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+#endif
+    return false;
+  }
+
+  return PrepareMapFile(fp);
+}
+
+// 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 (file_util::PathExists(path)) {
+    return file_util::Delete(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+";
+  FILE *fp = file_util::OpenFile(path, mode);
+  return PrepareMapFile(fp);
+}
+
+#endif  // !defined(OS_ANDROID)
+
+bool SharedMemory::Map(uint32 bytes) {
+  if (mapped_file_ == -1)
+    return false;
+
+#if defined(OS_ANDROID)
+  if (bytes == 0) {
+    int ashmem_bytes = ashmem_get_size_region(mapped_file_);
+    if (ashmem_bytes < 0)
+      return false;
+
+    DCHECK_GE(static_cast<uint32>(ashmem_bytes), bytes);
+    // The caller wants to determine the map region size from ashmem.
+    bytes = ashmem_bytes;
+    // TODO(port): we set the created size here so that it is available in
+    // transport_dib_android.cc. We should use ashmem_get_size_region()
+    // in transport_dib_android.cc.
+    created_size_ = bytes;
+  }
+#endif
+
+  memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
+                 MAP_SHARED, mapped_file_, 0);
+
+  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() {
+  Unmap();
+
+  if (mapped_file_ > 0) {
+    if (HANDLE_EINTR(close(mapped_file_)) < 0)
+      PLOG(ERROR) << "close";
+    mapped_file_ = -1;
+  }
+}
+
+void SharedMemory::Lock() {
+  g_thread_lock_.Get().Acquire();
+  LockOrUnlockCommon(F_LOCK);
+}
+
+void SharedMemory::Unlock() {
+  LockOrUnlockCommon(F_ULOCK);
+  g_thread_lock_.Get().Release();
+}
+
+#if !defined(OS_ANDROID)
+bool SharedMemory::PrepareMapFile(FILE *fp) {
+  DCHECK_EQ(-1, mapped_file_);
+  if (fp == NULL) return false;
+
+  // This function theoretically can block on the disk, but realistically
+  // the temporary files we create will just go into the buffer cache
+  // and be deleted before they ever make it out to disk.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  file_util::ScopedFILE file_closer(fp);
+
+  mapped_file_ = dup(fileno(fp));
+  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;
+    }
+  }
+
+  struct stat st;
+  if (fstat(mapped_file_, &st))
+    NOTREACHED();
+  inode_ = st.st_ino;
+
+  return true;
+}
+#endif
+
+// 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 (!file_util::GetShmemTempDir(&temp_dir, false))
+    return false;
+
+#if !defined(OS_MACOSX)
+#if defined(GOOGLE_CHROME_BUILD)
+  std::string name_base = std::string("com.google.Chrome");
+#else
+  std::string name_base = std::string("org.chromium.Chromium");
+#endif
+#else  // OS_MACOSX
+  std::string name_base = std::string(base::mac::BaseBundleID());
+#endif  // OS_MACOSX
+  *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name);
+  return true;
+}
+
+void SharedMemory::LockOrUnlockCommon(int function) {
+  DCHECK_GE(mapped_file_, 0);
+  while (lockf(mapped_file_, function, 0) < 0) {
+    if (errno == EINTR) {
+      continue;
+    } else if (errno == ENOLCK) {
+      // temporary kernel resource exaustion
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
+      continue;
+    } else {
+      NOTREACHED() << "lockf() failed."
+                   << " function:" << function
+                   << " fd:" << mapped_file_
+                   << " errno:" << errno
+                   << " msg:" << safe_strerror(errno);
+    }
+  }
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle *new_handle,
+                                        bool close_self) {
+  const int new_fd = dup(mapped_file_);
+  DCHECK_GE(new_fd, 0);
+  new_handle->fd = new_fd;
+  new_handle->auto_close = true;
+
+  if (close_self)
+    Close();
+
+  return true;
+}
+
+}  // namespace base
diff --git a/base/shared_memory_unittest.cc b/base/shared_memory_unittest.cc
new file mode 100644
index 0000000..bd53769
--- /dev/null
+++ b/base/shared_memory_unittest.cc
@@ -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.
+
+#include "base/basictypes.h"
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+#include "base/memory/scoped_ptr.h"
+#include "base/shared_memory.h"
+#include "base/test/multiprocess_test.h"
+#include "base/threading/platform_thread.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+#if defined(OS_POSIX)
+#include <sys/mman.h>
+#endif
+
+static const int kNumThreads = 5;
+static const int kNumTasks = 5;
+
+namespace base {
+
+namespace {
+
+// Each thread will open the shared memory.  Each thread will take a different 4
+// byte int pointer, and keep changing it, with some small pauses in between.
+// Verify that each thread's value in the shared memory is always correct.
+class MultipleThreadMain : public PlatformThread::Delegate {
+ public:
+  explicit MultipleThreadMain(int16 id) : id_(id) {}
+  virtual ~MultipleThreadMain() {}
+
+  static void CleanUp() {
+    SharedMemory memory;
+    memory.Delete(s_test_name_);
+  }
+
+  // PlatformThread::Delegate interface.
+  virtual void ThreadMain() OVERRIDE {
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool pool;
+#endif
+    const uint32 kDataSize = 1024;
+    SharedMemory memory;
+    bool rv = memory.CreateNamed(s_test_name_, true, kDataSize);
+    EXPECT_TRUE(rv);
+    rv = memory.Map(kDataSize);
+    EXPECT_TRUE(rv);
+    int *ptr = static_cast<int*>(memory.memory()) + id_;
+    EXPECT_EQ(0, *ptr);
+
+    for (int idx = 0; idx < 100; idx++) {
+      *ptr = idx;
+      PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
+      EXPECT_EQ(*ptr, idx);
+    }
+    // Reset back to 0 for the next test that uses the same name.
+    *ptr = 0;
+
+    memory.Close();
+  }
+
+ private:
+  int16 id_;
+
+  static const char* const s_test_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain);
+};
+
+const char* const MultipleThreadMain::s_test_name_ =
+    "SharedMemoryOpenThreadTest";
+
+// TODO(port):
+// This test requires the ability to pass file descriptors between processes.
+// We haven't done that yet in Chrome for POSIX.
+#if defined(OS_WIN)
+// Each thread will open the shared memory.  Each thread will take the memory,
+// and keep changing it while trying to lock it, with some small pauses in
+// between. Verify that each thread's value in the shared memory is always
+// correct.
+class MultipleLockThread : public PlatformThread::Delegate {
+ public:
+  explicit MultipleLockThread(int id) : id_(id) {}
+  virtual ~MultipleLockThread() {}
+
+  // PlatformThread::Delegate interface.
+  virtual void ThreadMain() OVERRIDE {
+    const uint32 kDataSize = sizeof(int);
+    SharedMemoryHandle handle = NULL;
+    {
+      SharedMemory memory1;
+      EXPECT_TRUE(memory1.CreateNamed("SharedMemoryMultipleLockThreadTest",
+                                 true, kDataSize));
+      EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle));
+      // TODO(paulg): Implement this once we have a posix version of
+      // SharedMemory::ShareToProcess.
+      EXPECT_TRUE(true);
+    }
+
+    SharedMemory memory2(handle, false);
+    EXPECT_TRUE(memory2.Map(kDataSize));
+    volatile int* const ptr = static_cast<int*>(memory2.memory());
+
+    for (int idx = 0; idx < 20; idx++) {
+      memory2.Lock();
+      int i = (id_ << 16) + idx;
+      *ptr = i;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
+      EXPECT_EQ(*ptr, i);
+      memory2.Unlock();
+    }
+
+    memory2.Close();
+  }
+
+ private:
+  int id_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultipleLockThread);
+};
+#endif
+
+}  // namespace
+
+// Android doesn't support SharedMemory::Open/Delete/
+// CreateNamed(openExisting=true)
+#if !defined(OS_ANDROID)
+TEST(SharedMemoryTest, OpenClose) {
+  const uint32 kDataSize = 1024;
+  std::string test_name = "SharedMemoryOpenCloseTest";
+
+  // Open two handles to a memory segment, confirm that they are mapped
+  // separately yet point to the same space.
+  SharedMemory memory1;
+  bool rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+  rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+  rv = memory1.Open(test_name, false);
+  EXPECT_FALSE(rv);
+  rv = memory1.CreateNamed(test_name, false, kDataSize);
+  EXPECT_TRUE(rv);
+  rv = memory1.Map(kDataSize);
+  EXPECT_TRUE(rv);
+  SharedMemory memory2;
+  rv = memory2.Open(test_name, false);
+  EXPECT_TRUE(rv);
+  rv = memory2.Map(kDataSize);
+  EXPECT_TRUE(rv);
+  EXPECT_NE(memory1.memory(), memory2.memory());  // Compare the pointers.
+
+  // Make sure we don't segfault. (it actually happened!)
+  ASSERT_NE(memory1.memory(), static_cast<void*>(NULL));
+  ASSERT_NE(memory2.memory(), static_cast<void*>(NULL));
+
+  // Write data to the first memory segment, verify contents of second.
+  memset(memory1.memory(), '1', kDataSize);
+  EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0);
+
+  // Close the first memory segment, and verify the second has the right data.
+  memory1.Close();
+  char *start_ptr = static_cast<char *>(memory2.memory());
+  char *end_ptr = start_ptr + kDataSize;
+  for (char* ptr = start_ptr; ptr < end_ptr; ptr++)
+    EXPECT_EQ(*ptr, '1');
+
+  // Close the second memory segment.
+  memory2.Close();
+
+  rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+  rv = memory2.Delete(test_name);
+  EXPECT_TRUE(rv);
+}
+
+TEST(SharedMemoryTest, OpenExclusive) {
+  const uint32 kDataSize = 1024;
+  const uint32 kDataSize2 = 2048;
+  std::ostringstream test_name_stream;
+  test_name_stream << "SharedMemoryOpenExclusiveTest."
+                   << Time::Now().ToDoubleT();
+  std::string test_name = test_name_stream.str();
+
+  // Open two handles to a memory segment and check that open_existing works
+  // as expected.
+  SharedMemory memory1;
+  bool rv = memory1.CreateNamed(test_name, false, kDataSize);
+  EXPECT_TRUE(rv);
+
+  // Memory1 knows it's size because it created it.
+  EXPECT_EQ(memory1.created_size(), kDataSize);
+
+  rv = memory1.Map(kDataSize);
+  EXPECT_TRUE(rv);
+
+  memset(memory1.memory(), 'G', kDataSize);
+
+  SharedMemory memory2;
+  // Should not be able to create if openExisting is false.
+  rv = memory2.CreateNamed(test_name, false, kDataSize2);
+  EXPECT_FALSE(rv);
+
+  // Should be able to create with openExisting true.
+  rv = memory2.CreateNamed(test_name, true, kDataSize2);
+  EXPECT_TRUE(rv);
+
+  // Memory2 shouldn't know the size because we didn't create it.
+  EXPECT_EQ(memory2.created_size(), 0U);
+
+  // We should be able to map the original size.
+  rv = memory2.Map(kDataSize);
+  EXPECT_TRUE(rv);
+
+  // 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
+
+// Create a set of N threads to each open a shared memory segment and write to
+// it. Verify that they are always reading/writing consistent data.
+TEST(SharedMemoryTest, MultipleThreads) {
+  MultipleThreadMain::CleanUp();
+  // On POSIX we have a problem when 2 threads try to create the shmem
+  // (a file) at exactly the same time, since create both creates the
+  // file and zerofills it.  We solve the problem for this unit test
+  // (make it not flaky) by starting with 1 thread, then
+  // intentionally don't clean up its shmem before running with
+  // kNumThreads.
+
+  int threadcounts[] = { 1, kNumThreads };
+  for (size_t i = 0; i < arraysize(threadcounts); i++) {
+    int numthreads = threadcounts[i];
+    scoped_array<PlatformThreadHandle> thread_handles;
+    scoped_array<MultipleThreadMain*> thread_delegates;
+
+    thread_handles.reset(new PlatformThreadHandle[numthreads]);
+    thread_delegates.reset(new MultipleThreadMain*[numthreads]);
+
+    // Spawn the threads.
+    for (int16 index = 0; index < numthreads; index++) {
+      PlatformThreadHandle pth;
+      thread_delegates[index] = new MultipleThreadMain(index);
+      EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
+      thread_handles[index] = pth;
+    }
+
+    // Wait for the threads to finish.
+    for (int index = 0; index < numthreads; index++) {
+      PlatformThread::Join(thread_handles[index]);
+      delete thread_delegates[index];
+    }
+  }
+  MultipleThreadMain::CleanUp();
+}
+
+// TODO(port): this test requires the MultipleLockThread class
+// (defined above), which requires the ability to pass file
+// descriptors between processes.  We haven't done that yet in Chrome
+// for POSIX.
+#if defined(OS_WIN)
+// Create a set of threads to each open a shared memory segment and write to it
+// with the lock held. Verify that they are always reading/writing consistent
+// data.
+TEST(SharedMemoryTest, Lock) {
+  PlatformThreadHandle thread_handles[kNumThreads];
+  MultipleLockThread* thread_delegates[kNumThreads];
+
+  // Spawn the threads.
+  for (int index = 0; index < kNumThreads; ++index) {
+    PlatformThreadHandle pth;
+    thread_delegates[index] = new MultipleLockThread(index);
+    EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
+    thread_handles[index] = pth;
+  }
+
+  // Wait for the threads to finish.
+  for (int index = 0; index < kNumThreads; ++index) {
+    PlatformThread::Join(thread_handles[index]);
+    delete thread_delegates[index];
+  }
+}
+#endif
+
+// Allocate private (unique) shared memory with an empty string for a
+// name.  Make sure several of them don't point to the same thing as
+// we might expect if the names are equal.
+TEST(SharedMemoryTest, AnonymousPrivate) {
+  int i, j;
+  int count = 4;
+  bool rv;
+  const uint32 kDataSize = 8192;
+
+  scoped_array<SharedMemory> memories(new SharedMemory[count]);
+  scoped_array<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();
+  }
+}
+
+#if defined(OS_POSIX)
+// Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
+TEST(SharedMemoryTest, AnonymousExecutable) {
+  const uint32 kTestSize = 1 << 16;
+
+  SharedMemory shared_memory;
+  SharedMemoryCreateOptions options;
+  options.size = kTestSize;
+  options.executable = true;
+
+  EXPECT_TRUE(shared_memory.Create(options));
+  EXPECT_TRUE(shared_memory.Map(shared_memory.created_size()));
+
+  EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.created_size(),
+                        PROT_READ | PROT_EXEC));
+}
+#endif
+
+// Map() will return addresses which are aligned to the platform page size, this
+// varies from platform to platform though.  Since we'd like to advertise a
+// minimum alignment that callers can count on, test for it here.
+TEST(SharedMemoryTest, MapMinimumAlignment) {
+  static const int kDataSize = 8192;
+
+  SharedMemory shared_memory;
+  ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize));
+  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(
+      shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+  shared_memory.Close();
+}
+
+#if !defined(OS_IOS)  // iOS does not allow multiple processes.
+
+// On POSIX it is especially important we test shmem across processes,
+// not just across threads.  But the test is enabled on all platforms.
+class SharedMemoryProcessTest : public MultiProcessTest {
+ public:
+
+  static void CleanUp() {
+    SharedMemory memory;
+    memory.Delete(s_test_name_);
+  }
+
+  static int TaskTestMain() {
+    int errors = 0;
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool pool;
+#endif
+    const uint32 kDataSize = 1024;
+    SharedMemory memory;
+    bool rv = memory.CreateNamed(s_test_name_, true, kDataSize);
+    EXPECT_TRUE(rv);
+    if (rv != true)
+      errors++;
+    rv = memory.Map(kDataSize);
+    EXPECT_TRUE(rv);
+    if (rv != true)
+      errors++;
+    int *ptr = static_cast<int*>(memory.memory());
+
+    for (int idx = 0; idx < 20; idx++) {
+      memory.Lock();
+      int i = (1 << 16) + idx;
+      *ptr = i;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
+      if (*ptr != i)
+        errors++;
+      memory.Unlock();
+    }
+
+    memory.Close();
+    return errors;
+  }
+
+ private:
+  static const char* const s_test_name_;
+};
+
+const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
+
+TEST_F(SharedMemoryProcessTest, Tasks) {
+  SharedMemoryProcessTest::CleanUp();
+
+  ProcessHandle handles[kNumTasks];
+  for (int index = 0; index < kNumTasks; ++index) {
+    handles[index] = SpawnChild("SharedMemoryTestMain", false);
+    ASSERT_TRUE(handles[index]);
+  }
+
+  int exit_code = 0;
+  for (int index = 0; index < kNumTasks; ++index) {
+    EXPECT_TRUE(WaitForExitCode(handles[index], &exit_code));
+    EXPECT_EQ(0, exit_code);
+  }
+
+  SharedMemoryProcessTest::CleanUp();
+}
+
+MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) {
+  return SharedMemoryProcessTest::TaskTestMain();
+}
+
+#endif  // !OS_IOS
+
+}  // namespace base
diff --git a/base/shared_memory_win.cc b/base/shared_memory_win.cc
new file mode 100644
index 0000000..a4f86cb
--- /dev/null
+++ b/base/shared_memory_win.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/shared_memory.h"
+
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+SharedMemory::SharedMemory()
+    : mapped_file_(NULL),
+      memory_(NULL),
+      read_only_(false),
+      created_size_(0),
+      lock_(NULL) {
+}
+
+SharedMemory::SharedMemory(const std::wstring& name)
+    : mapped_file_(NULL),
+      memory_(NULL),
+      read_only_(false),
+      created_size_(0),
+      lock_(NULL),
+      name_(name) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+    : mapped_file_(handle),
+      memory_(NULL),
+      read_only_(read_only),
+      created_size_(0),
+      lock_(NULL) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+                           ProcessHandle process)
+    : mapped_file_(NULL),
+      memory_(NULL),
+      read_only_(read_only),
+      created_size_(0),
+      lock_(NULL) {
+  ::DuplicateHandle(process, handle,
+                    GetCurrentProcess(), &mapped_file_,
+                    STANDARD_RIGHTS_REQUIRED |
+                    (read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS),
+                    FALSE, 0);
+}
+
+SharedMemory::~SharedMemory() {
+  Close();
+  if (lock_ != NULL)
+    CloseHandle(lock_);
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle != NULL;
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return NULL;
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  DCHECK(handle != NULL);
+  ::CloseHandle(handle);
+}
+
+bool SharedMemory::CreateAndMapAnonymous(uint32 size) {
+  return CreateAnonymous(size) && Map(size);
+}
+
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  DCHECK(!options.executable);
+  DCHECK(!mapped_file_);
+  if (options.size == 0)
+    return false;
+
+  // NaCl's memory allocator requires 0mod64K alignment and size for
+  // shared memory objects.  To allow passing shared memory to NaCl,
+  // therefore we round the size actually created to the nearest 64K unit.
+  // To avoid client impact, we continue to retain the size as the
+  // actual requested size.
+  uint32 rounded_size = (options.size + 0xffff) & ~0xffff;
+  name_ = ASCIIToWide(options.name == NULL ? "" : *options.name);
+  mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
+      PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size),
+      name_.empty() ? NULL : name_.c_str());
+  if (!mapped_file_)
+    return false;
+
+  created_size_ = options.size;
+
+  // Check if the shared memory pre-exists.
+  if (GetLastError() == ERROR_ALREADY_EXISTS) {
+    // If the file already existed, set created_size_ to 0 to show that
+    // we don't know the size.
+    created_size_ = 0;
+    if (!options.open_existing) {
+      Close();
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool SharedMemory::Delete(const std::string& name) {
+  // intentionally empty -- there is nothing for us to do on Windows.
+  return true;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  DCHECK(!mapped_file_);
+
+  name_ = ASCIIToWide(name);
+  read_only_ = read_only;
+  mapped_file_ = OpenFileMapping(
+      read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, false,
+      name_.empty() ? NULL : name_.c_str());
+  if (mapped_file_ != NULL) {
+    // Note: size_ is not set in this case.
+    return true;
+  }
+  return false;
+}
+
+bool SharedMemory::Map(uint32 bytes) {
+  if (mapped_file_ == NULL)
+    return false;
+
+  memory_ = MapViewOfFile(mapped_file_,
+      read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, 0, 0, bytes);
+  if (memory_ != NULL) {
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+        (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+    return true;
+  }
+  return false;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  UnmapViewOfFile(memory_);
+  memory_ = NULL;
+  return true;
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle *new_handle,
+                                        bool close_self) {
+  *new_handle = 0;
+  DWORD access = STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ;
+  DWORD options = 0;
+  HANDLE mapped_file = mapped_file_;
+  HANDLE result;
+  if (!read_only_)
+    access |= FILE_MAP_WRITE;
+  if (close_self) {
+    // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file.
+    options = DUPLICATE_CLOSE_SOURCE;
+    mapped_file_ = NULL;
+    Unmap();
+  }
+
+  if (process == GetCurrentProcess() && close_self) {
+    *new_handle = mapped_file;
+    return true;
+  }
+
+  if (!DuplicateHandle(GetCurrentProcess(), mapped_file, process,
+      &result, access, FALSE, options))
+    return false;
+  *new_handle = result;
+  return true;
+}
+
+
+void SharedMemory::Close() {
+  if (memory_ != NULL) {
+    UnmapViewOfFile(memory_);
+    memory_ = NULL;
+  }
+
+  if (mapped_file_ != NULL) {
+    CloseHandle(mapped_file_);
+    mapped_file_ = NULL;
+  }
+}
+
+void SharedMemory::Lock() {
+  Lock(INFINITE, NULL);
+}
+
+bool SharedMemory::Lock(uint32 timeout_ms, SECURITY_ATTRIBUTES* sec_attr) {
+  if (lock_ == NULL) {
+    std::wstring name = name_;
+    name.append(L"lock");
+    lock_ = CreateMutex(sec_attr, FALSE, name.c_str());
+    if (lock_ == NULL) {
+      DPLOG(ERROR) << "Could not create mutex.";
+      return false;  // there is nothing good we can do here.
+    }
+  }
+  DWORD result = WaitForSingleObject(lock_, timeout_ms);
+
+  // Return false for WAIT_ABANDONED, WAIT_TIMEOUT or WAIT_FAILED.
+  return (result == WAIT_OBJECT_0);
+}
+
+void SharedMemory::Unlock() {
+  DCHECK(lock_ != NULL);
+  ReleaseMutex(lock_);
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  return mapped_file_;
+}
+
+}  // namespace base
diff --git a/base/single_thread_task_runner.h b/base/single_thread_task_runner.h
new file mode 100644
index 0000000..993d829
--- /dev/null
+++ b/base/single_thread_task_runner.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_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 dedicated.
+//
+// Some theoretical implementations of SingleThreadTaskRunner:
+//
+//   - A SingleThreadTaskRunner that uses a single worker thread to
+//     run posted tasks (i.e., a message loop).
+//
+//   - A SingleThreadTaskRunner that stores the list of posted tasks
+//     and has a method Run() that runs each runnable task in FIFO
+//     order that must be run only from the thread the
+//     SingleThreadTaskRunner was created on.
+class BASE_EXPORT SingleThreadTaskRunner : public SequencedTaskRunner {
+ public:
+  // A more explicit alias to RunsTasksOnCurrentThread().
+  bool BelongsToCurrentThread() const {
+    return RunsTasksOnCurrentThread();
+  }
+
+ protected:
+  virtual ~SingleThreadTaskRunner() {}
+};
+
+}  // namespace base
+
+#endif  // BASE_SERIAL_TASK_RUNNER_H_
diff --git a/base/stl_util.h b/base/stl_util.h
new file mode 100644
index 0000000..b3ddfa3
--- /dev/null
+++ b/base/stl_util.h
@@ -0,0 +1,194 @@
+// Copyright (c) 2011 The Chromium 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 <string>
+#include <vector>
+
+// 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;
+  }
+}
+
+// To treat a possibly-empty vector as an array, use these functions.
+// If you know the array will never be empty, you can use &*v.begin()
+// directly, but that is undefined behaviour if |v| is empty.
+template<typename T>
+inline T* vector_as_array(std::vector<T>* v) {
+  return v->empty() ? NULL : &*v->begin();
+}
+
+template<typename T>
+inline const T* vector_as_array(const std::vector<T>* v) {
+  return v->empty() ? NULL : &*v->begin();
+}
+
+// Return a mutable char* pointing to a string's internal buffer,
+// which may not be null-terminated. Writing through this pointer will
+// modify the string.
+//
+// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
+// next call to a string method that invalidates iterators.
+//
+// As of 2006-04, there is no standard-blessed way of getting a
+// mutable reference to a string's internal buffer. However, issue 530
+// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
+// proposes this as the method. According to Matt Austern, this should
+// already work on all current implementations.
+inline char* string_as_array(std::string* str) {
+  // DO NOT USE const_cast<char*>(str->data())
+  return str->empty() ? NULL : &*str->begin();
+}
+
+// The following functions are useful for cleaning up STL containers whose
+// elements point to allocated memory.
+
+// STLDeleteElements() deletes all the elements in an STL container and clears
+// the container.  This function is suitable for use with a vector, set,
+// hash_set, or any other STL container which defines sensible begin(), end(),
+// and clear() methods.
+//
+// If container is NULL, this function is a no-op.
+//
+// As an alternative to calling STLDeleteElements() directly, consider
+// STLElementDeleter (defined below), which ensures that your container's
+// elements are deleted when the STLElementDeleter goes out of scope.
+template <class T>
+void STLDeleteElements(T* container) {
+  if (!container)
+    return;
+  STLDeleteContainerPointers(container->begin(), container->end());
+  container->clear();
+}
+
+// Given an STL container consisting of (key, value) pairs, STLDeleteValues
+// deletes all the "value" components and clears the container.  Does nothing
+// in the case it's given a NULL pointer.
+template <class T>
+void STLDeleteValues(T* container) {
+  if (!container)
+    return;
+  for (typename T::iterator i(container->begin()); i != container->end(); ++i)
+    delete i->second;
+  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();
+}
+
+#endif  // BASE_STL_UTIL_H_
diff --git a/base/string16.cc b/base/string16.cc
new file mode 100644
index 0000000..930e09f
--- /dev/null
+++ b/base/string16.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/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/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;
+}
+
+}  // namespace base
+
+template class std::basic_string<char16, base::string16_char_traits>;
+
+namespace base {
+std::ostream& operator<<(std::ostream& out, const string16& str) {
+  return out << UTF16ToUTF8(str);
+}
+
+void PrintTo(const string16& str, std::ostream* out) {
+  *out << str;
+}
+}
+
+#endif  // WCHAR_T_IS_UTF32
diff --git a/base/string16.h b/base/string16.h
new file mode 100644
index 0000000..e5d8e35
--- /dev/null
+++ b/base/string16.h
@@ -0,0 +1,185 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRING16_H_
+#define BASE_STRING16_H_
+
+// WHAT:
+// A version of std::basic_string that provides 2-byte characters even when
+// wchar_t is not implemented as a 2-byte type. You can access this class as
+// string16. We also define char16, which string16 is based upon.
+//
+// WHY:
+// On Windows, wchar_t is 2 bytes, and it can conveniently handle UTF-16/UCS-2
+// data. Plenty of existing code operates on strings encoded as UTF-16.
+//
+// On many other platforms, sizeof(wchar_t) is 4 bytes by default. We can make
+// it 2 bytes by using the GCC flag -fshort-wchar. But then std::wstring fails
+// at run time, because it calls some functions (like wcslen) that come from
+// the system's native C library -- which was built with a 4-byte wchar_t!
+// It's wasteful to use 4-byte wchar_t strings to carry UTF-16 data, and it's
+// entirely improper on those systems where the encoding of wchar_t is defined
+// as UTF-32.
+//
+// Here, we define string16, which is similar to std::wstring but replaces all
+// libc functions with custom, 2-byte-char compatible routines. It is capable
+// of carrying UTF-16-encoded data.
+
+#include <stdio.h>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(WCHAR_T_IS_UTF16)
+
+typedef wchar_t char16;
+typedef std::wstring string16;
+
+namespace base {
+typedef std::char_traits<wchar_t> string16_char_traits;
+}
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+typedef uint16 char16;
+
+namespace base {
+
+// char16 versions of the functions required by string16_char_traits; these
+// are based on the wide character functions of similar names ("w" or "wcs"
+// instead of "c16").
+BASE_EXPORT int c16memcmp(const char16* s1, const char16* s2, size_t n);
+BASE_EXPORT size_t c16len(const char16* s);
+BASE_EXPORT const char16* c16memchr(const char16* s, char16 c, size_t n);
+BASE_EXPORT char16* c16memmove(char16* s1, const char16* s2, size_t n);
+BASE_EXPORT char16* c16memcpy(char16* s1, const char16* s2, size_t n);
+BASE_EXPORT char16* c16memset(char16* s, char16 c, size_t n);
+
+struct string16_char_traits {
+  typedef char16 char_type;
+  typedef int int_type;
+
+  // int_type needs to be able to hold each possible value of char_type, and in
+  // addition, the distinct value of eof().
+  COMPILE_ASSERT(sizeof(int_type) > sizeof(char_type), unexpected_type_width);
+
+  typedef std::streamoff off_type;
+  typedef mbstate_t state_type;
+  typedef std::fpos<state_type> pos_type;
+
+  static void assign(char_type& c1, const char_type& c2) {
+    c1 = c2;
+  }
+
+  static bool eq(const char_type& c1, const char_type& c2) {
+    return c1 == c2;
+  }
+  static bool lt(const char_type& c1, const char_type& c2) {
+    return c1 < c2;
+  }
+
+  static int compare(const char_type* s1, const char_type* s2, size_t n) {
+    return c16memcmp(s1, s2, n);
+  }
+
+  static size_t length(const char_type* s) {
+    return c16len(s);
+  }
+
+  static const char_type* find(const char_type* s, size_t n,
+                               const char_type& a) {
+    return c16memchr(s, a, n);
+  }
+
+  static char_type* move(char_type* s1, const char_type* s2, int_type 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);
+  }
+};
+
+}  // 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<char16, base::string16_char_traits>;
+
+typedef std::basic_string<char16, base::string16_char_traits> string16;
+
+namespace base {
+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);
+}
+
+#endif  // WCHAR_T_IS_UTF32
+
+#endif  // BASE_STRING16_H_
diff --git a/base/string16_unittest.cc b/base/string16_unittest.cc
new file mode 100644
index 0000000..e833ed2
--- /dev/null
+++ b/base/string16_unittest.cc
@@ -0,0 +1,53 @@
+// 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 <sstream>
+
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(WCHAR_T_IS_UTF32)
+
+// We define a custom operator<< for string16 so we can use it with logging.
+// This tests that conversion.
+TEST(String16Test, OutputStream) {
+  // Basic stream test.
+  {
+    std::ostringstream stream;
+    stream << "Empty '" << string16() << "' standard '"
+           << string16(ASCIIToUTF16("Hello, world")) << "'";
+    EXPECT_STREQ("Empty '' standard 'Hello, world'",
+                 stream.str().c_str());
+  }
+
+  // Interesting edge cases.
+  {
+    // These should each get converted to the invalid character: EF BF BD.
+    string16 initial_surrogate;
+    initial_surrogate.push_back(0xd800);
+    string16 final_surrogate;
+    final_surrogate.push_back(0xdc00);
+
+    // Old italic A = U+10300, will get converted to: F0 90 8C 80 'z'.
+    string16 surrogate_pair;
+    surrogate_pair.push_back(0xd800);
+    surrogate_pair.push_back(0xdf00);
+    surrogate_pair.push_back('z');
+
+    // Will get converted to the invalid char + 's': EF BF BD 's'.
+    string16 unterminated_surrogate;
+    unterminated_surrogate.push_back(0xd800);
+    unterminated_surrogate.push_back('s');
+
+    std::ostringstream stream;
+    stream << initial_surrogate << "," << final_surrogate << ","
+           << surrogate_pair << "," << unterminated_surrogate;
+
+    EXPECT_STREQ("\xef\xbf\xbd,\xef\xbf\xbd,\xf0\x90\x8c\x80z,\xef\xbf\xbds",
+                 stream.str().c_str());
+  }
+}
+
+#endif
diff --git a/base/string_number_conversions.cc b/base/string_number_conversions.cc
new file mode 100644
index 0000000..e80b649
--- /dev/null
+++ b/base/string_number_conversions.cc
@@ -0,0 +1,488 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/string_number_conversions.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <wctype.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/third_party/dmg_fp/dmg_fp.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+template <typename STR, typename INT, typename UINT, bool NEG>
+struct IntToStringT {
+  // This is to avoid a compiler warning about unary minus on unsigned type.
+  // For example, say you had the following code:
+  //   template <typename INT>
+  //   INT abs(INT value) { return value < 0 ? -value : value; }
+  // Even though if INT is unsigned, it's impossible for value < 0, so the
+  // unary minus will never be taken, the compiler will still generate a
+  // warning.  We do a little specialization dance...
+  template <typename INT2, typename UINT2, bool NEG2>
+  struct ToUnsignedT {};
+
+  template <typename INT2, typename UINT2>
+  struct ToUnsignedT<INT2, UINT2, false> {
+    static UINT2 ToUnsigned(INT2 value) {
+      return static_cast<UINT2>(value);
+    }
+  };
+
+  template <typename INT2, typename UINT2>
+  struct ToUnsignedT<INT2, UINT2, true> {
+    static UINT2 ToUnsigned(INT2 value) {
+      return static_cast<UINT2>(value < 0 ? -value : value);
+    }
+  };
+
+  // This set of templates is very similar to the above templates, but
+  // for testing whether an integer is negative.
+  template <typename INT2, bool NEG2>
+  struct TestNegT {};
+  template <typename INT2>
+  struct TestNegT<INT2, false> {
+    static bool TestNeg(INT2 value) {
+      // value is unsigned, and can never be negative.
+      return false;
+    }
+  };
+  template <typename INT2>
+  struct TestNegT<INT2, true> {
+    static bool TestNeg(INT2 value) {
+      return value < 0;
+    }
+  };
+
+  static STR IntToString(INT value) {
+    // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
+    // So round up to allocate 3 output characters per byte, plus 1 for '-'.
+    const int kOutputBufSize = 3 * sizeof(INT) + 1;
+
+    // Allocate the whole string right away, we will right back to front, and
+    // then return the substr of what we ended up using.
+    STR outbuf(kOutputBufSize, 0);
+
+    bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
+    // Even though is_neg will never be true when INT is parameterized as
+    // unsigned, even the presence of the unary operation causes a warning.
+    UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
+
+    for (typename STR::iterator it = outbuf.end();;) {
+      --it;
+      DCHECK(it != outbuf.begin());
+      *it = static_cast<typename STR::value_type>((res % 10) + '0');
+      res /= 10;
+
+      // We're done..
+      if (res == 0) {
+        if (is_neg) {
+          --it;
+          DCHECK(it != outbuf.begin());
+          *it = static_cast<typename STR::value_type>('-');
+        }
+        return STR(it, outbuf.end());
+      }
+    }
+    NOTREACHED();
+    return STR();
+  }
+};
+
+// Utility to convert a character to a digit in a given base
+template<typename CHAR, int BASE, bool BASE_LTE_10> class BaseCharToDigit {
+};
+
+// Faster specialization for bases <= 10
+template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
+ public:
+  static bool Convert(CHAR c, uint8* digit) {
+    if (c >= '0' && c < '0' + BASE) {
+      *digit = c - '0';
+      return true;
+    }
+    return false;
+  }
+};
+
+// Specialization for bases where 10 < base <= 36
+template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
+ public:
+  static bool Convert(CHAR c, uint8* digit) {
+    if (c >= '0' && c <= '9') {
+      *digit = c - '0';
+    } else if (c >= 'a' && c < 'a' + BASE - 10) {
+      *digit = c - 'a' + 10;
+    } else if (c >= 'A' && c < 'A' + BASE - 10) {
+      *digit = c - 'A' + 10;
+    } else {
+      return false;
+    }
+    return true;
+  }
+};
+
+template<int BASE, typename CHAR> bool CharToDigit(CHAR c, uint8* digit) {
+  return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
+}
+
+// There is an IsWhitespace for wchars defined in string_util.h, but it is
+// locale independent, whereas the functions we are replacing were
+// locale-dependent. TBD what is desired, but for the moment let's not introduce
+// a change in behaviour.
+template<typename CHAR> class WhitespaceHelper {
+};
+
+template<> class WhitespaceHelper<char> {
+ public:
+  static bool Invoke(char c) {
+    return 0 != isspace(static_cast<unsigned char>(c));
+  }
+};
+
+template<> class WhitespaceHelper<char16> {
+ public:
+  static bool Invoke(char16 c) {
+    return 0 != iswspace(c);
+  }
+};
+
+template<typename CHAR> bool LocalIsWhitespace(CHAR c) {
+  return WhitespaceHelper<CHAR>::Invoke(c);
+}
+
+// IteratorRangeToNumberTraits should provide:
+//  - a typedef for iterator_type, the iterator type used as input.
+//  - a typedef for value_type, the target numeric type.
+//  - static functions min, max (returning the minimum and maximum permitted
+//    values)
+//  - constant kBase, the base in which to interpret the input
+template<typename IteratorRangeToNumberTraits>
+class IteratorRangeToNumber {
+ public:
+  typedef IteratorRangeToNumberTraits traits;
+  typedef typename traits::iterator_type const_iterator;
+  typedef typename traits::value_type value_type;
+
+  // Generalized iterator-range-to-number conversion.
+  //
+  static bool Invoke(const_iterator begin,
+                     const_iterator end,
+                     value_type* output) {
+    bool valid = true;
+
+    while (begin != end && LocalIsWhitespace(*begin)) {
+      valid = false;
+      ++begin;
+    }
+
+    if (begin != end && *begin == '-') {
+      if (!Negative::Invoke(begin + 1, end, output)) {
+        valid = false;
+      }
+    } else {
+      if (begin != end && *begin == '+') {
+        ++begin;
+      }
+      if (!Positive::Invoke(begin, end, output)) {
+        valid = false;
+      }
+    }
+
+    return valid;
+  }
+
+ private:
+  // Sign provides:
+  //  - a static function, CheckBounds, that determines whether the next digit
+  //    causes an overflow/underflow
+  //  - a static function, Increment, that appends the next digit appropriately
+  //    according to the sign of the number being parsed.
+  template<typename Sign>
+  class Base {
+   public:
+    static bool Invoke(const_iterator begin, const_iterator end,
+                       typename traits::value_type* output) {
+      *output = 0;
+
+      if (begin == end) {
+        return false;
+      }
+
+      // Note: no performance difference was found when using template
+      // specialization to remove this check in bases other than 16
+      if (traits::kBase == 16 && end - begin > 2 && *begin == '0' &&
+          (*(begin + 1) == 'x' || *(begin + 1) == 'X')) {
+        begin += 2;
+      }
+
+      for (const_iterator current = begin; current != end; ++current) {
+        uint8 new_digit = 0;
+
+        if (!CharToDigit<traits::kBase>(*current, &new_digit)) {
+          return false;
+        }
+
+        if (current != begin) {
+          if (!Sign::CheckBounds(output, new_digit)) {
+            return false;
+          }
+          *output *= traits::kBase;
+        }
+
+        Sign::Increment(new_digit, output);
+      }
+      return true;
+    }
+  };
+
+  class Positive : public Base<Positive> {
+   public:
+    static bool CheckBounds(value_type* output, uint8 new_digit) {
+      if (*output > static_cast<value_type>(traits::max() / traits::kBase) ||
+          (*output == static_cast<value_type>(traits::max() / traits::kBase) &&
+           new_digit > traits::max() % traits::kBase)) {
+        *output = traits::max();
+        return false;
+      }
+      return true;
+    }
+    static void Increment(uint8 increment, value_type* output) {
+      *output += increment;
+    }
+  };
+
+  class Negative : public Base<Negative> {
+   public:
+    static bool CheckBounds(value_type* output, uint8 new_digit) {
+      if (*output < traits::min() / traits::kBase ||
+          (*output == traits::min() / traits::kBase &&
+           new_digit > 0 - traits::min() % traits::kBase)) {
+        *output = traits::min();
+        return false;
+      }
+      return true;
+    }
+    static void Increment(uint8 increment, value_type* output) {
+      *output -= increment;
+    }
+  };
+};
+
+template<typename ITERATOR, typename VALUE, int BASE>
+class BaseIteratorRangeToNumberTraits {
+ public:
+  typedef ITERATOR iterator_type;
+  typedef VALUE value_type;
+  static value_type min() {
+    return std::numeric_limits<value_type>::min();
+  }
+  static value_type max() {
+    return std::numeric_limits<value_type>::max();
+  }
+  static const int kBase = BASE;
+};
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToIntTraits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
+ public:
+  // Allow parsing of 0xFFFFFFFF, which is technically an overflow
+  static unsigned int max() {
+    return std::numeric_limits<unsigned int>::max();
+  }
+};
+
+typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
+    HexIteratorRangeToIntTraits;
+
+template<typename STR>
+bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
+  DCHECK_EQ(output->size(), 0u);
+  size_t count = input.size();
+  if (count == 0 || (count % 2) != 0)
+    return false;
+  for (uintptr_t i = 0; i < count / 2; ++i) {
+    uint8 msb = 0;  // most significant 4 bits
+    uint8 lsb = 0;  // least significant 4 bits
+    if (!CharToDigit<16>(input[i * 2], &msb) ||
+        !CharToDigit<16>(input[i * 2 + 1], &lsb))
+      return false;
+    output->push_back((msb << 4) | lsb);
+  }
+  return true;
+}
+
+template <typename VALUE, int BASE>
+class StringPieceToNumberTraits
+    : public BaseIteratorRangeToNumberTraits<StringPiece::const_iterator,
+                                             VALUE,
+                                             BASE> {};
+
+template <typename VALUE>
+bool StringToIntImpl(const StringPiece& input, VALUE* output) {
+  return IteratorRangeToNumber<StringPieceToNumberTraits<VALUE, 10> >::Invoke(
+      input.begin(), input.end(), output);
+}
+
+template <typename VALUE, int BASE>
+class StringPiece16ToNumberTraits
+    : public BaseIteratorRangeToNumberTraits<StringPiece16::const_iterator,
+                                             VALUE,
+                                             BASE> {};
+
+template <typename VALUE>
+bool String16ToIntImpl(const StringPiece16& input, VALUE* output) {
+  return IteratorRangeToNumber<StringPiece16ToNumberTraits<VALUE, 10> >::Invoke(
+      input.begin(), input.end(), output);
+}
+
+}  // namespace
+
+std::string IntToString(int value) {
+  return IntToStringT<std::string, int, unsigned int, true>::
+      IntToString(value);
+}
+
+string16 IntToString16(int value) {
+  return IntToStringT<string16, int, unsigned int, true>::
+      IntToString(value);
+}
+
+std::string UintToString(unsigned int value) {
+  return IntToStringT<std::string, unsigned int, unsigned int, false>::
+      IntToString(value);
+}
+
+string16 UintToString16(unsigned int value) {
+  return IntToStringT<string16, unsigned int, unsigned int, false>::
+      IntToString(value);
+}
+
+std::string Int64ToString(int64 value) {
+  return IntToStringT<std::string, int64, uint64, true>::
+      IntToString(value);
+}
+
+string16 Int64ToString16(int64 value) {
+  return IntToStringT<string16, int64, uint64, true>::IntToString(value);
+}
+
+std::string Uint64ToString(uint64 value) {
+  return IntToStringT<std::string, uint64, uint64, false>::
+      IntToString(value);
+}
+
+string16 Uint64ToString16(uint64 value) {
+  return IntToStringT<string16, uint64, uint64, false>::
+      IntToString(value);
+}
+
+std::string DoubleToString(double value) {
+  // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
+  char buffer[32];
+  dmg_fp::g_fmt(buffer, value);
+  return std::string(buffer);
+}
+
+bool StringToInt(const StringPiece& input, int* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToInt(const StringPiece16& input, int* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToUint(const StringPiece& input, unsigned* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToUint(const StringPiece16& input, unsigned* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToInt64(const StringPiece& input, int64* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToInt64(const StringPiece16& input, int64* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToUint64(const StringPiece& input, uint64* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToUint64(const StringPiece16& input, uint64* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToSizeT(const StringPiece& input, size_t* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToSizeT(const StringPiece16& input, size_t* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToDouble(const std::string& input, double* output) {
+  errno = 0;  // Thread-safe?  It is on at least Mac, Linux, and Windows.
+  char* endptr = NULL;
+  *output = dmg_fp::strtod(input.c_str(), &endptr);
+
+  // Cases to return false:
+  //  - If errno is ERANGE, there was an overflow or underflow.
+  //  - If the input string is empty, there was nothing to parse.
+  //  - If endptr does not point to the end of the string, there are either
+  //    characters remaining in the string after a parsed number, or the string
+  //    does not begin with a parseable number.  endptr is compared to the
+  //    expected end given the string's stated length to correctly catch cases
+  //    where the string contains embedded NUL characters.
+  //  - If the first character is a space, there was leading whitespace
+  return errno == 0 &&
+         !input.empty() &&
+         input.c_str() + input.length() == endptr &&
+         !isspace(input[0]);
+}
+
+// Note: if you need to add String16ToDouble, first ask yourself if it's
+// really necessary. If it is, probably the best implementation here is to
+// convert to 8-bit and then use the 8-bit version.
+
+// Note: if you need to add an iterator range version of StringToDouble, first
+// ask yourself if it's really necessary. If it is, probably the best
+// implementation here is to instantiate a string and use the string version.
+
+std::string HexEncode(const void* bytes, size_t size) {
+  static const char kHexChars[] = "0123456789ABCDEF";
+
+  // Each input byte creates two output hex characters.
+  std::string ret(size * 2, '\0');
+
+  for (size_t i = 0; i < size; ++i) {
+    char b = reinterpret_cast<const char*>(bytes)[i];
+    ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
+    ret[(i * 2) + 1] = kHexChars[b & 0xf];
+  }
+  return ret;
+}
+
+bool HexStringToInt(const StringPiece& input, int* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke(
+    input.begin(), input.end(), output);
+}
+
+bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
+  return HexStringToBytesT(input, output);
+}
+
+}  // namespace base
diff --git a/base/string_number_conversions.h b/base/string_number_conversions.h
new file mode 100644
index 0000000..54f05b0
--- /dev/null
+++ b/base/string_number_conversions.h
@@ -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.
+
+#ifndef BASE_STRING_NUMBER_CONVERSIONS_H_
+#define BASE_STRING_NUMBER_CONVERSIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/string_piece.h"
+#include "base/string16.h"
+
+// ----------------------------------------------------------------------------
+// IMPORTANT MESSAGE FROM YOUR SPONSOR
+//
+// This file contains no "wstring" variants. New code should use string16. If
+// you need to make old code work, use the UTF8 version and convert. Please do
+// not add wstring variants.
+//
+// Please do not add "convenience" functions for converting strings to integers
+// that return the value and ignore success/failure. That encourages people to
+// write code that doesn't properly handle the error conditions.
+// ----------------------------------------------------------------------------
+
+namespace base {
+
+// Number -> string conversions ------------------------------------------------
+
+BASE_EXPORT std::string IntToString(int value);
+BASE_EXPORT string16 IntToString16(int value);
+
+BASE_EXPORT std::string UintToString(unsigned value);
+BASE_EXPORT string16 UintToString16(unsigned value);
+
+BASE_EXPORT std::string Int64ToString(int64 value);
+BASE_EXPORT string16 Int64ToString16(int64 value);
+
+BASE_EXPORT std::string Uint64ToString(uint64 value);
+BASE_EXPORT string16 Uint64ToString16(uint64 value);
+
+// 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/underflow.  |*output| will be set to the maximum value supported
+//    by the data type.
+//  - Trailing characters in the string after parsing the number.  |*output|
+//    will be set to the value of the number that was parsed.
+//  - Leading whitespace in the string before parsing the number. |*output| will
+//    be set to the value of the number that was parsed.
+//  - No characters parseable as a number at the beginning of the string.
+//    |*output| will be set to 0.
+//  - Empty string.  |*output| will be set to 0.
+BASE_EXPORT bool StringToInt(const StringPiece& input, int* output);
+BASE_EXPORT bool StringToInt(const StringPiece16& input, int* output);
+
+BASE_EXPORT bool StringToUint(const StringPiece& input, unsigned* output);
+BASE_EXPORT bool StringToUint(const StringPiece16& input, unsigned* output);
+
+BASE_EXPORT bool StringToInt64(const StringPiece& input, int64* output);
+BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64* output);
+
+BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64* output);
+BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64* output);
+
+BASE_EXPORT bool StringToSizeT(const StringPiece& input, size_t* output);
+BASE_EXPORT bool StringToSizeT(const StringPiece16& input, size_t* output);
+
+// For floating-point conversions, only conversions of input strings in decimal
+// form are defined to work.  Behavior with strings representing floating-point
+// numbers in hexadecimal, and strings representing non-fininte values (such as
+// NaN and inf) is undefined.  Otherwise, these behave the same as the integral
+// variants.  This expects the input string to NOT be specific to the locale.
+// If your input is locale specific, use ICU to read the number.
+BASE_EXPORT bool StringToDouble(const std::string& input, double* output);
+
+// Hex encoding ----------------------------------------------------------------
+
+// Returns a hex string representation of a binary buffer. The returned hex
+// string will be in upper case. This function does not check if |size| is
+// within reasonable limits since it's written with trusted data in mind.  If
+// you suspect that the data you want to format might be large, the absolute
+// max size for |size| should be is
+//   std::numeric_limits<size_t>::max() / 2
+BASE_EXPORT std::string HexEncode(const void* bytes, size_t size);
+
+// Best effort conversion, see StringToInt above for restrictions.
+BASE_EXPORT bool HexStringToInt(const StringPiece& input, int* output);
+
+// Similar to the previous functions, except that output is a vector of bytes.
+// |*output| will contain as many bytes as were successfully parsed prior to the
+// error.  There is no overflow, but input.size() must be evenly divisible by 2.
+// Leading 0x or +/- are not allowed.
+BASE_EXPORT bool HexStringToBytes(const std::string& input,
+                                  std::vector<uint8>* output);
+
+}  // namespace base
+
+#endif  // BASE_STRING_NUMBER_CONVERSIONS_H_
+
diff --git a/base/string_number_conversions_unittest.cc b/base/string_number_conversions_unittest.cc
new file mode 100644
index 0000000..30b9b8c
--- /dev/null
+++ b/base/string_number_conversions_unittest.cc
@@ -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.
+
+#include <math.h>
+
+#include <limits>
+
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+template <typename INT>
+struct IntToStringTest {
+  INT num;
+  const char* sexpected;
+  const char* uexpected;
+};
+
+}  // namespace
+
+TEST(StringNumberConversionsTest, IntToString) {
+  static const IntToStringTest<int> int_tests[] = {
+      { 0, "0", "0" },
+      { -1, "-1", "4294967295" },
+      { std::numeric_limits<int>::max(), "2147483647", "2147483647" },
+      { std::numeric_limits<int>::min(), "-2147483648", "2147483648" },
+  };
+  static const IntToStringTest<int64> int64_tests[] = {
+      { 0, "0", "0" },
+      { -1, "-1", "18446744073709551615" },
+      { std::numeric_limits<int64>::max(),
+        "9223372036854775807",
+        "9223372036854775807", },
+      { std::numeric_limits<int64>::min(),
+        "-9223372036854775808",
+        "9223372036854775808" },
+  };
+
+  for (size_t i = 0; i < arraysize(int_tests); ++i) {
+    const IntToStringTest<int>* test = &int_tests[i];
+    EXPECT_EQ(IntToString(test->num), test->sexpected);
+    EXPECT_EQ(IntToString16(test->num), UTF8ToUTF16(test->sexpected));
+    EXPECT_EQ(UintToString(test->num), test->uexpected);
+    EXPECT_EQ(UintToString16(test->num), UTF8ToUTF16(test->uexpected));
+  }
+  for (size_t i = 0; i < arraysize(int64_tests); ++i) {
+    const IntToStringTest<int64>* test = &int64_tests[i];
+    EXPECT_EQ(Int64ToString(test->num), test->sexpected);
+    EXPECT_EQ(Int64ToString16(test->num), UTF8ToUTF16(test->sexpected));
+    EXPECT_EQ(Uint64ToString(test->num), test->uexpected);
+    EXPECT_EQ(Uint64ToString16(test->num), UTF8ToUTF16(test->uexpected));
+  }
+}
+
+TEST(StringNumberConversionsTest, Uint64ToString) {
+  static const struct {
+    uint64 input;
+    std::string output;
+  } cases[] = {
+    {0, "0"},
+    {42, "42"},
+    {INT_MAX, "2147483647"},
+    {kuint64max, "18446744073709551615"},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(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_UNSAFE(cases); ++i) {
+    int output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  int output;
+  EXPECT_FALSE(StringToInt(input_string, &output));
+  EXPECT_EQ(6, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToInt(utf16_input, &output));
+  EXPECT_EQ(6, output);
+
+  output = 0;
+  const char16 negative_wide_input[] = { 0xFF4D, '4', '2', 0};
+  EXPECT_FALSE(StringToInt(string16(negative_wide_input), &output));
+  EXPECT_EQ(0, output);
+}
+
+TEST(StringNumberConversionsTest, StringToInt64) {
+  static const struct {
+    std::string input;
+    int64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"-2147483648", INT_MIN, true},
+    {"2147483647", INT_MAX, true},
+    {"-2147483649", GG_INT64_C(-2147483649), true},
+    {"-99999999999", GG_INT64_C(-99999999999), true},
+    {"2147483648", GG_INT64_C(2147483648), true},
+    {"99999999999", GG_INT64_C(99999999999), true},
+    {"9223372036854775807", kint64max, true},
+    {"-9223372036854775808", kint64min, true},
+    {"09", 9, true},
+    {"-09", -9, true},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"0x42", 0, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", -273, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-9223372036854775809", kint64min, false},
+    {"-99999999999999999999", kint64min, false},
+    {"9223372036854775808", kint64max, false},
+    {"99999999999999999999", kint64max, false},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    int64 output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt64(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  int64 output;
+  EXPECT_FALSE(StringToInt64(input_string, &output));
+  EXPECT_EQ(6, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToInt64(utf16_input, &output));
+  EXPECT_EQ(6, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToInt) {
+  static const struct {
+    std::string input;
+    int output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 66, true},
+    {"-42", -66, true},
+    {"+42", 66, true},
+    {"7fffffff", INT_MAX, true},
+    {"80000000", INT_MIN, true},
+    {"ffffffff", -1, true},
+    {"DeadBeef", 0xdeadbeef, true},
+    {"0x42", 66, true},
+    {"-0x42", -66, true},
+    {"+0x42", 66, true},
+    {"0x7fffffff", INT_MAX, true},
+    {"0x80000000", INT_MIN, true},
+    {"0xffffffff", -1, true},
+    {"0XDeadBeef", 0xdeadbeef, true},
+    {"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},
+    {"100000000", -1, false},  // don't care about |output|, just |success|
+    {"-", 0, false},
+    {"", 0, false},
+    {"0x", 0, false},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(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\09";
+  std::string input_string(input, arraysize(input) - 1);
+  int output;
+  EXPECT_FALSE(HexStringToInt(input_string, &output));
+  EXPECT_EQ(0xc0ffee, 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_UNSAFE(cases); ++i) {
+    std::vector<uint8> output;
+    std::vector<uint8> compare;
+    EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) <<
+        i << ": " << cases[i].input;
+    for (size_t j = 0; j < cases[i].output_len; ++j)
+      compare.push_back(static_cast<uint8>(cases[i].output[j]));
+    ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input;
+    EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) <<
+        i << ": " << cases[i].input;
+  }
+}
+
+TEST(StringNumberConversionsTest, StringToDouble) {
+  static const struct {
+    std::string input;
+    double output;
+    bool success;
+  } cases[] = {
+    {"0", 0.0, true},
+    {"42", 42.0, true},
+    {"-42", -42.0, true},
+    {"123.45", 123.45, true},
+    {"-123.45", -123.45, true},
+    {"+123.45", 123.45, true},
+    {"2.99792458e8", 299792458.0, true},
+    {"149597870.691E+3", 149597870691.0, true},
+    {"6.", 6.0, true},
+    {"9e99999999999999999999", HUGE_VAL, false},
+    {"-9e99999999999999999999", -HUGE_VAL, false},
+    {"1e-2", 0.01, true},
+    {"42 ", 42.0, false},
+    {" 1e-2", 0.01, false},
+    {"1e-2 ", 0.01, false},
+    {"-1E-7", -0.0000001, true},
+    {"01e02", 100, true},
+    {"2.3e15", 2.3e15, true},
+    {"\t\n\v\f\r -123.45e2", -12345.0, false},
+    {"+123 e4", 123.0, false},
+    {"123e ", 123.0, false},
+    {"123e", 123.0, false},
+    {" 2.99", 2.99, false},
+    {"1e3.4", 1000.0, false},
+    {"nothing", 0.0, false},
+    {"-", 0.0, false},
+    {"+", 0.0, false},
+    {"", 0.0, false},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    double output;
+    EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output));
+    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\0159";
+  std::string input_string(input, arraysize(input) - 1);
+  double output;
+  EXPECT_FALSE(StringToDouble(input_string, &output));
+  EXPECT_DOUBLE_EQ(3.14, output);
+}
+
+TEST(StringNumberConversionsTest, DoubleToString) {
+  static const struct {
+    double input;
+    const char* expected;
+  } cases[] = {
+    {0.0, "0"},
+    {1.25, "1.25"},
+    {1.33518e+012, "1.33518e+12"},
+    {1.33489e+012, "1.33489e+12"},
+    {1.33505e+012, "1.33505e+12"},
+    {1.33545e+009, "1335450000"},
+    {1.33503e+009, "1335030000"},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    EXPECT_EQ(cases[i].expected, DoubleToString(cases[i].input));
+  }
+
+  // The following two values were seen in crashes in the wild.
+  const char input_bytes[8] = {0, 0, 0, 0, '\xee', '\x6d', '\x73', '\x42'};
+  double input = 0;
+  memcpy(&input, input_bytes, arraysize(input_bytes));
+  EXPECT_EQ("1335179083776", DoubleToString(input));
+  const char input_bytes2[8] =
+      {0, 0, 0, '\xa0', '\xda', '\x6c', '\x73', '\x42'};
+  input = 0;
+  memcpy(&input, input_bytes2, arraysize(input_bytes2));
+  EXPECT_EQ("1334890332160", DoubleToString(input));
+}
+
+TEST(StringNumberConversionsTest, HexEncode) {
+  std::string hex(HexEncode(NULL, 0));
+  EXPECT_EQ(hex.length(), 0U);
+  unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81};
+  hex = HexEncode(bytes, sizeof(bytes));
+  EXPECT_EQ(hex.compare("01FF02FE038081"), 0);
+}
+
+}  // namespace base
diff --git a/base/string_piece.cc b/base/string_piece.cc
new file mode 100644
index 0000000..7a41361
--- /dev/null
+++ b/base/string_piece.cc
@@ -0,0 +1,255 @@
+// Copyright (c) 2012 The Chromium 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 <algorithm>
+#include <ostream>
+
+#include "base/string_piece.h"
+
+namespace base {
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+namespace internal {
+template class StringPieceDetail<std::string>;
+template class StringPieceDetail<string16>;
+}  // namespace internal
+
+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 {
+void CopyToString(const StringPiece& self, std::string* target) {
+  target->assign(!self.empty() ? self.data() : "", self.size());
+}
+
+void AppendToString(const StringPiece& self, std::string* target) {
+  if (!self.empty())
+    target->append(self.data(), self.size());
+}
+
+StringPiece::size_type copy(const StringPiece& self,
+                            char* buf,
+                            StringPiece::size_type n,
+                            StringPiece::size_type pos) {
+  StringPiece::size_type ret = std::min(self.size() - pos, n);
+  memcpy(buf, self.data() + pos, ret);
+  return ret;
+}
+
+StringPiece::size_type find(const StringPiece& self,
+                            const StringPiece& s,
+                            StringPiece::size_type pos) {
+  if (pos > self.size())
+    return StringPiece::npos;
+
+  StringPiece::const_iterator result =
+      std::search(self.begin() + pos, self.end(), s.begin(), s.end());
+  const StringPiece::size_type xpos =
+    static_cast<size_t>(result - self.begin());
+  return xpos + s.size() <= self.size() ? xpos : StringPiece::npos;
+}
+
+StringPiece::size_type find(const StringPiece& self,
+                            char c,
+                            StringPiece::size_type pos) {
+  if (pos >= self.size())
+    return StringPiece::npos;
+
+  StringPiece::const_iterator result =
+      std::find(self.begin() + pos, self.end(), c);
+  return result != self.end() ?
+      static_cast<size_t>(result - self.begin()) : StringPiece::npos;
+}
+
+StringPiece::size_type rfind(const StringPiece& self,
+                             const StringPiece& s,
+                             StringPiece::size_type pos) {
+  if (self.size() < s.size())
+    return StringPiece::npos;
+
+  if (s.empty())
+    return std::min(self.size(), pos);
+
+  StringPiece::const_iterator last =
+      self.begin() + std::min(self.size() - s.size(), pos) + s.size();
+  StringPiece::const_iterator result =
+      std::find_end(self.begin(), last, s.begin(), s.end());
+  return result != last ?
+      static_cast<size_t>(result - self.begin()) : StringPiece::npos;
+}
+
+StringPiece::size_type rfind(const StringPiece& self,
+                             char c,
+                             StringPiece::size_type pos) {
+  if (self.size() == 0)
+    return StringPiece::npos;
+
+  for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) {
+    if (self.data()[i] == c)
+      return i;
+    if (i == 0)
+      break;
+  }
+  return StringPiece::npos;
+}
+
+// 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]
+static inline void BuildLookupTable(const StringPiece& characters_wanted,
+                                    bool* table) {
+  const StringPiece::size_type length = characters_wanted.length();
+  const char* const data = characters_wanted.data();
+  for (StringPiece::size_type i = 0; i < length; ++i) {
+    table[static_cast<unsigned char>(data[i])] = true;
+  }
+}
+
+StringPiece::size_type find_first_of(const StringPiece& self,
+                                     const StringPiece& s,
+                                     StringPiece::size_type 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 (StringPiece::size_type i = pos; i < self.size(); ++i) {
+    if (lookup[static_cast<unsigned char>(self.data()[i])]) {
+      return i;
+    }
+  }
+  return StringPiece::npos;
+}
+
+StringPiece::size_type find_first_not_of(const StringPiece& self,
+                                         const StringPiece& s,
+                                         StringPiece::size_type 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 (StringPiece::size_type i = pos; i < self.size(); ++i) {
+    if (!lookup[static_cast<unsigned char>(self.data()[i])]) {
+      return i;
+    }
+  }
+  return StringPiece::npos;
+}
+
+StringPiece::size_type find_first_not_of(const StringPiece& self,
+                                         char c,
+                                         StringPiece::size_type pos) {
+  if (self.size() == 0)
+    return StringPiece::npos;
+
+  for (; pos < self.size(); ++pos) {
+    if (self.data()[pos] != c) {
+      return pos;
+    }
+  }
+  return StringPiece::npos;
+}
+
+StringPiece::size_type find_last_of(const StringPiece& self,
+                                    const StringPiece& s,
+                                    StringPiece::size_type 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 (StringPiece::size_type 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;
+}
+
+StringPiece::size_type find_last_not_of(const StringPiece& self,
+                                        const StringPiece& s,
+                                        StringPiece::size_type pos) {
+  if (self.size() == 0)
+    return StringPiece::npos;
+
+  StringPiece::size_type 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;
+}
+
+StringPiece::size_type find_last_not_of(const StringPiece& self,
+                                        char c,
+                                        StringPiece::size_type pos) {
+  if (self.size() == 0)
+    return StringPiece::npos;
+
+  for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) {
+    if (self.data()[i] != c)
+      return i;
+    if (i == 0)
+      break;
+  }
+  return StringPiece::npos;
+}
+
+StringPiece substr(const StringPiece& self,
+                   StringPiece::size_type pos,
+                   StringPiece::size_type n) {
+  if (pos > self.size()) pos = self.size();
+  if (n > self.size() - pos) n = self.size() - pos;
+  return StringPiece(self.data() + pos, n);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/string_piece.h b/base/string_piece.h
new file mode 100644
index 0000000..416fca8
--- /dev/null
+++ b/base/string_piece.h
@@ -0,0 +1,451 @@
+// Copyright (c) 2012 The Chromium 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.
+//
+// Functions or methods may use const StringPiece& parameters to accept either
+// a "const char*" or a "string" value that will be implicitly converted to
+// a StringPiece.  The implicit conversion means that it is often appropriate
+// to include this .h file in other files rather than forward-declaring
+// StringPiece as would be appropriate for most other Google classes.
+//
+// Systematic usage of StringPiece is encouraged as it will reduce unnecessary
+// conversions from "const char*" to "string" and back again.
+//
+// StringPiece16 is similar to StringPiece but for base::string16 instead of
+// std::string. We do not define as large of a subset of the STL functions
+// from basic_string as in StringPiece, but this can be changed if these
+// functions (find, find_first_of, etc.) are found to be useful in this context.
+//
+
+#ifndef BASE_STRING_PIECE_H_
+#define BASE_STRING_PIECE_H_
+
+#include <stddef.h>
+
+#include <iosfwd>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/string16.h"
+
+namespace base {
+
+template <typename STRING_TYPE> class BasicStringPiece;
+typedef BasicStringPiece<std::string> StringPiece;
+typedef BasicStringPiece<string16> StringPiece16;
+
+namespace internal {
+
+// 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.
+template <typename STRING_TYPE> class StringPieceDetail {
+ 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).
+  StringPieceDetail() : ptr_(NULL), length_(0) {}
+  StringPieceDetail(const value_type* str)
+      : ptr_(str),
+        length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {}
+  StringPieceDetail(const STRING_TYPE& str)
+      : ptr_(str.data()), length_(str.size()) {}
+  StringPieceDetail(const value_type* offset, size_type len)
+      : ptr_(offset), length_(len) {}
+  StringPieceDetail(const typename STRING_TYPE::const_iterator& begin,
+                    const typename STRING_TYPE::const_iterator& end)
+      : ptr_((end > begin) ? &(*begin) : NULL),
+        length_((end > begin) ? (size_type)(end - begin) : 0) {}
+
+  // data() may return a pointer to a buffer with embedded NULs, and the
+  // returned buffer may or may not be null terminated.  Therefore it is
+  // typically a mistake to pass data() to a routine that expects a NUL
+  // terminated string.
+  const value_type* data() const { return ptr_; }
+  size_type size() const { return length_; }
+  size_type length() const { return length_; }
+  bool empty() const { return length_ == 0; }
+
+  void clear() {
+    ptr_ = NULL;
+    length_ = 0;
+  }
+  void set(const value_type* data, size_type len) {
+    ptr_ = data;
+    length_ = len;
+  }
+  void set(const value_type* str) {
+    ptr_ = str;
+    length_ = str ? STRING_TYPE::traits_type::length(str) : 0;
+  }
+
+  value_type operator[](size_type i) const { return ptr_[i]; }
+
+  void remove_prefix(size_type n) {
+    ptr_ += n;
+    length_ -= n;
+  }
+
+  void remove_suffix(size_type n) {
+    length_ -= n;
+  }
+
+  int compare(const BasicStringPiece<STRING_TYPE>& x) const {
+    int r = wordmemcmp(
+        ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_));
+    if (r == 0) {
+      if (length_ < x.length_) r = -1;
+      else if (length_ > x.length_) r = +1;
+    }
+    return r;
+  }
+
+  STRING_TYPE as_string() const {
+    // std::string doesn't like to take a NULL pointer even with a 0 size.
+    return empty() ? STRING_TYPE() : STRING_TYPE(data(), size());
+  }
+
+  const_iterator begin() const { return ptr_; }
+  const_iterator end() const { return ptr_ + length_; }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(ptr_ + length_);
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(ptr_);
+  }
+
+  size_type max_size() const { return length_; }
+  size_type capacity() const { return length_; }
+
+  static int wordmemcmp(const value_type* p,
+                        const value_type* p2,
+                        size_type N) {
+    return STRING_TYPE::traits_type::compare(p, p2, N);
+  }
+
+ protected:
+  const value_type* ptr_;
+  size_type     length_;
+};
+
+template <typename STRING_TYPE>
+const typename StringPieceDetail<STRING_TYPE>::size_type
+StringPieceDetail<STRING_TYPE>::npos =
+    typename StringPieceDetail<STRING_TYPE>::size_type(-1);
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+extern template class BASE_EXPORT StringPieceDetail<std::string>;
+extern template class BASE_EXPORT StringPieceDetail<string16>;
+#endif
+
+BASE_EXPORT void CopyToString(const StringPiece& self, std::string* target);
+BASE_EXPORT void AppendToString(const StringPiece& self, std::string* target);
+BASE_EXPORT StringPieceDetail<std::string>::size_type copy(
+    const StringPiece& self,
+    char* buf,
+    StringPieceDetail<std::string>::size_type n,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type find(
+    const StringPiece& self,
+    const StringPiece& s,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type find(
+    const StringPiece& self,
+    char c,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type rfind(
+    const StringPiece& self,
+    const StringPiece& s,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type rfind(
+    const StringPiece& self,
+    char c,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_of(
+    const StringPiece& self,
+    const StringPiece& s,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_not_of(
+    const StringPiece& self,
+    const StringPiece& s,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_not_of(
+    const StringPiece& self,
+    char c,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_of(
+    const StringPiece& self,
+    const StringPiece& s,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_of(
+    const StringPiece& self,
+    char c,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_not_of(
+    const StringPiece& self,
+    const StringPiece& s,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_not_of(
+    const StringPiece& self,
+    char c,
+    StringPieceDetail<std::string>::size_type pos);
+BASE_EXPORT StringPiece substr(const StringPiece& self,
+                               StringPieceDetail<std::string>::size_type pos,
+                               StringPieceDetail<std::string>::size_type n);
+}  // namespace internal
+
+// Defines the template type that is instantiated as either StringPiece or
+// StringPiece16.
+template <typename STRING_TYPE> class BasicStringPiece :
+    public internal::StringPieceDetail<STRING_TYPE> {
+ public:
+  typedef typename internal::StringPieceDetail<STRING_TYPE>::value_type
+      value_type;
+  typedef typename internal::StringPieceDetail<STRING_TYPE>::size_type
+      size_type;
+
+  BasicStringPiece() {}
+  BasicStringPiece(const value_type*str)
+      : internal::StringPieceDetail<STRING_TYPE>(str) {}
+  BasicStringPiece(const STRING_TYPE& str)
+      : internal::StringPieceDetail<STRING_TYPE>(str) {}
+  BasicStringPiece(const value_type* offset, size_type len)
+      : internal::StringPieceDetail<STRING_TYPE>(offset, len) {}
+  BasicStringPiece(const typename STRING_TYPE::const_iterator& begin,
+                   const typename STRING_TYPE::const_iterator& end)
+      : internal::StringPieceDetail<STRING_TYPE>(begin, end) {}
+};
+
+// Specializes BasicStringPiece for std::string to add a few operations that
+// are not needed for string16.
+template <> class BasicStringPiece<std::string> :
+    public internal::StringPieceDetail<std::string> {
+ public:
+  BasicStringPiece() {}
+  BasicStringPiece(const char* str)
+      : internal::StringPieceDetail<std::string>(str) {}
+  BasicStringPiece(const std::string& str)
+      : internal::StringPieceDetail<std::string>(str) {}
+  BasicStringPiece(const char* offset, size_type len)
+      : internal::StringPieceDetail<std::string>(offset, len) {}
+  BasicStringPiece(const std::string::const_iterator& begin,
+                   const std::string::const_iterator& end)
+      : internal::StringPieceDetail<std::string>(begin, end) {}
+
+  // Prevent the following overload of set() from hiding the definitions in the
+  // base class.
+  using internal::StringPieceDetail<std::string>::set;
+
+  void set(const void* data, size_type len) {
+    ptr_ = reinterpret_cast<const value_type*>(data);
+    length_ = len;
+  }
+
+  void CopyToString(std::string* target) const {
+    internal::CopyToString(*this, target);
+  }
+
+  void AppendToString(std::string* target) const {
+    internal::AppendToString(*this, target);
+  }
+
+  // Does "this" start with "x"
+  bool starts_with(const BasicStringPiece& x) const {
+    return ((length_ >= x.length_) &&
+            (wordmemcmp(ptr_, x.ptr_, x.length_) == 0));
+  }
+
+  // Does "this" end with "x"
+  bool ends_with(const BasicStringPiece& x) const {
+    return ((length_ >= x.length_) &&
+            (wordmemcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0));
+  }
+
+  size_type copy(char* buf, size_type n, size_type pos = 0) const {
+    return internal::copy(*this, buf, n, pos);
+  }
+
+  size_type find(const BasicStringPiece& s, size_type pos = 0) const {
+    return internal::find(*this, s, pos);
+  }
+
+  size_type find(char c, size_type pos = 0) const {
+    return internal::find(*this, c, pos);
+  }
+
+  size_type rfind(const BasicStringPiece& s, size_type pos = npos) const {
+    return internal::rfind(*this, s, pos);
+  }
+
+  size_type rfind(char c, size_type pos = npos) const {
+    return internal::rfind(*this, c, pos);
+  }
+
+  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(char c, size_type pos = 0) const {
+    return find(c, pos);
+  }
+
+  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(char c, size_type pos = 0) const {
+    return internal::find_first_not_of(*this, c, pos);
+  }
+
+  size_type find_last_of(const BasicStringPiece& s,
+                         size_type pos = npos) const {
+    return internal::find_last_of(*this, s, pos);
+  }
+
+  size_type find_last_of(char c, size_type pos = npos) const {
+    return rfind(c, pos);
+  }
+
+  size_type find_last_not_of(const BasicStringPiece& s,
+                             size_type pos = npos) const {
+    return internal::find_last_not_of(*this, s, pos);
+  }
+
+  size_type find_last_not_of(char c, size_type pos = npos) const {
+    return internal::find_last_not_of(*this, c, pos);
+  }
+
+  BasicStringPiece substr(size_type pos, size_type n = npos) const {
+    return internal::substr(*this, pos, n);
+  }
+};
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+// We can't explicitly declare the std::string instantiation here because it was
+// already instantiated when specialized, above. Not only is it a no-op, but
+// currently it also crashes Clang (see http://crbug.com/107412).
+extern template class BASE_EXPORT BasicStringPiece<string16>;
+#endif
+
+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);
+}
+
+inline bool operator==(const StringPiece16& x, const StringPiece16& y) {
+  if (x.size() != y.size())
+    return false;
+
+  return StringPiece16::wordmemcmp(x.data(), y.data(), x.size()) == 0;
+}
+
+inline bool operator!=(const StringPiece16& x, const StringPiece16& y) {
+  return !(x == y);
+}
+
+inline bool operator<(const StringPiece16& x, const StringPiece16& y) {
+  const int r = StringPiece16::wordmemcmp(
+      x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
+  return ((r < 0) || ((r == 0) && (x.size() < y.size())));
+}
+
+inline bool operator>(const StringPiece16& x, const StringPiece16& y) {
+  return y < x;
+}
+
+inline bool operator<=(const StringPiece16& x, const StringPiece16& y) {
+  return !(x > y);
+}
+
+inline bool operator>=(const StringPiece16& x, const StringPiece16& y) {
+  return !(x < y);
+}
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& o,
+                                     const StringPiece& piece);
+
+}  // namespace base
+
+// 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/hash_tables.h. We don't use the
+// ones already defined for string and string16 directly because it would
+// require the string constructors to be called, which we don't want.
+#define HASH_STRING_PIECE(StringPieceType, string_piece)                \
+  std::size_t result = 0;                                               \
+  for (StringPieceType::const_iterator i = string_piece.begin();        \
+       i != string_piece.end(); ++i)                                    \
+    result = (result * 131) + *i;                                       \
+  return result;                                                        \
+
+namespace BASE_HASH_NAMESPACE {
+#if defined(COMPILER_GCC)
+
+template<>
+struct hash<base::StringPiece> {
+  std::size_t operator()(const base::StringPiece& sp) const {
+    HASH_STRING_PIECE(base::StringPiece, sp);
+  }
+};
+template<>
+struct hash<base::StringPiece16> {
+  std::size_t operator()(const base::StringPiece16& sp16) const {
+    HASH_STRING_PIECE(base::StringPiece16, sp16);
+  }
+};
+
+#elif defined(COMPILER_MSVC)
+
+inline size_t hash_value(const base::StringPiece& sp) {
+  HASH_STRING_PIECE(base::StringPiece, sp);
+}
+inline size_t hash_value(const base::StringPiece16& sp16) {
+  HASH_STRING_PIECE(base::StringPiece16, sp16);
+}
+
+#endif  // COMPILER
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#endif  // BASE_STRING_PIECE_H_
diff --git a/base/string_piece_unittest.cc b/base/string_piece_unittest.cc
new file mode 100644
index 0000000..e93dba8
--- /dev/null
+++ b/base/string_piece_unittest.cc
@@ -0,0 +1,677 @@
+// Copyright (c) 2012 The Chromium Authors. 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/string16.h"
+#include "base/string_piece.h"
+#include "base/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());
+}
+
+// STL stuff only supported by the std::string version
+TEST(StringPieceTest, CheckSTL) {
+  StringPiece a("abcdefghijklmnopqrstuvwxyz");
+  StringPiece b("abc");
+  StringPiece c("xyz");
+  StringPiece d("foobar");
+  d.clear();
+  StringPiece e;
+  std::string temp("123");
+  temp += '\0';
+  temp += "456";
+  StringPiece f(temp);
+
+  char 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(StringPiece::npos, std::string::npos);
+
+  ASSERT_EQ(a.find(b), 0U);
+  ASSERT_EQ(a.find(b, 1), StringPiece::npos);
+  ASSERT_EQ(a.find(c), 23U);
+  ASSERT_EQ(a.find(c, 9), 23U);
+  ASSERT_EQ(a.find(c, StringPiece::npos), StringPiece::npos);
+  ASSERT_EQ(b.find(c), StringPiece::npos);
+  ASSERT_EQ(b.find(c, StringPiece::npos), StringPiece::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);
+  StringPiece g("xx not found bb");
+  ASSERT_EQ(a.find(g), StringPiece::npos);
+  // empty string nonsense
+  ASSERT_EQ(d.find(b), StringPiece::npos);
+  ASSERT_EQ(e.find(b), StringPiece::npos);
+  ASSERT_EQ(d.find(b, 4), StringPiece::npos);
+  ASSERT_EQ(e.find(b, 7), StringPiece::npos);
+
+  size_t empty_search_pos = std::string().find(std::string());
+  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('$'), StringPiece::npos);
+  ASSERT_EQ(a.find('\0'), StringPiece::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), StringPiece::npos);
+  // empty string nonsense
+  ASSERT_EQ(d.find('\0'), StringPiece::npos);
+  ASSERT_EQ(e.find('\0'), StringPiece::npos);
+  ASSERT_EQ(d.find('\0', 4), StringPiece::npos);
+  ASSERT_EQ(e.find('\0', 7), StringPiece::npos);
+  ASSERT_EQ(d.find('x'), StringPiece::npos);
+  ASSERT_EQ(e.find('x'), StringPiece::npos);
+  ASSERT_EQ(d.find('x', 4), StringPiece::npos);
+  ASSERT_EQ(e.find('x', 7), StringPiece::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), StringPiece::npos);
+  ASSERT_EQ(a.rfind(c, 1U), StringPiece::npos);
+  ASSERT_EQ(a.rfind(c, 0U), StringPiece::npos);
+  ASSERT_EQ(b.rfind(c), StringPiece::npos);
+  ASSERT_EQ(b.rfind(c, 0U), StringPiece::npos);
+  ASSERT_EQ(a.rfind(d), (size_t) a.as_string().rfind(std::string()));
+  ASSERT_EQ(a.rfind(e), a.as_string().rfind(std::string()));
+  ASSERT_EQ(a.rfind(d, 12), 12U);
+  ASSERT_EQ(a.rfind(e, 17), 17U);
+  ASSERT_EQ(a.rfind(g), StringPiece::npos);
+  ASSERT_EQ(d.rfind(b), StringPiece::npos);
+  ASSERT_EQ(e.rfind(b), StringPiece::npos);
+  ASSERT_EQ(d.rfind(b, 4), StringPiece::npos);
+  ASSERT_EQ(e.rfind(b, 7), StringPiece::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'), StringPiece::npos);
+  ASSERT_EQ(g.rfind('o', 8), 8U);
+  ASSERT_EQ(g.rfind('o', 7), 4U);
+  ASSERT_EQ(g.rfind('o', 3), StringPiece::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'), StringPiece::npos);
+  ASSERT_EQ(e.rfind('o'), StringPiece::npos);
+  ASSERT_EQ(d.rfind('o', 4), StringPiece::npos);
+  ASSERT_EQ(e.rfind('o', 7), StringPiece::npos);
+
+  ASSERT_EQ(
+      StringPiece("one,two:three;four").find_first_of(StringPiece(",:"), 1),
+      3U);
+  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), StringPiece::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), StringPiece::npos);
+  ASSERT_EQ(g.find_first_of(b), 13U);
+  ASSERT_EQ(g.find_first_of(c), 0U);
+  ASSERT_EQ(a.find_first_of(f), StringPiece::npos);
+  ASSERT_EQ(f.find_first_of(a), StringPiece::npos);
+  // empty string nonsense
+  ASSERT_EQ(a.find_first_of(d), StringPiece::npos);
+  ASSERT_EQ(a.find_first_of(e), StringPiece::npos);
+  ASSERT_EQ(d.find_first_of(b), StringPiece::npos);
+  ASSERT_EQ(e.find_first_of(b), StringPiece::npos);
+  ASSERT_EQ(d.find_first_of(d), StringPiece::npos);
+  ASSERT_EQ(e.find_first_of(d), StringPiece::npos);
+  ASSERT_EQ(d.find_first_of(e), StringPiece::npos);
+  ASSERT_EQ(e.find_first_of(e), StringPiece::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), StringPiece::npos);
+  ASSERT_EQ(c.find_first_not_of(a), StringPiece::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), StringPiece::npos);
+  ASSERT_EQ(e.find_first_not_of(a), StringPiece::npos);
+  ASSERT_EQ(d.find_first_not_of(d), StringPiece::npos);
+  ASSERT_EQ(e.find_first_not_of(d), StringPiece::npos);
+  ASSERT_EQ(d.find_first_not_of(e), StringPiece::npos);
+  ASSERT_EQ(e.find_first_not_of(e), StringPiece::npos);
+
+  StringPiece h("====");
+  ASSERT_EQ(h.find_first_not_of('='), StringPiece::npos);
+  ASSERT_EQ(h.find_first_not_of('=', 3), StringPiece::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'), StringPiece::npos);
+  ASSERT_EQ(e.find_first_not_of('x'), StringPiece::npos);
+  ASSERT_EQ(d.find_first_not_of('\0'), StringPiece::npos);
+  ASSERT_EQ(e.find_first_not_of('\0'), StringPiece::npos);
+
+  //  StringPiece g("xx not found bb");
+  StringPiece i("56");
+  ASSERT_EQ(h.find_last_of(a), StringPiece::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), StringPiece::npos);
+  ASSERT_EQ(a.find_last_of('z', 25), 25U);
+  ASSERT_EQ(a.find_last_of('z', 24), StringPiece::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), StringPiece::npos);
+  // empty string nonsense
+  ASSERT_EQ(f.find_last_of(d), StringPiece::npos);
+  ASSERT_EQ(f.find_last_of(e), StringPiece::npos);
+  ASSERT_EQ(f.find_last_of(d, 4), StringPiece::npos);
+  ASSERT_EQ(f.find_last_of(e, 4), StringPiece::npos);
+  ASSERT_EQ(d.find_last_of(d), StringPiece::npos);
+  ASSERT_EQ(d.find_last_of(e), StringPiece::npos);
+  ASSERT_EQ(e.find_last_of(d), StringPiece::npos);
+  ASSERT_EQ(e.find_last_of(e), StringPiece::npos);
+  ASSERT_EQ(d.find_last_of(f), StringPiece::npos);
+  ASSERT_EQ(e.find_last_of(f), StringPiece::npos);
+  ASSERT_EQ(d.find_last_of(d, 4), StringPiece::npos);
+  ASSERT_EQ(d.find_last_of(e, 4), StringPiece::npos);
+  ASSERT_EQ(e.find_last_of(d, 4), StringPiece::npos);
+  ASSERT_EQ(e.find_last_of(e, 4), StringPiece::npos);
+  ASSERT_EQ(d.find_last_of(f, 4), StringPiece::npos);
+  ASSERT_EQ(e.find_last_of(f, 4), StringPiece::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), StringPiece::npos);
+  ASSERT_EQ(b.find_last_not_of(b), StringPiece::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), StringPiece::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), StringPiece::npos);
+  ASSERT_EQ(d.find_last_not_of(e), StringPiece::npos);
+  ASSERT_EQ(e.find_last_not_of(d), StringPiece::npos);
+  ASSERT_EQ(e.find_last_not_of(e), StringPiece::npos);
+  ASSERT_EQ(d.find_last_not_of(f), StringPiece::npos);
+  ASSERT_EQ(e.find_last_not_of(f), StringPiece::npos);
+  ASSERT_EQ(d.find_last_not_of(d, 4), StringPiece::npos);
+  ASSERT_EQ(d.find_last_not_of(e, 4), StringPiece::npos);
+  ASSERT_EQ(e.find_last_not_of(d, 4), StringPiece::npos);
+  ASSERT_EQ(e.find_last_not_of(e, 4), StringPiece::npos);
+  ASSERT_EQ(d.find_last_not_of(f, 4), StringPiece::npos);
+  ASSERT_EQ(e.find_last_not_of(f, 4), StringPiece::npos);
+
+  ASSERT_EQ(h.find_last_not_of('x'), h.size() - 1);
+  ASSERT_EQ(h.find_last_not_of('='), StringPiece::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), StringPiece::npos);
+  ASSERT_EQ(b.find_last_not_of('b', 1), 0U);
+  // empty string nonsense
+  ASSERT_EQ(d.find_last_not_of('x'), StringPiece::npos);
+  ASSERT_EQ(e.find_last_not_of('x'), StringPiece::npos);
+  ASSERT_EQ(d.find_last_not_of('\0'), StringPiece::npos);
+  ASSERT_EQ(e.find_last_not_of('\0'), StringPiece::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), "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(static_cast<const void*>("foobar"), 6);
+  ASSERT_EQ(c, a);
+  c.set(static_cast<const void*>("foobar"), 0);
+  ASSERT_EQ(c, e);
+  c.set(static_cast<const void*>("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_TRUE(abc.compare(BasicStringPiece<TypeParam>(alphabet)) == 0);
+
+  ASSERT_TRUE(abc < BasicStringPiece<TypeParam>(alphabet_z));
+  ASSERT_TRUE(abc.compare(BasicStringPiece<TypeParam>(alphabet_z)) < 0);
+
+  ASSERT_TRUE(abc > BasicStringPiece<TypeParam>(alphabet_y));
+  ASSERT_TRUE(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(), 0U));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(NULL));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(NULL, 0U));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>());
+  ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str.begin(), str.end()));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(str.begin(), str.begin()));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(empty));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(empty.begin(), empty.end()));
+}
+
+}  // namespace base
diff --git a/base/string_split.cc b/base/string_split.cc
new file mode 100644
index 0000000..e5befcf
--- /dev/null
+++ b/base/string_split.cc
@@ -0,0 +1,219 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/string_split.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+template<typename STR>
+static void SplitStringT(const STR& str,
+                         const typename STR::value_type s,
+                         bool trim_whitespace,
+                         std::vector<STR>* r) {
+  r->clear();
+  size_t last = 0;
+  size_t c = str.size();
+  for (size_t i = 0; i <= c; ++i) {
+    if (i == c || str[i] == s) {
+      STR tmp(str, last, i - last);
+      if (trim_whitespace)
+        TrimWhitespace(tmp, TRIM_ALL, &tmp);
+      // Avoid converting an empty or all-whitespace source string into a vector
+      // of one empty string.
+      if (i != c || !r->empty() || !tmp.empty())
+        r->push_back(tmp);
+      last = i + 1;
+    }
+  }
+}
+
+void SplitString(const string16& str,
+                 char16 c,
+                 std::vector<string16>* r) {
+  DCHECK(CBU16_IS_SINGLE(c));
+  SplitStringT(str, c, true, r);
+}
+
+void SplitString(const std::string& str,
+                 char c,
+                 std::vector<std::string>* r) {
+#if CHAR_MIN < 0
+  DCHECK(c >= 0);
+#endif
+  DCHECK(c < 0x7F);
+  SplitStringT(str, c, true, r);
+}
+
+bool SplitStringIntoKeyValues(
+    const std::string& line,
+    char key_value_delimiter,
+    std::string* key, std::vector<std::string>* values) {
+  key->clear();
+  values->clear();
+
+  // Find the key string.
+  size_t end_key_pos = line.find_first_of(key_value_delimiter);
+  if (end_key_pos == std::string::npos) {
+    DVLOG(1) << "cannot parse key from line: " << line;
+    return false;    // no key
+  }
+  key->assign(line, 0, end_key_pos);
+
+  // Find the values string.
+  std::string remains(line, end_key_pos, line.size() - end_key_pos);
+  size_t begin_values_pos = remains.find_first_not_of(key_value_delimiter);
+  if (begin_values_pos == std::string::npos) {
+    DVLOG(1) << "cannot parse value from line: " << line;
+    return false;   // no value
+  }
+  std::string values_string(remains, begin_values_pos,
+                            remains.size() - begin_values_pos);
+
+  // Construct the values vector.
+  values->push_back(values_string);
+  return true;
+}
+
+bool SplitStringIntoKeyValuePairs(
+    const std::string& line,
+    char key_value_delimiter,
+    char key_value_pair_delimiter,
+    std::vector<std::pair<std::string, std::string> >* kv_pairs) {
+  kv_pairs->clear();
+
+  std::vector<std::string> pairs;
+  SplitString(line, key_value_pair_delimiter, &pairs);
+
+  bool success = true;
+  for (size_t i = 0; i < pairs.size(); ++i) {
+    // Empty pair. SplitStringIntoKeyValues is more strict about an empty pair
+    // line, so continue with the next pair.
+    if (pairs[i].empty())
+      continue;
+
+    std::string key;
+    std::vector<std::string> value;
+    if (!SplitStringIntoKeyValues(pairs[i],
+                                  key_value_delimiter,
+                                  &key, &value)) {
+      // Don't return here, to allow for keys without associated
+      // values; just record that our split failed.
+      success = false;
+    }
+    DCHECK_LE(value.size(), 1U);
+    kv_pairs->push_back(make_pair(key, value.empty()? "" : value[0]));
+  }
+  return success;
+}
+
+template <typename STR>
+static void SplitStringUsingSubstrT(const STR& str,
+                                    const STR& s,
+                                    std::vector<STR>* r) {
+  r->clear();
+  typename STR::size_type begin_index = 0;
+  while (true) {
+    const typename STR::size_type end_index = str.find(s, begin_index);
+    if (end_index == STR::npos) {
+      const STR term = str.substr(begin_index);
+      STR tmp;
+      TrimWhitespace(term, TRIM_ALL, &tmp);
+      r->push_back(tmp);
+      return;
+    }
+    const STR term = str.substr(begin_index, end_index - begin_index);
+    STR tmp;
+    TrimWhitespace(term, TRIM_ALL, &tmp);
+    r->push_back(tmp);
+    begin_index = end_index + s.size();
+  }
+}
+
+void SplitStringUsingSubstr(const string16& str,
+                            const string16& s,
+                            std::vector<string16>* r) {
+  SplitStringUsingSubstrT(str, s, r);
+}
+
+void SplitStringUsingSubstr(const std::string& str,
+                            const std::string& s,
+                            std::vector<std::string>* r) {
+  SplitStringUsingSubstrT(str, s, r);
+}
+
+void SplitStringDontTrim(const string16& str,
+                         char16 c,
+                         std::vector<string16>* r) {
+  DCHECK(CBU16_IS_SINGLE(c));
+  SplitStringT(str, c, false, r);
+}
+
+void SplitStringDontTrim(const std::string& str,
+                         char c,
+                         std::vector<std::string>* r) {
+  DCHECK(IsStringUTF8(str));
+#if CHAR_MIN < 0
+  DCHECK(c >= 0);
+#endif
+  DCHECK(c < 0x7F);
+  SplitStringT(str, c, false, r);
+}
+
+template<typename STR>
+void SplitStringAlongWhitespaceT(const STR& str, std::vector<STR>* result) {
+  result->clear();
+  const size_t length = str.length();
+  if (!length)
+    return;
+
+  bool last_was_ws = false;
+  size_t last_non_ws_start = 0;
+  for (size_t i = 0; i < length; ++i) {
+    switch (str[i]) {
+      // HTML 5 defines whitespace as: space, tab, LF, line tab, FF, or CR.
+      case L' ':
+      case L'\t':
+      case L'\xA':
+      case L'\xB':
+      case L'\xC':
+      case L'\xD':
+        if (!last_was_ws) {
+          if (i > 0) {
+            result->push_back(
+                str.substr(last_non_ws_start, i - last_non_ws_start));
+          }
+          last_was_ws = true;
+        }
+        break;
+
+      default:  // Not a space character.
+        if (last_was_ws) {
+          last_was_ws = false;
+          last_non_ws_start = i;
+        }
+        break;
+    }
+  }
+  if (!last_was_ws) {
+    result->push_back(
+        str.substr(last_non_ws_start, length - last_non_ws_start));
+  }
+}
+
+void SplitStringAlongWhitespace(const string16& str,
+                                std::vector<string16>* result) {
+  SplitStringAlongWhitespaceT(str, result);
+}
+
+void SplitStringAlongWhitespace(const std::string& str,
+                                std::vector<std::string>* result) {
+  SplitStringAlongWhitespaceT(str, result);
+}
+
+}  // namespace base
diff --git a/base/string_split.h b/base/string_split.h
new file mode 100644
index 0000000..f8022e3
--- /dev/null
+++ b/base/string_split.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRING_SPLIT_H_
+#define BASE_STRING_SPLIT_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/string16.h"
+
+namespace base {
+
+// Splits |str| into a vector of strings delimited by |s|, placing the results
+// in |r|. If several instances of |s| are contiguous, or if |str| begins with
+// or ends with |s|, then an empty string is inserted.
+//
+// Every substring is trimmed of any leading or trailing white space.
+// NOTE: |c| must be in BMP (Basic Multilingual Plane)
+BASE_EXPORT void SplitString(const string16& str,
+                             char16 c,
+                             std::vector<string16>* r);
+// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
+// the trailing byte of a multi-byte character can be in the ASCII range.
+// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
+// Note: |c| must be in the ASCII range.
+BASE_EXPORT void SplitString(const std::string& str,
+                             char c,
+                             std::vector<std::string>* r);
+
+BASE_EXPORT bool SplitStringIntoKeyValues(
+    const std::string& line,
+    char key_value_delimiter,
+    std::string* key, std::vector<std::string>* values);
+
+BASE_EXPORT bool SplitStringIntoKeyValuePairs(
+    const std::string& line,
+    char key_value_delimiter,
+    char key_value_pair_delimiter,
+    std::vector<std::pair<std::string, std::string> >* kv_pairs);
+
+// The same as SplitString, but use a substring delimiter instead of a char.
+BASE_EXPORT void SplitStringUsingSubstr(const string16& str,
+                                        const string16& s,
+                                        std::vector<string16>* r);
+BASE_EXPORT void SplitStringUsingSubstr(const std::string& str,
+                                        const std::string& s,
+                                        std::vector<std::string>* r);
+
+// The same as SplitString, but don't trim white space.
+// NOTE: |c| must be in BMP (Basic Multilingual Plane)
+BASE_EXPORT void SplitStringDontTrim(const string16& str,
+                                     char16 c,
+                                     std::vector<string16>* r);
+// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
+// the trailing byte of a multi-byte character can be in the ASCII range.
+// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
+// Note: |c| must be in the ASCII range.
+BASE_EXPORT void SplitStringDontTrim(const std::string& str,
+                                     char c,
+                                     std::vector<std::string>* r);
+
+// WARNING: this uses whitespace as defined by the HTML5 spec. If you need
+// a function similar to this but want to trim all types of whitespace, then
+// factor this out into a function that takes a string containing the characters
+// that are treated as whitespace.
+//
+// Splits the string along whitespace (where whitespace is the five space
+// characters defined by HTML 5). Each contiguous block of non-whitespace
+// characters is added to result.
+BASE_EXPORT void SplitStringAlongWhitespace(const string16& str,
+                                            std::vector<string16>* result);
+BASE_EXPORT void SplitStringAlongWhitespace(const std::string& str,
+                                            std::vector<std::string>* result);
+
+}  // namespace base
+
+#endif  // BASE_STRING_SPLIT_H
diff --git a/base/string_split_unittest.cc b/base/string_split_unittest.cc
new file mode 100644
index 0000000..a4412e4
--- /dev/null
+++ b/base/string_split_unittest.cc
@@ -0,0 +1,316 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/string_split.h"
+
+#include "base/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::ElementsAre;
+
+namespace base {
+
+namespace {
+
+#if !defined(WCHAR_T_IS_UTF16)
+// Overload SplitString with a wide-char version to make it easier to
+// test the string16 version with wide character literals.
+void SplitString(const std::wstring& str,
+                 wchar_t c,
+                 std::vector<std::wstring>* result) {
+  std::vector<string16> result16;
+  SplitString(WideToUTF16(str), c, &result16);
+  for (size_t i = 0; i < result16.size(); ++i)
+    result->push_back(UTF16ToWide(result16[i]));
+}
+#endif
+
+}  // anonymous namespace
+
+class SplitStringIntoKeyValuesTest : public testing::Test {
+ protected:
+  std::string key;
+  std::vector<std::string> values;
+};
+
+TEST_F(SplitStringIntoKeyValuesTest, EmptyInputMultipleValues) {
+  EXPECT_FALSE(SplitStringIntoKeyValues("",     // Empty input
+                                        '\t',   // Key separators
+                                        &key, &values));
+  EXPECT_TRUE(key.empty());
+  EXPECT_TRUE(values.empty());
+}
+
+TEST_F(SplitStringIntoKeyValuesTest, EmptyValueInputMultipleValues) {
+  EXPECT_FALSE(SplitStringIntoKeyValues("key_with_no_value\t",
+                                        '\t',  // Key separators
+                                        &key, &values));
+  EXPECT_EQ("key_with_no_value", key);
+  EXPECT_TRUE(values.empty());
+}
+
+TEST_F(SplitStringIntoKeyValuesTest, EmptyKeyInputMultipleValues) {
+  EXPECT_TRUE(SplitStringIntoKeyValues("\tvalue for empty key",
+                                       '\t',  // Key separators
+                                       &key, &values));
+  EXPECT_TRUE(key.empty());
+  ASSERT_EQ(1U, values.size());
+}
+
+TEST_F(SplitStringIntoKeyValuesTest, KeyWithMultipleValues) {
+  EXPECT_TRUE(SplitStringIntoKeyValues("key1\tvalue1,   value2   value3",
+                                       '\t',  // Key separators
+                                       &key, &values));
+  EXPECT_EQ("key1", key);
+  ASSERT_EQ(1U, values.size());
+  EXPECT_EQ("value1,   value2   value3", values[0]);
+}
+
+TEST_F(SplitStringIntoKeyValuesTest, EmptyInputSingleValue) {
+  EXPECT_FALSE(SplitStringIntoKeyValues("",     // Empty input
+                                        '\t',   // Key separators
+                                        &key, &values));
+  EXPECT_TRUE(key.empty());
+  EXPECT_TRUE(values.empty());
+}
+
+TEST_F(SplitStringIntoKeyValuesTest, EmptyValueInputSingleValue) {
+  EXPECT_FALSE(SplitStringIntoKeyValues("key_with_no_value\t",
+                                        '\t',  // Key separators
+                                        &key, &values));
+  EXPECT_EQ("key_with_no_value", key);
+  EXPECT_TRUE(values.empty());
+}
+
+TEST_F(SplitStringIntoKeyValuesTest, EmptyKeyInputSingleValue) {
+  EXPECT_TRUE(SplitStringIntoKeyValues("\tvalue for empty key",
+                                       '\t',  // Key separators
+                                       &key, &values));
+  EXPECT_TRUE(key.empty());
+  ASSERT_EQ(1U, values.size());
+  EXPECT_EQ("value for empty key", values[0]);
+}
+
+TEST_F(SplitStringIntoKeyValuesTest, KeyWithSingleValue) {
+  EXPECT_TRUE(SplitStringIntoKeyValues("key1\tvalue1,   value2   value3",
+                                       '\t',  // Key separators
+                                       &key, &values));
+  EXPECT_EQ("key1", key);
+  ASSERT_EQ(1U, values.size());
+  EXPECT_EQ("value1,   value2   value3", values[0]);
+}
+
+class SplitStringIntoKeyValuePairsTest : public testing::Test {
+ protected:
+  std::vector<std::pair<std::string, std::string> > kv_pairs;
+};
+
+TEST_F(SplitStringIntoKeyValuePairsTest, EmptyString) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("",
+                                           ':',   // Key-value delimiters
+                                           ',',   // Key-value pair delims
+                                           &kv_pairs));
+  EXPECT_TRUE(kv_pairs.empty());
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, EmptySecondPair) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:value1,,key3:value3",
+                                           ':',   // Key-value delimiters
+                                           ',',   // Key-value pair delims
+                                           &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, EmptySecondValue) {
+  EXPECT_FALSE(SplitStringIntoKeyValuePairs("key1:value1 , key2:",
+                                            ':',   // Key-value delimiters
+                                            ',',   // Key-value pair delims
+                                            &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("", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, DelimiterInValue) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:va:ue1 , key2:value2",
+                                           ':',   // Key-value delimiters
+                                           ',',   // Key-value pair delims
+                                           &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("", "DELIMITER", &results);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_THAT(results, ElementsAre(""));
+}
+
+// Test for SplitString
+TEST(StringUtilTest, SplitString) {
+  std::vector<std::wstring> r;
+
+  SplitString(L"", L',', &r);
+  EXPECT_EQ(0U, r.size());
+  r.clear();
+
+  SplitString(L"a,b,c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"b");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
+  SplitString(L"a, b, c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"b");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
+  SplitString(L"a,,c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
+  SplitString(L"   ", L'*', &r);
+  EXPECT_EQ(0U, r.size());
+  r.clear();
+
+  SplitString(L"foo", L'*', &r);
+  ASSERT_EQ(1U, r.size());
+  EXPECT_EQ(r[0], L"foo");
+  r.clear();
+
+  SplitString(L"foo ,", L',', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], L"foo");
+  EXPECT_EQ(r[1], L"");
+  r.clear();
+
+  SplitString(L",", L',', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], L"");
+  EXPECT_EQ(r[1], L"");
+  r.clear();
+
+  SplitString(L"\t\ta\t", L'\t', &r);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], L"");
+  EXPECT_EQ(r[1], L"");
+  EXPECT_EQ(r[2], L"a");
+  EXPECT_EQ(r[3], L"");
+  r.clear();
+
+  SplitString(L"\ta\t\nb\tcc", L'\n', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"b\tcc");
+  r.clear();
+}
+
+TEST(SplitStringUsingSubstrTest, StringWithNoDelimiter) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr("alongwordwithnodelimiter", "DELIMITER", &results);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter"));
+}
+
+TEST(SplitStringUsingSubstrTest, LeadingDelimitersSkipped) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(
+      "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree",
+      "DELIMITER",
+      &results);
+  ASSERT_EQ(6u, results.size());
+  EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three"));
+}
+
+TEST(SplitStringUsingSubstrTest, ConsecutiveDelimitersSkipped) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(
+      "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro",
+      "DELIMITER",
+      &results);
+  ASSERT_EQ(7u, results.size());
+  EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro"));
+}
+
+TEST(SplitStringUsingSubstrTest, TrailingDelimitersSkipped) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(
+      "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER",
+      "DELIMITER",
+      &results);
+  ASSERT_EQ(7u, results.size());
+  EXPECT_THAT(
+      results, ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
+}
+
+TEST(StringSplitTest, StringSplitDontTrim) {
+  std::vector<std::string> r;
+
+  SplitStringDontTrim("   ", '*', &r);
+  ASSERT_EQ(1U, r.size());
+  EXPECT_EQ(r[0], "   ");
+
+  SplitStringDontTrim("\t  \ta\t ", '\t', &r);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], "");
+  EXPECT_EQ(r[1], "  ");
+  EXPECT_EQ(r[2], "a");
+  EXPECT_EQ(r[3], " ");
+
+  SplitStringDontTrim("\ta\t\nb\tcc", '\n', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], "\ta\t");
+  EXPECT_EQ(r[1], "b\tcc");
+}
+
+TEST(StringSplitTest, SplitStringAlongWhitespace) {
+  struct TestData {
+    const char* input;
+    const size_t expected_result_count;
+    const char* output1;
+    const char* output2;
+  } data[] = {
+    { "a",       1, "a",  ""   },
+    { " ",       0, "",   ""   },
+    { " a",      1, "a",  ""   },
+    { " ab ",    1, "ab", ""   },
+    { " ab c",   2, "ab", "c"  },
+    { " ab c ",  2, "ab", "c"  },
+    { " ab cd",  2, "ab", "cd" },
+    { " ab cd ", 2, "ab", "cd" },
+    { " \ta\t",  1, "a",  ""   },
+    { " b\ta\t", 2, "b",  "a"  },
+    { " b\tat",  2, "b",  "at" },
+    { "b\tat",   2, "b",  "at" },
+    { "b\t at",  2, "b",  "at" },
+  };
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
+    std::vector<std::string> results;
+    SplitStringAlongWhitespace(data[i].input, &results);
+    ASSERT_EQ(data[i].expected_result_count, results.size());
+    if (data[i].expected_result_count > 0)
+      ASSERT_EQ(data[i].output1, results[0]);
+    if (data[i].expected_result_count > 1)
+      ASSERT_EQ(data[i].output2, results[1]);
+  }
+}
+
+}  // namespace base
diff --git a/base/string_tokenizer.h b/base/string_tokenizer.h
new file mode 100644
index 0000000..c2307a5
--- /dev/null
+++ b/base/string_tokenizer.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.
+
+#ifndef BASE_STRING_TOKENIZER_H_
+#define BASE_STRING_TOKENIZER_H_
+
+#include <algorithm>
+#include <string>
+
+#include "base/string_piece.h"
+
+// 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;
+
+#endif  // BASE_STRING_TOKENIZER_H_
diff --git a/base/string_tokenizer_unittest.cc b/base/string_tokenizer_unittest.cc
new file mode 100644
index 0000000..80cb960
--- /dev/null
+++ b/base/string_tokenizer_unittest.cc
@@ -0,0 +1,229 @@
+// 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/string_tokenizer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace {
+class StringTokenizerTest : public testing::Test {};
+}
+
+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());
+}
diff --git a/base/string_util.cc b/base/string_util.cc
new file mode 100644
index 0000000..9e3422d
--- /dev/null
+++ b/base/string_util.cc
@@ -0,0 +1,1060 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/string_util.h"
+
+#include "build/build_config.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/utf_string_conversion_utils.h"
+#include "base/utf_string_conversions.h"
+#include "base/third_party/icu/icu_utf.h"
+
+namespace {
+
+// Force the singleton used by Empty[W]String[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 std::wstring ws;
+  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;
+}
+
+}  // namespace
+
+namespace base {
+
+bool IsWprintfFormatPortable(const wchar_t* format) {
+  for (const wchar_t* position = format; *position != '\0'; ++position) {
+    if (*position == '%') {
+      bool in_specification = true;
+      bool modifier_l = false;
+      while (in_specification) {
+        // Eat up characters until reaching a known specifier.
+        if (*++position == '\0') {
+          // The format string ended in the middle of a specification.  Call
+          // it portable because no unportable specifications were found.  The
+          // string is equally broken on all platforms.
+          return true;
+        }
+
+        if (*position == 'l') {
+          // 'l' is the only thing that can save the 's' and 'c' specifiers.
+          modifier_l = true;
+        } else if (((*position == 's' || *position == 'c') && !modifier_l) ||
+                   *position == 'S' || *position == 'C' || *position == 'F' ||
+                   *position == 'D' || *position == 'O' || *position == 'U') {
+          // Not portable.
+          return false;
+        }
+
+        if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
+          // Portable, keep scanning the rest of the format string.
+          in_specification = false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+}  // namespace base
+
+
+const std::string& EmptyString() {
+  return EmptyStrings::GetInstance()->s;
+}
+
+const std::wstring& EmptyWString() {
+  return EmptyStrings::GetInstance()->ws;
+}
+
+const string16& EmptyString16() {
+  return EmptyStrings::GetInstance()->s16;
+}
+
+#define WHITESPACE_UNICODE \
+  0x0009, /* <control-0009> to <control-000D> */ \
+  0x000A,                                        \
+  0x000B,                                        \
+  0x000C,                                        \
+  0x000D,                                        \
+  0x0020, /* Space */                            \
+  0x0085, /* <control-0085> */                   \
+  0x00A0, /* No-Break Space */                   \
+  0x1680, /* Ogham Space Mark */                 \
+  0x180E, /* Mongolian Vowel Separator */        \
+  0x2000, /* En Quad to Hair Space */            \
+  0x2001,                                        \
+  0x2002,                                        \
+  0x2003,                                        \
+  0x2004,                                        \
+  0x2005,                                        \
+  0x2006,                                        \
+  0x2007,                                        \
+  0x2008,                                        \
+  0x2009,                                        \
+  0x200A,                                        \
+  0x200C, /* Zero Width Non-Joiner */            \
+  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,    // <control-0009> to <control-000D>
+  0x0A,
+  0x0B,
+  0x0C,
+  0x0D,
+  0x20,    // Space
+  0
+};
+
+const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF";
+
+template<typename STR>
+bool ReplaceCharsT(const STR& input,
+                   const typename STR::value_type 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 char16 replace_chars[],
+                  const string16& replace_with,
+                  string16* output) {
+  return ReplaceCharsT(input, replace_chars, replace_with, output);
+}
+
+bool ReplaceChars(const std::string& input,
+                  const char replace_chars[],
+                  const std::string& replace_with,
+                  std::string* output) {
+  return ReplaceCharsT(input, replace_chars, replace_with, output);
+}
+
+bool RemoveChars(const string16& input,
+                 const char16 remove_chars[],
+                 string16* output) {
+  return ReplaceChars(input, remove_chars, string16(), output);
+}
+
+bool RemoveChars(const std::string& input,
+                 const char remove_chars[],
+                 std::string* output) {
+  return ReplaceChars(input, remove_chars, std::string(), output);
+}
+
+template<typename STR>
+TrimPositions TrimStringT(const STR& input,
+                          const typename STR::value_type trim_chars[],
+                          TrimPositions positions,
+                          STR* output) {
+  // Find the edges of leading/trailing whitespace as desired.
+  const typename STR::size_type last_char = input.length() - 1;
+  const typename STR::size_type first_good_char = (positions & TRIM_LEADING) ?
+      input.find_first_not_of(trim_chars) : 0;
+  const typename STR::size_type last_good_char = (positions & TRIM_TRAILING) ?
+      input.find_last_not_of(trim_chars) : last_char;
+
+  // When the string was all whitespace, report that we stripped off whitespace
+  // from whichever position the caller was interested in.  For empty input, we
+  // stripped no whitespace, 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 the whitespace.
+  *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 std::wstring& input,
+                const wchar_t trim_chars[],
+                std::wstring* output) {
+  return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+bool TrimString(const string16& input,
+                const char16 trim_chars[],
+                string16* output) {
+  return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+#endif
+
+bool TrimString(const std::string& input,
+                const char trim_chars[],
+                std::string* output) {
+  return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+
+void TruncateUTF8ToByteSize(const std::string& input,
+                            const size_t byte_size,
+                            std::string* output) {
+  DCHECK(output);
+  if (byte_size > input.length()) {
+    *output = input;
+    return;
+  }
+  DCHECK_LE(byte_size, static_cast<uint32>(kint32max));
+  // Note: This cast is necessary because CBU8_NEXT uses int32s.
+  int32 truncation_length = static_cast<int32>(byte_size);
+  int32 char_index = truncation_length - 1;
+  const char* data = input.data();
+
+  // Using CBU8, we will move backwards from the truncation point
+  // to the beginning of the string looking for a valid UTF8
+  // character.  Once a full UTF8 character is found, we will
+  // truncate the string to the end of that character.
+  while (char_index >= 0) {
+    int32 prev = char_index;
+    uint32 code_point = 0;
+    CBU8_NEXT(data, char_index, truncation_length, code_point);
+    if (!base::IsValidCharacter(code_point) ||
+        !base::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, kWhitespaceUTF16, positions, output);
+}
+
+TrimPositions TrimWhitespaceASCII(const std::string& input,
+                                  TrimPositions positions,
+                                  std::string* output) {
+  return TrimStringT(input, kWhitespaceASCII, positions, output);
+}
+
+// This function is only for backward-compatibility.
+// To be removed when all callers are updated.
+TrimPositions TrimWhitespace(const std::string& input,
+                             TrimPositions positions,
+                             std::string* output) {
+  return TrimWhitespaceASCII(input, positions, output);
+}
+
+template<typename STR>
+STR CollapseWhitespaceT(const STR& text,
+                        bool trim_sequences_with_line_breaks) {
+  STR result;
+  result.resize(text.size());
+
+  // Set flags to pretend we're already in a trimmed whitespace sequence, so we
+  // will trim any leading whitespace.
+  bool in_whitespace = true;
+  bool already_trimmed = true;
+
+  int chars_written = 0;
+  for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) {
+    if (IsWhitespace(*i)) {
+      if (!in_whitespace) {
+        // Reduce all whitespace sequences to a single space.
+        in_whitespace = true;
+        result[chars_written++] = L' ';
+      }
+      if (trim_sequences_with_line_breaks && !already_trimmed &&
+          ((*i == '\n') || (*i == '\r'))) {
+        // Whitespace sequences containing CR or LF are eliminated entirely.
+        already_trimmed = true;
+        --chars_written;
+      }
+    } else {
+      // Non-whitespace chracters are copied straight across.
+      in_whitespace = false;
+      already_trimmed = false;
+      result[chars_written++] = *i;
+    }
+  }
+
+  if (in_whitespace && !already_trimmed) {
+    // Any trailing whitespace is eliminated.
+    --chars_written;
+  }
+
+  result.resize(chars_written);
+  return result;
+}
+
+std::wstring CollapseWhitespace(const std::wstring& text,
+                                bool trim_sequences_with_line_breaks) {
+  return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+string16 CollapseWhitespace(const string16& text,
+                            bool trim_sequences_with_line_breaks) {
+  return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
+}
+#endif
+
+std::string CollapseWhitespaceASCII(const std::string& text,
+                                    bool trim_sequences_with_line_breaks) {
+  return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
+}
+
+bool ContainsOnlyWhitespaceASCII(const std::string& str) {
+  for (std::string::const_iterator i(str.begin()); i != str.end(); ++i) {
+    if (!IsAsciiWhitespace(*i))
+      return false;
+  }
+  return true;
+}
+
+bool ContainsOnlyWhitespace(const string16& str) {
+  return str.find_first_not_of(kWhitespaceUTF16) == string16::npos;
+}
+
+template<typename STR>
+static bool ContainsOnlyCharsT(const STR& input, const STR& characters) {
+  for (typename STR::const_iterator iter = input.begin();
+       iter != input.end(); ++iter) {
+    if (characters.find(*iter) == STR::npos)
+      return false;
+  }
+  return true;
+}
+
+bool ContainsOnlyChars(const std::wstring& input,
+                       const std::wstring& characters) {
+  return ContainsOnlyCharsT(input, characters);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+bool ContainsOnlyChars(const string16& input, const string16& characters) {
+  return ContainsOnlyCharsT(input, characters);
+}
+#endif
+
+bool ContainsOnlyChars(const std::string& input,
+                       const std::string& characters) {
+  return ContainsOnlyCharsT(input, characters);
+}
+
+std::string WideToASCII(const std::wstring& wide) {
+  DCHECK(IsStringASCII(wide)) << wide;
+  return std::string(wide.begin(), wide.end());
+}
+
+std::string UTF16ToASCII(const string16& utf16) {
+  DCHECK(IsStringASCII(utf16)) << utf16;
+  return std::string(utf16.begin(), utf16.end());
+}
+
+// Latin1 is just the low range of Unicode, so we can copy directly to convert.
+bool WideToLatin1(const std::wstring& wide, std::string* latin1) {
+  std::string output;
+  output.resize(wide.size());
+  latin1->clear();
+  for (size_t i = 0; i < wide.size(); i++) {
+    if (wide[i] > 255)
+      return false;
+    output[i] = static_cast<char>(wide[i]);
+  }
+  latin1->swap(output);
+  return true;
+}
+
+template<class STR>
+static bool DoIsStringASCII(const STR& str) {
+  for (size_t i = 0; i < str.length(); i++) {
+    typename ToUnsigned<typename STR::value_type>::Unsigned c = str[i];
+    if (c > 0x7F)
+      return false;
+  }
+  return true;
+}
+
+bool IsStringASCII(const std::wstring& str) {
+  return DoIsStringASCII(str);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+bool IsStringASCII(const string16& str) {
+  return DoIsStringASCII(str);
+}
+#endif
+
+bool IsStringASCII(const base::StringPiece& str) {
+  return DoIsStringASCII(str);
+}
+
+bool IsStringUTF8(const std::string& str) {
+  const char *src = str.data();
+  int32 src_len = static_cast<int32>(str.length());
+  int32 char_index = 0;
+
+  while (char_index < src_len) {
+    int32 code_point;
+    CBU8_NEXT(src, char_index, src_len, code_point);
+    if (!base::IsValidCharacter(code_point))
+      return false;
+  }
+  return true;
+}
+
+template<typename Iter>
+static inline bool DoLowerCaseEqualsASCII(Iter a_begin,
+                                          Iter a_end,
+                                          const char* b) {
+  for (Iter it = a_begin; it != a_end; ++it, ++b) {
+    if (!*b || base::ToLowerASCII(*it) != *b)
+      return false;
+  }
+  return *b == 0;
+}
+
+// Front-ends for LowerCaseEqualsASCII.
+bool LowerCaseEqualsASCII(const std::string& a, const char* b) {
+  return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+}
+
+bool LowerCaseEqualsASCII(const std::wstring& a, const char* b) {
+  return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+bool LowerCaseEqualsASCII(const string16& a, const char* b) {
+  return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+}
+#endif
+
+bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
+                          std::string::const_iterator a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool LowerCaseEqualsASCII(std::wstring::const_iterator a_begin,
+                          std::wstring::const_iterator a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
+                          string16::const_iterator a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+#endif
+
+// TODO(port): Resolve wchar_t/iterator issues that require OS_ANDROID here.
+#if !defined(OS_ANDROID)
+bool LowerCaseEqualsASCII(const char* a_begin,
+                          const char* a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool LowerCaseEqualsASCII(const wchar_t* a_begin,
+                          const wchar_t* a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+bool LowerCaseEqualsASCII(const char16* a_begin,
+                          const char16* a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+#endif
+
+#endif  // !defined(OS_ANDROID)
+
+bool EqualsASCII(const string16& a, const base::StringPiece& b) {
+  if (a.length() != b.length())
+    return false;
+  return std::equal(b.begin(), b.end(), a.begin());
+}
+
+bool StartsWithASCII(const std::string& str,
+                     const std::string& search,
+                     bool case_sensitive) {
+  if (case_sensitive)
+    return str.compare(0, search.length(), search) == 0;
+  else
+    return base::strncasecmp(str.c_str(), search.c_str(), search.length()) == 0;
+}
+
+template <typename STR>
+bool StartsWithT(const STR& str, const STR& search, bool case_sensitive) {
+  if (case_sensitive) {
+    return str.compare(0, search.length(), search) == 0;
+  } else {
+    if (search.size() > str.size())
+      return false;
+    return std::equal(search.begin(), search.end(), str.begin(),
+                      base::CaseInsensitiveCompare<typename STR::value_type>());
+  }
+}
+
+bool StartsWith(const std::wstring& str, const std::wstring& search,
+                bool case_sensitive) {
+  return StartsWithT(str, search, case_sensitive);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+bool StartsWith(const string16& str, const string16& search,
+                bool case_sensitive) {
+  return StartsWithT(str, search, case_sensitive);
+}
+#endif
+
+template <typename STR>
+bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) {
+  typename STR::size_type str_length = str.length();
+  typename STR::size_type search_length = search.length();
+  if (search_length > str_length)
+    return false;
+  if (case_sensitive) {
+    return str.compare(str_length - search_length, search_length, search) == 0;
+  } else {
+    return std::equal(search.begin(), search.end(),
+                      str.begin() + (str_length - search_length),
+                      base::CaseInsensitiveCompare<typename STR::value_type>());
+  }
+}
+
+bool EndsWith(const std::string& str, const std::string& search,
+              bool case_sensitive) {
+  return EndsWithT(str, search, case_sensitive);
+}
+
+bool EndsWith(const std::wstring& str, const std::wstring& search,
+              bool case_sensitive) {
+  return EndsWithT(str, search, case_sensitive);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+bool EndsWith(const string16& str, const string16& search,
+              bool case_sensitive) {
+  return EndsWithT(str, search, case_sensitive);
+}
+#endif
+
+static const char* const kByteStringsUnlocalized[] = {
+  " B",
+  " kB",
+  " MB",
+  " GB",
+  " TB",
+  " PB"
+};
+
+string16 FormatBytesUnlocalized(int64 bytes) {
+  double unit_amount = static_cast<double>(bytes);
+  size_t dimension = 0;
+  const int kKilo = 1024;
+  while (unit_amount >= kKilo &&
+         dimension < arraysize(kByteStringsUnlocalized) - 1) {
+    unit_amount /= kKilo;
+    dimension++;
+  }
+
+  char buf[64];
+  if (bytes != 0 && dimension > 0 && unit_amount < 100) {
+    base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount,
+                   kByteStringsUnlocalized[dimension]);
+  } else {
+    base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount,
+                   kByteStringsUnlocalized[dimension]);
+  }
+
+  return ASCIIToUTF16(buf);
+}
+
+template<class StringType>
+void DoReplaceSubstringsAfterOffset(StringType* str,
+                                    typename StringType::size_type start_offset,
+                                    const StringType& find_this,
+                                    const StringType& replace_with,
+                                    bool replace_all) {
+  if ((start_offset == StringType::npos) || (start_offset >= str->length()))
+    return;
+
+  DCHECK(!find_this.empty());
+  for (typename StringType::size_type offs(str->find(find_this, start_offset));
+      offs != StringType::npos; offs = str->find(find_this, offs)) {
+    str->replace(offs, find_this.length(), replace_with);
+    offs += replace_with.length();
+
+    if (!replace_all)
+      break;
+  }
+}
+
+void ReplaceFirstSubstringAfterOffset(string16* str,
+                                      string16::size_type start_offset,
+                                      const string16& find_this,
+                                      const string16& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 false);  // replace first instance
+}
+
+void ReplaceFirstSubstringAfterOffset(std::string* str,
+                                      std::string::size_type start_offset,
+                                      const std::string& find_this,
+                                      const std::string& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 false);  // replace first instance
+}
+
+void ReplaceSubstringsAfterOffset(string16* str,
+                                  string16::size_type start_offset,
+                                  const string16& find_this,
+                                  const string16& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 true);  // replace all instances
+}
+
+void ReplaceSubstringsAfterOffset(std::string* str,
+                                  std::string::size_type start_offset,
+                                  const std::string& find_this,
+                                  const std::string& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 true);  // replace all instances
+}
+
+
+template<typename STR>
+static size_t TokenizeT(const STR& str,
+                        const STR& delimiters,
+                        std::vector<STR>* tokens) {
+  tokens->clear();
+
+  typename STR::size_type start = str.find_first_not_of(delimiters);
+  while (start != STR::npos) {
+    typename STR::size_type end = str.find_first_of(delimiters, start + 1);
+    if (end == STR::npos) {
+      tokens->push_back(str.substr(start));
+      break;
+    } else {
+      tokens->push_back(str.substr(start, end - start));
+      start = str.find_first_not_of(delimiters, end + 1);
+    }
+  }
+
+  return tokens->size();
+}
+
+size_t Tokenize(const std::wstring& str,
+                const std::wstring& delimiters,
+                std::vector<std::wstring>* tokens) {
+  return TokenizeT(str, delimiters, tokens);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+size_t Tokenize(const string16& str,
+                const string16& delimiters,
+                std::vector<string16>* tokens) {
+  return TokenizeT(str, delimiters, tokens);
+}
+#endif
+
+size_t Tokenize(const std::string& str,
+                const std::string& delimiters,
+                std::vector<std::string>* tokens) {
+  return TokenizeT(str, delimiters, tokens);
+}
+
+size_t Tokenize(const base::StringPiece& str,
+                const base::StringPiece& delimiters,
+                std::vector<base::StringPiece>* tokens) {
+  return TokenizeT(str, delimiters, tokens);
+}
+
+template<typename STR>
+static STR JoinStringT(const std::vector<STR>& parts, const STR& sep) {
+  if (parts.empty())
+    return STR();
+
+  STR result(parts[0]);
+  typename std::vector<STR>::const_iterator iter = parts.begin();
+  ++iter;
+
+  for (; iter != parts.end(); ++iter) {
+    result += sep;
+    result += *iter;
+  }
+
+  return result;
+}
+
+std::string JoinString(const std::vector<std::string>& parts, char sep) {
+  return JoinStringT(parts, std::string(1, sep));
+}
+
+string16 JoinString(const std::vector<string16>& parts, char16 sep) {
+  return JoinStringT(parts, string16(1, sep));
+}
+
+std::string JoinString(const std::vector<std::string>& parts,
+                       const std::string& separator) {
+  return JoinStringT(parts, separator);
+}
+
+string16 JoinString(const std::vector<string16>& parts,
+                    const string16& separator) {
+  return JoinStringT(parts, separator);
+}
+
+template<class FormatStringType, class OutStringType>
+OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string,
+    const std::vector<OutStringType>& subst, std::vector<size_t>* offsets) {
+  size_t substitutions = subst.size();
+
+  size_t sub_length = 0;
+  for (typename std::vector<OutStringType>::const_iterator iter = subst.begin();
+       iter != subst.end(); ++iter) {
+    sub_length += iter->length();
+  }
+
+  OutStringType formatted;
+  formatted.reserve(format_string.length() + sub_length);
+
+  std::vector<ReplacementOffset> r_offsets;
+  for (typename FormatStringType::const_iterator i = format_string.begin();
+       i != format_string.end(); ++i) {
+    if ('$' == *i) {
+      if (i + 1 != format_string.end()) {
+        ++i;
+        DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i;
+        if ('$' == *i) {
+          while (i != format_string.end() && '$' == *i) {
+            formatted.push_back('$');
+            ++i;
+          }
+          --i;
+        } else {
+          uintptr_t index = 0;
+          while (i != format_string.end() && '0' <= *i && *i <= '9') {
+            index *= 10;
+            index += *i - '0';
+            ++i;
+          }
+          --i;
+          index -= 1;
+          if (offsets) {
+            ReplacementOffset r_offset(index,
+                static_cast<int>(formatted.size()));
+            r_offsets.insert(std::lower_bound(r_offsets.begin(),
+                                              r_offsets.end(),
+                                              r_offset,
+                                              &CompareParameter),
+                             r_offset);
+          }
+          if (index < substitutions)
+            formatted.append(subst.at(index));
+        }
+      }
+    } else {
+      formatted.push_back(*i);
+    }
+  }
+  if (offsets) {
+    for (std::vector<ReplacementOffset>::const_iterator i = r_offsets.begin();
+         i != r_offsets.end(); ++i) {
+      offsets->push_back(i->offset);
+    }
+  }
+  return formatted;
+}
+
+string16 ReplaceStringPlaceholders(const string16& format_string,
+                                   const std::vector<string16>& subst,
+                                   std::vector<size_t>* offsets) {
+  return DoReplaceStringPlaceholders(format_string, subst, offsets);
+}
+
+std::string ReplaceStringPlaceholders(const base::StringPiece& format_string,
+                                      const std::vector<std::string>& subst,
+                                      std::vector<size_t>* offsets) {
+  return DoReplaceStringPlaceholders(format_string, subst, offsets);
+}
+
+string16 ReplaceStringPlaceholders(const string16& format_string,
+                                   const string16& a,
+                                   size_t* offset) {
+  std::vector<size_t> offsets;
+  std::vector<string16> subst;
+  subst.push_back(a);
+  string16 result = ReplaceStringPlaceholders(format_string, subst, &offsets);
+
+  DCHECK(offsets.size() == 1);
+  if (offset) {
+    *offset = offsets[0];
+  }
+  return result;
+}
+
+static bool IsWildcard(base_icu::UChar32 character) {
+  return character == '*' || character == '?';
+}
+
+// Move the strings pointers to the point where they start to differ.
+template <typename CHAR, typename NEXT>
+static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end,
+                         const CHAR** string, const CHAR* string_end,
+                         NEXT next) {
+  const CHAR* escape = NULL;
+  while (*pattern != pattern_end && *string != string_end) {
+    if (!escape && IsWildcard(**pattern)) {
+      // We don't want to match wildcard here, except if it's escaped.
+      return;
+    }
+
+    // Check if the escapement char is found. If so, skip it and move to the
+    // next character.
+    if (!escape && **pattern == '\\') {
+      escape = *pattern;
+      next(pattern, pattern_end);
+      continue;
+    }
+
+    // Check if the chars match, if so, increment the ptrs.
+    const CHAR* pattern_next = *pattern;
+    const CHAR* string_next = *string;
+    base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
+    if (pattern_char == next(&string_next, string_end) &&
+        pattern_char != (base_icu::UChar32) CBU_SENTINEL) {
+      *pattern = pattern_next;
+      *string = string_next;
+    } else {
+      // Uh ho, it did not match, we are done. If the last char was an
+      // escapement, that means that it was an error to advance the ptr here,
+      // let's put it back where it was. This also mean that the MatchPattern
+      // function will return false because if we can't match an escape char
+      // here, then no one will.
+      if (escape) {
+        *pattern = escape;
+      }
+      return;
+    }
+
+    escape = NULL;
+  }
+}
+
+template <typename CHAR, typename NEXT>
+static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
+  while (*pattern != end) {
+    if (!IsWildcard(**pattern))
+      return;
+    next(pattern, end);
+  }
+}
+
+template <typename CHAR, typename NEXT>
+static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end,
+                          const CHAR* pattern, const CHAR* pattern_end,
+                          int depth,
+                          NEXT next) {
+  const int kMaxDepth = 16;
+  if (depth > kMaxDepth)
+    return false;
+
+  // Eat all the matching chars.
+  EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
+
+  // If the string is empty, then the pattern must be empty too, or contains
+  // only wildcards.
+  if (eval == eval_end) {
+    EatWildcard(&pattern, pattern_end, next);
+    return pattern == pattern_end;
+  }
+
+  // Pattern is empty but not string, this is not a match.
+  if (pattern == pattern_end)
+    return false;
+
+  // If this is a question mark, then we need to compare the rest with
+  // the current string or the string with one character eaten.
+  const CHAR* next_pattern = pattern;
+  next(&next_pattern, pattern_end);
+  if (pattern[0] == '?') {
+    if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
+                      depth + 1, next))
+      return true;
+    const CHAR* next_eval = eval;
+    next(&next_eval, eval_end);
+    if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end,
+                      depth + 1, next))
+      return true;
+  }
+
+  // This is a *, try to match all the possible substrings with the remainder
+  // of the pattern.
+  if (pattern[0] == '*') {
+    // Collapse duplicate wild cards (********** into *) so that the
+    // method does not recurse unnecessarily. http://crbug.com/52839
+    EatWildcard(&next_pattern, pattern_end, next);
+
+    while (eval != eval_end) {
+      if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
+                        depth + 1, next))
+        return true;
+      eval++;
+    }
+
+    // We reached the end of the string, let see if the pattern contains only
+    // wildcards.
+    if (eval == eval_end) {
+      EatWildcard(&pattern, pattern_end, next);
+      if (pattern != pattern_end)
+        return false;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+struct NextCharUTF8 {
+  base_icu::UChar32 operator()(const char** p, const char* end) {
+    base_icu::UChar32 c;
+    int offset = 0;
+    CBU8_NEXT(*p, offset, end - *p, c);
+    *p += offset;
+    return c;
+  }
+};
+
+struct NextCharUTF16 {
+  base_icu::UChar32 operator()(const char16** p, const char16* end) {
+    base_icu::UChar32 c;
+    int offset = 0;
+    CBU16_NEXT(*p, offset, end - *p, c);
+    *p += offset;
+    return c;
+  }
+};
+
+bool MatchPattern(const base::StringPiece& eval,
+                  const base::StringPiece& pattern) {
+  return MatchPatternT(eval.data(), eval.data() + eval.size(),
+                       pattern.data(), pattern.data() + pattern.size(),
+                       0, NextCharUTF8());
+}
+
+bool MatchPattern(const string16& eval, const string16& pattern) {
+  return MatchPatternT(eval.c_str(), eval.c_str() + eval.size(),
+                       pattern.c_str(), pattern.c_str() + pattern.size(),
+                       0, NextCharUTF16());
+}
+
+// The following code is compatible with the OpenBSD lcpy interface.  See:
+//   http://www.gratisoft.us/todd/papers/strlcpy.html
+//   ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
+
+namespace {
+
+template <typename CHAR>
+size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
+  for (size_t i = 0; i < dst_size; ++i) {
+    if ((dst[i] = src[i]) == 0)  // We hit and copied the terminating NULL.
+      return i;
+  }
+
+  // We were left off at dst_size.  We over copied 1 byte.  Null terminate.
+  if (dst_size != 0)
+    dst[dst_size - 1] = 0;
+
+  // Count the rest of the |src|, and return it's length in characters.
+  while (src[dst_size]) ++dst_size;
+  return dst_size;
+}
+
+}  // namespace
+
+size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
+  return lcpyT<char>(dst, src, dst_size);
+}
+size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
+  return lcpyT<wchar_t>(dst, src, dst_size);
+}
diff --git a/base/string_util.h b/base/string_util.h
new file mode 100644
index 0000000..367eaa8
--- /dev/null
+++ b/base/string_util.h
@@ -0,0 +1,576 @@
+// Copyright (c) 2011 The Chromium 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_STRING_UTIL_H_
+#define BASE_STRING_UTIL_H_
+
+#include <ctype.h>
+#include <stdarg.h>   // va_list
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/string16.h"
+#include "base/string_piece.h"  // For implicit conversions.
+
+// Safe standard library wrappers for all platforms.
+
+namespace base {
+
+// C standard-library functions like "strncasecmp" and "snprintf" that aren't
+// cross-platform are provided as "base::strncasecmp", and their prototypes
+// are listed below.  These functions are then implemented as inline calls
+// to the platform-specific equivalents in the platform-specific headers.
+
+// Compares the two strings s1 and s2 without regard to case using
+// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
+// s2 > s1 according to a lexicographic comparison.
+int strcasecmp(const char* s1, const char* s2);
+
+// Compares up to count characters of s1 and s2 without regard to case using
+// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
+// s2 > s1 according to a lexicographic comparison.
+int strncasecmp(const char* s1, const char* s2, size_t count);
+
+// Same as strncmp but for char16 strings.
+int strncmp16(const char16* s1, const char16* s2, size_t count);
+
+// Wrapper for vsnprintf that always null-terminates and always returns the
+// number of characters that would be in an untruncated formatted
+// string, even when truncation occurs.
+int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments)
+    PRINTF_FORMAT(3, 0);
+
+// vswprintf always null-terminates, but when truncation occurs, it will either
+// return -1 or the number of characters that would be in an untruncated
+// formatted string.  The actual return value depends on the underlying
+// C library's vswprintf implementation.
+int vswprintf(wchar_t* buffer, size_t size,
+              const wchar_t* format, va_list arguments)
+    WPRINTF_FORMAT(3, 0);
+
+// Some of these implementations need to be inlined.
+
+// We separate the declaration from the implementation of this inline
+// function just so the PRINTF_FORMAT works.
+inline int snprintf(char* buffer, size_t size, const char* format, ...)
+    PRINTF_FORMAT(3, 4);
+inline int snprintf(char* buffer, size_t size, const char* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  int result = vsnprintf(buffer, size, format, arguments);
+  va_end(arguments);
+  return result;
+}
+
+// We separate the declaration from the implementation of this inline
+// function just so the WPRINTF_FORMAT works.
+inline int swprintf(wchar_t* buffer, size_t size, const wchar_t* format, ...)
+    WPRINTF_FORMAT(3, 4);
+inline int swprintf(wchar_t* buffer, size_t size, const wchar_t* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  int result = vswprintf(buffer, size, format, arguments);
+  va_end(arguments);
+  return result;
+}
+
+// BSD-style safe and consistent string copy functions.
+// Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|.
+// Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as
+// long as |dst_size| is not 0.  Returns the length of |src| in characters.
+// If the return value is >= dst_size, then the output was truncated.
+// NOTE: All sizes are in number of characters, NOT in bytes.
+BASE_EXPORT size_t strlcpy(char* dst, const char* src, size_t dst_size);
+BASE_EXPORT size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size);
+
+// Scan a wprintf format string to determine whether it's portable across a
+// variety of systems.  This function only checks that the conversion
+// specifiers used by the format string are supported and have the same meaning
+// on a variety of systems.  It doesn't check for other errors that might occur
+// within a format string.
+//
+// Nonportable conversion specifiers for wprintf are:
+//  - 's' and 'c' without an 'l' length modifier.  %s and %c operate on char
+//     data on all systems except Windows, which treat them as wchar_t data.
+//     Use %ls and %lc for wchar_t data instead.
+//  - 'S' and 'C', which operate on wchar_t data on all systems except Windows,
+//     which treat them as char data.  Use %ls and %lc for wchar_t data
+//     instead.
+//  - 'F', which is not identified by Windows wprintf documentation.
+//  - 'D', 'O', and 'U', which are deprecated and not available on all systems.
+//     Use %ld, %lo, and %lu instead.
+//
+// Note that there is no portable conversion specifier for char data when
+// working with wprintf.
+//
+// This function is intended to be called from base::vswprintf.
+BASE_EXPORT bool IsWprintfFormatPortable(const wchar_t* format);
+
+// ASCII-specific tolower.  The standard library's tolower is locale sensitive,
+// so we don't want to use it here.
+template <class Char> inline Char ToLowerASCII(Char c) {
+  return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+}
+
+// ASCII-specific toupper.  The standard library's toupper is locale sensitive,
+// so we don't want to use it here.
+template <class Char> inline Char ToUpperASCII(Char c) {
+  return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
+}
+
+// Function objects to aid in comparing/searching strings.
+
+template<typename Char> struct CaseInsensitiveCompare {
+ public:
+  bool operator()(Char x, Char y) const {
+    // TODO(darin): Do we really want to do locale sensitive comparisons here?
+    // See http://crbug.com/24917
+    return tolower(x) == tolower(y);
+  }
+};
+
+template<typename Char> struct CaseInsensitiveCompareASCII {
+ public:
+  bool operator()(Char x, Char y) const {
+    return ToLowerASCII(x) == ToLowerASCII(y);
+  }
+};
+
+}  // namespace base
+
+#if defined(OS_WIN)
+#include "base/string_util_win.h"
+#elif defined(OS_POSIX)
+#include "base/string_util_posix.h"
+#else
+#error Define string operations appropriately for your platform
+#endif
+
+// These threadsafe functions return references to globally unique empty
+// strings.
+//
+// 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 std::wstring& EmptyWString();
+BASE_EXPORT const string16& EmptyString16();
+
+BASE_EXPORT extern const wchar_t kWhitespaceWide[];
+BASE_EXPORT extern const char16 kWhitespaceUTF16[];
+BASE_EXPORT extern const char kWhitespaceASCII[];
+
+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 char16 remove_chars[],
+                             string16* output);
+BASE_EXPORT bool RemoveChars(const std::string& input,
+                             const char 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 char16 replace_chars[],
+                              const string16& replace_with,
+                              string16* output);
+BASE_EXPORT bool ReplaceChars(const std::string& input,
+                              const char replace_chars[],
+                              const std::string& replace_with,
+                              std::string* output);
+
+// Removes characters in |trim_chars| from the beginning and end of |input|.
+// |trim_chars| must be null-terminated.
+// NOTE: Safe to use the same variable for both |input| and |output|.
+BASE_EXPORT bool TrimString(const std::wstring& input,
+                            const wchar_t trim_chars[],
+                            std::wstring* output);
+BASE_EXPORT bool TrimString(const string16& input,
+                            const char16 trim_chars[],
+                            string16* output);
+BASE_EXPORT bool TrimString(const std::string& input,
+                            const char trim_chars[],
+                            std::string* output);
+
+// Truncates a string to the nearest UTF-8 character that will leave
+// the string less than or equal to the specified byte size.
+BASE_EXPORT void TruncateUTF8ToByteSize(const std::string& input,
+                                        const size_t byte_size,
+                                        std::string* output);
+
+// Trims any whitespace from either end of the input string.  Returns where
+// whitespace was found.
+// The non-wide version has two functions:
+// * TrimWhitespaceASCII()
+//   This function is for ASCII strings and only looks for ASCII whitespace;
+// Please choose the best one according to your usage.
+// NOTE: Safe to use the same variable for both input and output.
+enum TrimPositions {
+  TRIM_NONE     = 0,
+  TRIM_LEADING  = 1 << 0,
+  TRIM_TRAILING = 1 << 1,
+  TRIM_ALL      = TRIM_LEADING | TRIM_TRAILING,
+};
+BASE_EXPORT TrimPositions TrimWhitespace(const string16& input,
+                                         TrimPositions positions,
+                                         string16* output);
+BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input,
+                                              TrimPositions positions,
+                                              std::string* output);
+
+// Deprecated. This function is only for backward compatibility and calls
+// TrimWhitespaceASCII().
+BASE_EXPORT TrimPositions TrimWhitespace(const std::string& input,
+                                         TrimPositions positions,
+                                         std::string* output);
+
+// Searches  for CR or LF characters.  Removes all contiguous whitespace
+// strings that contain them.  This is useful when trying to deal with text
+// copied from terminals.
+// Returns |text|, with the following three transformations:
+// (1) Leading and trailing whitespace is trimmed.
+// (2) If |trim_sequences_with_line_breaks| is true, any other whitespace
+//     sequences containing a CR or LF are trimmed.
+// (3) All other whitespace sequences are converted to single spaces.
+BASE_EXPORT std::wstring CollapseWhitespace(
+    const std::wstring& text,
+    bool trim_sequences_with_line_breaks);
+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 the passed string is empty or contains only white-space
+// characters.
+BASE_EXPORT bool ContainsOnlyWhitespaceASCII(const std::string& str);
+BASE_EXPORT bool ContainsOnlyWhitespace(const string16& str);
+
+// Returns true if |input| is empty or contains only characters found in
+// |characters|.
+BASE_EXPORT bool ContainsOnlyChars(const std::wstring& input,
+                                   const std::wstring& characters);
+BASE_EXPORT bool ContainsOnlyChars(const string16& input,
+                                   const string16& characters);
+BASE_EXPORT bool ContainsOnlyChars(const std::string& input,
+                                   const std::string& characters);
+
+// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
+// beforehand.
+BASE_EXPORT std::string WideToASCII(const std::wstring& wide);
+BASE_EXPORT std::string UTF16ToASCII(const string16& utf16);
+
+// Converts the given wide string to the corresponding Latin1. This will fail
+// (return false) if any characters are more than 255.
+BASE_EXPORT bool WideToLatin1(const std::wstring& wide, std::string* latin1);
+
+// 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.
+BASE_EXPORT bool IsStringUTF8(const std::string& str);
+BASE_EXPORT bool IsStringASCII(const std::wstring& str);
+BASE_EXPORT bool IsStringASCII(const base::StringPiece& str);
+BASE_EXPORT bool IsStringASCII(const string16& str);
+
+// Converts the elements of the given string.  This version uses a pointer to
+// clearly differentiate it from the non-pointer variant.
+template <class str> inline void StringToLowerASCII(str* s) {
+  for (typename str::iterator i = s->begin(); i != s->end(); ++i)
+    *i = base::ToLowerASCII(*i);
+}
+
+template <class str> inline str StringToLowerASCII(const str& s) {
+  // for std::string and std::wstring
+  str output(s);
+  StringToLowerASCII(&output);
+  return output;
+}
+
+// Converts the elements of the given string.  This version uses a pointer to
+// clearly differentiate it from the non-pointer variant.
+template <class str> inline void StringToUpperASCII(str* s) {
+  for (typename str::iterator i = s->begin(); i != s->end(); ++i)
+    *i = base::ToUpperASCII(*i);
+}
+
+template <class str> inline str StringToUpperASCII(const str& s) {
+  // for std::string and std::wstring
+  str output(s);
+  StringToUpperASCII(&output);
+  return output;
+}
+
+// Compare the lower-case form of the given string against the given ASCII
+// string.  This is useful for doing checking if an input string matches some
+// token, and it is optimized to avoid intermediate string copies.  This API is
+// borrowed from the equivalent APIs in Mozilla.
+BASE_EXPORT bool LowerCaseEqualsASCII(const std::string& a, const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const std::wstring& a, const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const string16& a, const char* b);
+
+// Same thing, but with string iterators instead.
+BASE_EXPORT bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
+                                      std::string::const_iterator a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(std::wstring::const_iterator a_begin,
+                                      std::wstring::const_iterator a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
+                                      string16::const_iterator a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
+                                      const char* a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const wchar_t* a_begin,
+                                      const wchar_t* a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const char16* a_begin,
+                                      const char16* a_end,
+                                      const char* b);
+
+// Performs a case-sensitive string compare. The behavior is undefined if both
+// strings are not ASCII.
+BASE_EXPORT bool EqualsASCII(const string16& a, const base::StringPiece& b);
+
+// Returns true if str starts with search, or false otherwise.
+BASE_EXPORT bool StartsWithASCII(const std::string& str,
+                                 const std::string& search,
+                                 bool case_sensitive);
+BASE_EXPORT bool StartsWith(const std::wstring& str,
+                            const std::wstring& search,
+                            bool case_sensitive);
+BASE_EXPORT bool StartsWith(const string16& str,
+                            const string16& search,
+                            bool case_sensitive);
+
+// Returns true if str ends with search, or false otherwise.
+BASE_EXPORT bool EndsWith(const std::string& str,
+                          const std::string& search,
+                          bool case_sensitive);
+BASE_EXPORT bool EndsWith(const std::wstring& str,
+                          const std::wstring& search,
+                          bool case_sensitive);
+BASE_EXPORT bool EndsWith(const string16& str,
+                          const string16& search,
+                          bool case_sensitive);
+
+
+// Determines the type of ASCII character, independent of locale (the C
+// library versions will change based on locale).
+template <typename Char>
+inline bool IsAsciiWhitespace(Char c) {
+  return c == ' ' || c == '\r' || c == '\n' || c == '\t';
+}
+template <typename Char>
+inline bool IsAsciiAlpha(Char c) {
+  return ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
+}
+template <typename Char>
+inline bool IsAsciiDigit(Char c) {
+  return c >= '0' && c <= '9';
+}
+
+template <typename Char>
+inline bool IsHexDigit(Char c) {
+  return (c >= '0' && c <= '9') ||
+         (c >= 'A' && c <= 'F') ||
+         (c >= 'a' && c <= 'f');
+}
+
+template <typename Char>
+inline Char HexDigitToInt(Char c) {
+  DCHECK(IsHexDigit(c));
+  if (c >= '0' && c <= '9')
+    return c - '0';
+  if (c >= 'A' && c <= 'F')
+    return c - 'A' + 10;
+  if (c >= 'a' && c <= 'f')
+    return c - 'a' + 10;
+  return 0;
+}
+
+// Returns true if it's a whitespace character.
+inline bool IsWhitespace(wchar_t c) {
+  return wcschr(kWhitespaceWide, c) != NULL;
+}
+
+// Return a byte string in human-readable format with a unit suffix. Not
+// appropriate for use in any UI; use of FormatBytes and friends in ui/base is
+// highly recommended instead. TODO(avi): Figure out how to get callers to use
+// FormatBytes instead; remove this.
+BASE_EXPORT string16 FormatBytesUnlocalized(int64 bytes);
+
+// Starting at |start_offset| (usually 0), replace the first instance of
+// |find_this| with |replace_with|.
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
+    string16* str,
+    string16::size_type start_offset,
+    const string16& find_this,
+    const string16& replace_with);
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
+    std::string* str,
+    std::string::size_type start_offset,
+    const std::string& find_this,
+    const std::string& replace_with);
+
+// Starting at |start_offset| (usually 0), look through |str| and replace all
+// instances of |find_this| with |replace_with|.
+//
+// This does entire substrings; use std::replace in <algorithm> for single
+// characters, for example:
+//   std::replace(str.begin(), str.end(), 'a', 'b');
+BASE_EXPORT void ReplaceSubstringsAfterOffset(
+    string16* str,
+    string16::size_type start_offset,
+    const string16& find_this,
+    const string16& replace_with);
+BASE_EXPORT void ReplaceSubstringsAfterOffset(
+    std::string* str,
+    std::string::size_type start_offset,
+    const std::string& find_this,
+    const std::string& replace_with);
+
+// Reserves enough memory in |str| to accommodate |length_with_null| characters,
+// sets the size of |str| to |length_with_null - 1| characters, and returns a
+// pointer to the underlying contiguous array of characters.  This is typically
+// used when calling a function that writes results into a character array, but
+// the caller wants the data to be managed by a string-like object.  It is
+// convenient in that is can be used inline in the call, and fast in that it
+// avoids copying the results of the call from a char* into a string.
+//
+// |length_with_null| must be at least 2, since otherwise the underlying string
+// would have size 0, and trying to access &((*str)[0]) in that case can result
+// in a number of problems.
+//
+// Internally, this takes linear time because the resize() call 0-fills the
+// underlying array for potentially all
+// (|length_with_null - 1| * sizeof(string_type::value_type)) bytes.  Ideally we
+// could avoid this aspect of the resize() call, as we expect the caller to
+// immediately write over this memory, but there is no other way to set the size
+// of the string, and not doing that will mean people who access |str| rather
+// than str.c_str() will get back a string of whatever size |str| had on entry
+// to this function (probably 0).
+template <class string_type>
+inline typename string_type::value_type* WriteInto(string_type* str,
+                                                   size_t length_with_null) {
+  DCHECK_GT(length_with_null, 1u);
+  str->reserve(length_with_null);
+  str->resize(length_with_null - 1);
+  return &((*str)[0]);
+}
+
+//-----------------------------------------------------------------------------
+
+// Splits a string into its fields delimited by any of the characters in
+// |delimiters|.  Each field is added to the |tokens| vector.  Returns the
+// number of tokens found.
+BASE_EXPORT size_t Tokenize(const std::wstring& str,
+                            const std::wstring& delimiters,
+                            std::vector<std::wstring>* tokens);
+BASE_EXPORT size_t Tokenize(const string16& str,
+                            const string16& delimiters,
+                            std::vector<string16>* tokens);
+BASE_EXPORT size_t Tokenize(const std::string& str,
+                            const std::string& delimiters,
+                            std::vector<std::string>* tokens);
+BASE_EXPORT size_t Tokenize(const base::StringPiece& str,
+                            const base::StringPiece& delimiters,
+                            std::vector<base::StringPiece>* tokens);
+
+// Does the opposite of SplitString().
+BASE_EXPORT string16 JoinString(const std::vector<string16>& parts, char16 s);
+BASE_EXPORT std::string JoinString(
+    const std::vector<std::string>& parts, char s);
+
+// Join |parts| using |separator|.
+BASE_EXPORT std::string JoinString(
+    const std::vector<std::string>& parts,
+    const std::string& separator);
+BASE_EXPORT string16 JoinString(
+    const std::vector<string16>& parts,
+    const string16& separator);
+
+// Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively.
+// Additionally, any number of consecutive '$' characters is replaced by that
+// number less one. Eg $$->$, $$$->$$, etc. The offsets parameter here can be
+// NULL. This only allows you to use up to nine replacements.
+BASE_EXPORT string16 ReplaceStringPlaceholders(
+    const string16& format_string,
+    const std::vector<string16>& subst,
+    std::vector<size_t>* offsets);
+
+BASE_EXPORT std::string ReplaceStringPlaceholders(
+    const base::StringPiece& format_string,
+    const std::vector<std::string>& subst,
+    std::vector<size_t>* offsets);
+
+// Single-string shortcut for ReplaceStringHolders. |offset| may be NULL.
+BASE_EXPORT string16 ReplaceStringPlaceholders(const string16& format_string,
+                                               const string16& a,
+                                               size_t* offset);
+
+// Returns true if the string passed in matches the pattern. The pattern
+// string can contain wildcards like * and ?
+// The backslash character (\) is an escape character for * and ?
+// We limit the patterns to having a max of 16 * or ? characters.
+// ? matches 0 or 1 character, while * matches 0 or more characters.
+BASE_EXPORT bool MatchPattern(const base::StringPiece& string,
+                              const base::StringPiece& pattern);
+BASE_EXPORT bool MatchPattern(const string16& string, const string16& pattern);
+
+// Hack to convert any char-like type to its unsigned counterpart.
+// For example, it will convert char, signed char and unsigned char to unsigned
+// char.
+template<typename T>
+struct ToUnsigned {
+  typedef T Unsigned;
+};
+
+template<>
+struct ToUnsigned<char> {
+  typedef unsigned char Unsigned;
+};
+template<>
+struct ToUnsigned<signed char> {
+  typedef unsigned char Unsigned;
+};
+template<>
+struct ToUnsigned<wchar_t> {
+#if defined(WCHAR_T_IS_UTF16)
+  typedef unsigned short Unsigned;
+#elif defined(WCHAR_T_IS_UTF32)
+  typedef uint32 Unsigned;
+#endif
+};
+template<>
+struct ToUnsigned<short> {
+  typedef unsigned short Unsigned;
+};
+
+#endif  // BASE_STRING_UTIL_H_
diff --git a/base/string_util_posix.h b/base/string_util_posix.h
new file mode 100644
index 0000000..9b776e6
--- /dev/null
+++ b/base/string_util_posix.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRING_UTIL_POSIX_H_
+#define BASE_STRING_UTIL_POSIX_H_
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+
+namespace base {
+
+// Chromium code style is to not use malloc'd strings; this is only for use
+// for interaction with APIs that require it.
+inline char* strdup(const char* str) {
+  return ::strdup(str);
+}
+
+inline int strcasecmp(const char* string1, const char* string2) {
+  return ::strcasecmp(string1, string2);
+}
+
+inline int strncasecmp(const char* string1, const char* string2, size_t count) {
+  return ::strncasecmp(string1, string2, count);
+}
+
+inline int vsnprintf(char* buffer, size_t size,
+                     const char* format, va_list arguments) {
+  return ::vsnprintf(buffer, size, format, arguments);
+}
+
+inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
+#if defined(WCHAR_T_IS_UTF16)
+  return ::wcsncmp(s1, s2, count);
+#elif defined(WCHAR_T_IS_UTF32)
+  return c16memcmp(s1, s2, count);
+#endif
+}
+
+inline int vswprintf(wchar_t* buffer, size_t size,
+                     const wchar_t* format, va_list arguments) {
+  DCHECK(IsWprintfFormatPortable(format));
+  return ::vswprintf(buffer, size, format, arguments);
+}
+
+}  // namespace base
+
+#endif  // BASE_STRING_UTIL_POSIX_H_
diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc
new file mode 100644
index 0000000..d36b955
--- /dev/null
+++ b/base/string_util_unittest.cc
@@ -0,0 +1,1190 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <math.h>
+#include <stdarg.h>
+
+#include <limits>
+#include <sstream>
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "base/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("", 0, &output));
+  EXPECT_EQ(output, "");
+  EXPECT_TRUE(Truncated("\xe1\x80\xbf", 0, &output));
+  EXPECT_EQ(output, "");
+  EXPECT_FALSE(Truncated("\xe1\x80\xbf", -1, &output));
+  EXPECT_FALSE(Truncated("\xe1\x80\xbf", 4, &output));
+
+  // Testing the truncation of valid UTF8 correctly
+  EXPECT_TRUE(Truncated("abc", 2, &output));
+  EXPECT_EQ(output, "ab");
+  EXPECT_TRUE(Truncated("\xc2\x81\xc2\x81", 2, &output));
+  EXPECT_EQ(output.compare("\xc2\x81"), 0);
+  EXPECT_TRUE(Truncated("\xc2\x81\xc2\x81", 3, &output));
+  EXPECT_EQ(output.compare("\xc2\x81"), 0);
+  EXPECT_FALSE(Truncated("\xc2\x81\xc2\x81", 4, &output));
+  EXPECT_EQ(output.compare("\xc2\x81\xc2\x81"), 0);
+
+  {
+    const char array[] = "\x00\x00\xc2\x81\xc2\x81";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\x00\x00\xc2\x81", 4)), 0);
+  }
+
+  {
+    const char array[] = "\x00\xc2\x81\xc2\x81";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\x00\xc2\x81", 3)), 0);
+  }
+
+  // Testing invalid UTF8
+  EXPECT_TRUE(Truncated("\xed\xa0\x80\xed\xbf\xbf", 6, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xed\xa0\x8f", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xed\xbf\xbf", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // Testing invalid UTF8 mixed with valid UTF8
+  EXPECT_FALSE(Truncated("\xe1\x80\xbf", 3, &output));
+  EXPECT_EQ(output.compare("\xe1\x80\xbf"), 0);
+  EXPECT_FALSE(Truncated("\xf1\x80\xa0\xbf", 4, &output));
+  EXPECT_EQ(output.compare("\xf1\x80\xa0\xbf"), 0);
+  EXPECT_FALSE(Truncated("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf",
+              10, &output));
+  EXPECT_EQ(output.compare("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf"), 0);
+  EXPECT_TRUE(Truncated("a\xc2\x81\xe1\x80\xbf\xf1""a""\x80\xa0",
+              10, &output));
+  EXPECT_EQ(output.compare("a\xc2\x81\xe1\x80\xbf\xf1""a"), 0);
+  EXPECT_FALSE(Truncated("\xef\xbb\xbf" "abc", 6, &output));
+  EXPECT_EQ(output.compare("\xef\xbb\xbf" "abc"), 0);
+
+  // Overlong sequences
+  EXPECT_TRUE(Truncated("\xc0\x80", 2, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xc1\x80\xc1\x81", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xe0\x80\x80", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xe0\x82\x80", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xe0\x9f\xbf", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x80\x80\x8D", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x80\x82\x91", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x80\xa0\x80", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x8f\xbb\xbf", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf8\x80\x80\x80\xbf", 5, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xfc\x80\x80\x80\xa0\xa5", 6, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // Beyond U+10FFFF (the upper limit of Unicode codespace)
+  EXPECT_TRUE(Truncated("\xf4\x90\x80\x80", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf8\xa0\xbf\x80\xbf", 5, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xfc\x9c\xbf\x80\xbf\x80", 6, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // BOMs in UTF-16(BE|LE) and UTF-32(BE|LE)
+  EXPECT_TRUE(Truncated("\xfe\xff", 2, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xff\xfe", 2, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  {
+    const char array[] = "\x00\x00\xfe\xff";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\x00\x00", 2)), 0);
+  }
+
+  // Variants on the previous test
+  {
+    const char array[] = "\xff\xfe\x00\x00";
+    const std::string array_string(array, 4);
+    EXPECT_FALSE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\xff\xfe\x00\x00", 4)), 0);
+  }
+  {
+    const char array[] = "\xff\x00\x00\xfe";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\xff\x00\x00", 3)), 0);
+  }
+
+  // Non-characters : U+xxFFF[EF] where xx is 0x00 through 0x10 and <FDD0,FDEF>
+  EXPECT_TRUE(Truncated("\xef\xbf\xbe", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x8f\xbf\xbe", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf3\xbf\xbf\xbf", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xef\xb7\x90", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xef\xb7\xaf", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // Strings in legacy encodings that are valid in UTF-8, but
+  // are invalid as UTF-8 in real data.
+  EXPECT_TRUE(Truncated("caf\xe9", 4, &output));
+  EXPECT_EQ(output.compare("caf"), 0);
+  EXPECT_TRUE(Truncated("\xb0\xa1\xb0\xa2", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_FALSE(Truncated("\xa7\x41\xa6\x6e", 4, &output));
+  EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0);
+  EXPECT_TRUE(Truncated("\xa7\x41\xa6\x6e\xd9\xee\xe4\xee", 7,
+              &output));
+  EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0);
+
+  // Testing using the same string as input and output.
+  EXPECT_FALSE(Truncated(output, 4, &output));
+  EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0);
+  EXPECT_TRUE(Truncated(output, 3, &output));
+  EXPECT_EQ(output.compare("\xa7\x41"), 0);
+
+  // "abc" with U+201[CD] in windows-125[0-8]
+  EXPECT_TRUE(Truncated("\x93" "abc\x94", 5, &output));
+  EXPECT_EQ(output.compare("\x93" "abc"), 0);
+
+  // U+0639 U+064E U+0644 U+064E in ISO-8859-6
+  EXPECT_TRUE(Truncated("\xd9\xee\xe4\xee", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7
+  EXPECT_TRUE(Truncated("\xe3\xe5\xe9\xdC", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+}
+
+TEST(StringUtilTest, TrimWhitespace) {
+  string16 output;  // Allow contents to carry over to next testcase
+  for (size_t i = 0; i < arraysize(trim_cases); ++i) {
+    const trim_case& value = trim_cases[i];
+    EXPECT_EQ(value.return_value,
+              TrimWhitespace(WideToUTF16(value.input), value.positions,
+                             &output));
+    EXPECT_EQ(WideToUTF16(value.output), output);
+  }
+
+  // Test that TrimWhitespace() can take the same string for input and output
+  output = ASCIIToUTF16("  This is a test \r\n");
+  EXPECT_EQ(TRIM_ALL, TrimWhitespace(output, TRIM_ALL, &output));
+  EXPECT_EQ(ASCIIToUTF16("This is a test"), output);
+
+  // Once more, but with a string of whitespace
+  output = ASCIIToUTF16("  \r\n");
+  EXPECT_EQ(TRIM_ALL, TrimWhitespace(output, TRIM_ALL, &output));
+  EXPECT_EQ(string16(), output);
+
+  std::string output_ascii;
+  for (size_t i = 0; i < arraysize(trim_cases_ascii); ++i) {
+    const trim_case_ascii& value = trim_cases_ascii[i];
+    EXPECT_EQ(value.return_value,
+              TrimWhitespace(value.input, value.positions, &output_ascii));
+    EXPECT_EQ(value.output, output_ascii);
+  }
+}
+
+static const struct collapse_case {
+  const wchar_t* input;
+  const bool trim;
+  const wchar_t* output;
+} collapse_cases[] = {
+  {L" Google Video ", false, L"Google Video"},
+  {L"Google Video", false, L"Google Video"},
+  {L"", false, L""},
+  {L"  ", false, L""},
+  {L"\t\rTest String\n", false, L"Test String"},
+  {L"\x2002Test String\x00A0\x3000", false, L"Test String"},
+  {L"    Test     \n  \t String    ", false, L"Test String"},
+  {L"\x2002Test\x1680 \x2028 \tString\x00A0\x3000", false, L"Test String"},
+  {L"   Test String", false, L"Test String"},
+  {L"Test String    ", false, L"Test String"},
+  {L"Test String", false, L"Test String"},
+  {L"", true, L""},
+  {L"\n", true, L""},
+  {L"  \r  ", true, L""},
+  {L"\nFoo", true, L"Foo"},
+  {L"\r  Foo  ", true, L"Foo"},
+  {L" Foo bar ", true, L"Foo bar"},
+  {L"  \tFoo  bar  \n", true, L"Foo bar"},
+  {L" a \r b\n c \r\n d \t\re \t f \n ", true, L"abcde f"},
+};
+
+TEST(StringUtilTest, CollapseWhitespace) {
+  for (size_t i = 0; i < arraysize(collapse_cases); ++i) {
+    const collapse_case& value = collapse_cases[i];
+    EXPECT_EQ(value.output, CollapseWhitespace(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, ContainsOnlyWhitespaceASCII) {
+  EXPECT_TRUE(ContainsOnlyWhitespaceASCII(""));
+  EXPECT_TRUE(ContainsOnlyWhitespaceASCII(" "));
+  EXPECT_TRUE(ContainsOnlyWhitespaceASCII("\t"));
+  EXPECT_TRUE(ContainsOnlyWhitespaceASCII("\t \r \n  "));
+  EXPECT_FALSE(ContainsOnlyWhitespaceASCII("a"));
+  EXPECT_FALSE(ContainsOnlyWhitespaceASCII("\thello\r \n  "));
+}
+
+TEST(StringUtilTest, ContainsOnlyWhitespace) {
+  EXPECT_TRUE(ContainsOnlyWhitespace(string16()));
+  EXPECT_TRUE(ContainsOnlyWhitespace(ASCIIToUTF16(" ")));
+  EXPECT_TRUE(ContainsOnlyWhitespace(ASCIIToUTF16("\t")));
+  EXPECT_TRUE(ContainsOnlyWhitespace(ASCIIToUTF16("\t \r \n  ")));
+  EXPECT_FALSE(ContainsOnlyWhitespace(ASCIIToUTF16("a")));
+  EXPECT_FALSE(ContainsOnlyWhitespace(ASCIIToUTF16("\thello\r \n  ")));
+}
+
+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, ConvertASCII) {
+  static const char* 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]));
+    std::wstring wide = ASCIIToWide(char_cases[i]);
+    EXPECT_EQ(wchar_cases[i], wide);
+
+    EXPECT_TRUE(IsStringASCII(wchar_cases[i]));
+    std::string ascii = WideToASCII(wchar_cases[i]);
+    EXPECT_EQ(char_cases[i], ascii);
+  }
+
+  EXPECT_FALSE(IsStringASCII("Google \x80Video"));
+  EXPECT_FALSE(IsStringASCII(L"Google \x80Video"));
+
+  // Convert empty strings.
+  std::wstring wempty;
+  std::string empty;
+  EXPECT_EQ(empty, WideToASCII(wempty));
+  EXPECT_EQ(wempty, ASCIIToWide(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);
+  std::wstring wide_with_nul = ASCIIToWide(string_with_nul);
+  EXPECT_EQ(static_cast<std::wstring::size_type>(length_with_nul),
+            wide_with_nul.length());
+  std::string narrow_with_nul = WideToASCII(wide_with_nul);
+  EXPECT_EQ(static_cast<std::string::size_type>(length_with_nul),
+            narrow_with_nul.length());
+  EXPECT_EQ(0, string_with_nul.compare(narrow_with_nul));
+}
+
+TEST(StringUtilTest, ToUpperASCII) {
+  EXPECT_EQ('C', ToUpperASCII('C'));
+  EXPECT_EQ('C', ToUpperASCII('c'));
+  EXPECT_EQ('2', ToUpperASCII('2'));
+
+  EXPECT_EQ(L'C', ToUpperASCII(L'C'));
+  EXPECT_EQ(L'C', ToUpperASCII(L'c'));
+  EXPECT_EQ(L'2', ToUpperASCII(L'2'));
+
+  std::string in_place_a("Cc2");
+  StringToUpperASCII(&in_place_a);
+  EXPECT_EQ("CC2", in_place_a);
+
+  std::wstring in_place_w(L"Cc2");
+  StringToUpperASCII(&in_place_w);
+  EXPECT_EQ(L"CC2", in_place_w);
+
+  std::string original_a("Cc2");
+  std::string upper_a = StringToUpperASCII(original_a);
+  EXPECT_EQ("CC2", upper_a);
+
+  std::wstring original_w(L"Cc2");
+  std::wstring upper_w = StringToUpperASCII(original_w);
+  EXPECT_EQ(L"CC2", upper_w);
+}
+
+TEST(StringUtilTest, LowerCaseEqualsASCII) {
+  static const struct {
+    const wchar_t* src_w;
+    const char*    src_a;
+    const char*    dst;
+  } lowercase_cases[] = {
+    { L"FoO", "FoO", "foo" },
+    { L"foo", "foo", "foo" },
+    { L"FOO", "FOO", "foo" },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(lowercase_cases); ++i) {
+    EXPECT_TRUE(LowerCaseEqualsASCII(lowercase_cases[i].src_w,
+                                     lowercase_cases[i].dst));
+    EXPECT_TRUE(LowerCaseEqualsASCII(lowercase_cases[i].src_a,
+                                     lowercase_cases[i].dst));
+  }
+}
+
+TEST(StringUtilTest, FormatBytesUnlocalized) {
+  static const struct {
+    int64 bytes;
+    const char* expected;
+  } cases[] = {
+    // Expected behavior: we show one post-decimal digit when we have
+    // under two pre-decimal digits, except in cases where it makes no
+    // sense (zero or bytes).
+    // Since we switch units once we cross the 1000 mark, this keeps
+    // the display of file sizes or bytes consistently around three
+    // digits.
+    {0, "0 B"},
+    {512, "512 B"},
+    {1024*1024, "1.0 MB"},
+    {1024*1024*1024, "1.0 GB"},
+    {10LL*1024*1024*1024, "10.0 GB"},
+    {99LL*1024*1024*1024, "99.0 GB"},
+    {105LL*1024*1024*1024, "105 GB"},
+    {105LL*1024*1024*1024 + 500LL*1024*1024, "105 GB"},
+    {~(1LL<<63), "8192 PB"},
+
+    {99*1024 + 103, "99.1 kB"},
+    {1024*1024 + 103, "1.0 MB"},
+    {1024*1024 + 205 * 1024, "1.2 MB"},
+    {1024*1024*1024 + (927 * 1024*1024), "1.9 GB"},
+    {10LL*1024*1024*1024, "10.0 GB"},
+    {100LL*1024*1024*1024, "100 GB"},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(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_UNSAFE(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_UNSAFE(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'));
+}
+
+// This checks where we can use the assignment operator for a va_list. We need
+// a way to do this since Visual C doesn't support va_copy, but assignment on
+// va_list is not guaranteed to be a copy. See StringAppendVT which uses this
+// capability.
+static void VariableArgsFunc(const char* format, ...) {
+  va_list org;
+  va_start(org, format);
+
+  va_list dup;
+  GG_VA_COPY(dup, org);
+  int i1 = va_arg(org, int);
+  int j1 = va_arg(org, int);
+  char* s1 = va_arg(org, char*);
+  double d1 = va_arg(org, double);
+  va_end(org);
+
+  int i2 = va_arg(dup, int);
+  int j2 = va_arg(dup, int);
+  char* s2 = va_arg(dup, char*);
+  double d2 = va_arg(dup, double);
+
+  EXPECT_EQ(i1, i2);
+  EXPECT_EQ(j1, j2);
+  EXPECT_STREQ(s1, s2);
+  EXPECT_EQ(d1, d2);
+
+  va_end(dup);
+}
+
+TEST(StringUtilTest, VAList) {
+  VariableArgsFunc("%d %d %s %lf", 45, 92, "This is interesting", 9.21);
+}
+
+// Test for Tokenize
+template <typename STR>
+void TokenizeTest() {
+  std::vector<STR> r;
+  size_t size;
+
+  size = Tokenize(STR("This is a string"), STR(" "), &r);
+  EXPECT_EQ(4U, size);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], STR("This"));
+  EXPECT_EQ(r[1], STR("is"));
+  EXPECT_EQ(r[2], STR("a"));
+  EXPECT_EQ(r[3], STR("string"));
+  r.clear();
+
+  size = Tokenize(STR("one,two,three"), STR(","), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR("two"));
+  EXPECT_EQ(r[2], STR("three"));
+  r.clear();
+
+  size = Tokenize(STR("one,two:three;four"), STR(",:"), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR("two"));
+  EXPECT_EQ(r[2], STR("three;four"));
+  r.clear();
+
+  size = Tokenize(STR("one,two:three;four"), STR(";,:"), &r);
+  EXPECT_EQ(4U, size);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR("two"));
+  EXPECT_EQ(r[2], STR("three"));
+  EXPECT_EQ(r[3], STR("four"));
+  r.clear();
+
+  size = Tokenize(STR("one, two, three"), STR(","), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR(" two"));
+  EXPECT_EQ(r[2], STR(" three"));
+  r.clear();
+
+  size = Tokenize(STR("one, two, three, "), STR(","), &r);
+  EXPECT_EQ(4U, size);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR(" two"));
+  EXPECT_EQ(r[2], STR(" three"));
+  EXPECT_EQ(r[3], STR(" "));
+  r.clear();
+
+  size = Tokenize(STR("one, two, three,"), STR(","), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR(" two"));
+  EXPECT_EQ(r[2], STR(" three"));
+  r.clear();
+
+  size = Tokenize(STR(""), STR(","), &r);
+  EXPECT_EQ(0U, size);
+  ASSERT_EQ(0U, r.size());
+  r.clear();
+
+  size = Tokenize(STR(","), STR(","), &r);
+  EXPECT_EQ(0U, size);
+  ASSERT_EQ(0U, r.size());
+  r.clear();
+
+  size = Tokenize(STR(",;:."), STR(".:;,"), &r);
+  EXPECT_EQ(0U, size);
+  ASSERT_EQ(0U, r.size());
+  r.clear();
+
+  size = Tokenize(STR("\t\ta\t"), STR("\t"), &r);
+  EXPECT_EQ(1U, size);
+  ASSERT_EQ(1U, r.size());
+  EXPECT_EQ(r[0], STR("a"));
+  r.clear();
+
+  size = Tokenize(STR("\ta\t\nb\tcc"), STR("\n"), &r);
+  EXPECT_EQ(2U, size);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], STR("\ta\t"));
+  EXPECT_EQ(r[1], STR("b\tcc"));
+  r.clear();
+}
+
+TEST(StringUtilTest, TokenizeStdString) {
+  TokenizeTest<std::string>();
+}
+
+TEST(StringUtilTest, TokenizeStringPiece) {
+  TokenizeTest<base::StringPiece>();
+}
+
+// Test for JoinString
+TEST(StringUtilTest, JoinString) {
+  std::vector<std::string> in;
+  EXPECT_EQ("", JoinString(in, ','));
+
+  in.push_back("a");
+  EXPECT_EQ("a", JoinString(in, ','));
+
+  in.push_back("b");
+  in.push_back("c");
+  EXPECT_EQ("a,b,c", JoinString(in, ','));
+
+  in.push_back("");
+  EXPECT_EQ("a,b,c,", JoinString(in, ','));
+  in.push_back(" ");
+  EXPECT_EQ("a|b|c|| ", JoinString(in, '|'));
+}
+
+// Test for JoinString overloaded with std::string separator
+TEST(StringUtilTest, JoinStringWithString) {
+  std::string separator(", ");
+  std::vector<std::string> parts;
+  EXPECT_EQ(std::string(), JoinString(parts, separator));
+
+  parts.push_back("a");
+  EXPECT_EQ("a", JoinString(parts, separator));
+
+  parts.push_back("b");
+  parts.push_back("c");
+  EXPECT_EQ("a, b, c", JoinString(parts, separator));
+
+  parts.push_back("");
+  EXPECT_EQ("a, b, c, ", JoinString(parts, separator));
+  parts.push_back(" ");
+  EXPECT_EQ("a|b|c|| ", JoinString(parts, "|"));
+}
+
+// Test for JoinString overloaded with string16 separator
+TEST(StringUtilTest, JoinStringWithString16) {
+  string16 separator = ASCIIToUTF16(", ");
+  std::vector<string16> parts;
+  EXPECT_EQ(string16(), JoinString(parts, separator));
+
+  parts.push_back(ASCIIToUTF16("a"));
+  EXPECT_EQ(ASCIIToUTF16("a"), JoinString(parts, separator));
+
+  parts.push_back(ASCIIToUTF16("b"));
+  parts.push_back(ASCIIToUTF16("c"));
+  EXPECT_EQ(ASCIIToUTF16("a, b, c"), JoinString(parts, separator));
+
+  parts.push_back(ASCIIToUTF16(""));
+  EXPECT_EQ(ASCIIToUTF16("a, b, c, "), JoinString(parts, separator));
+  parts.push_back(ASCIIToUTF16(" "));
+  EXPECT_EQ(ASCIIToUTF16("a|b|c|| "), JoinString(parts, ASCIIToUTF16("|")));
+}
+
+TEST(StringUtilTest, StartsWith) {
+  EXPECT_TRUE(StartsWithASCII("javascript:url", "javascript", true));
+  EXPECT_FALSE(StartsWithASCII("JavaScript:url", "javascript", true));
+  EXPECT_TRUE(StartsWithASCII("javascript:url", "javascript", false));
+  EXPECT_TRUE(StartsWithASCII("JavaScript:url", "javascript", false));
+  EXPECT_FALSE(StartsWithASCII("java", "javascript", true));
+  EXPECT_FALSE(StartsWithASCII("java", "javascript", false));
+  EXPECT_FALSE(StartsWithASCII("", "javascript", false));
+  EXPECT_FALSE(StartsWithASCII("", "javascript", true));
+  EXPECT_TRUE(StartsWithASCII("java", "", false));
+  EXPECT_TRUE(StartsWithASCII("java", "", true));
+
+  EXPECT_TRUE(StartsWith(L"javascript:url", L"javascript", true));
+  EXPECT_FALSE(StartsWith(L"JavaScript:url", L"javascript", true));
+  EXPECT_TRUE(StartsWith(L"javascript:url", L"javascript", false));
+  EXPECT_TRUE(StartsWith(L"JavaScript:url", L"javascript", false));
+  EXPECT_FALSE(StartsWith(L"java", L"javascript", true));
+  EXPECT_FALSE(StartsWith(L"java", L"javascript", false));
+  EXPECT_FALSE(StartsWith(L"", L"javascript", false));
+  EXPECT_FALSE(StartsWith(L"", L"javascript", true));
+  EXPECT_TRUE(StartsWith(L"java", L"", false));
+  EXPECT_TRUE(StartsWith(L"java", L"", true));
+}
+
+TEST(StringUtilTest, EndsWith) {
+  EXPECT_TRUE(EndsWith(L"Foo.plugin", L".plugin", true));
+  EXPECT_FALSE(EndsWith(L"Foo.Plugin", L".plugin", true));
+  EXPECT_TRUE(EndsWith(L"Foo.plugin", L".plugin", false));
+  EXPECT_TRUE(EndsWith(L"Foo.Plugin", L".plugin", false));
+  EXPECT_FALSE(EndsWith(L".plug", L".plugin", true));
+  EXPECT_FALSE(EndsWith(L".plug", L".plugin", false));
+  EXPECT_FALSE(EndsWith(L"Foo.plugin Bar", L".plugin", true));
+  EXPECT_FALSE(EndsWith(L"Foo.plugin Bar", L".plugin", false));
+  EXPECT_FALSE(EndsWith(L"", L".plugin", false));
+  EXPECT_FALSE(EndsWith(L"", L".plugin", true));
+  EXPECT_TRUE(EndsWith(L"Foo.plugin", L"", false));
+  EXPECT_TRUE(EndsWith(L"Foo.plugin", L"", true));
+  EXPECT_TRUE(EndsWith(L".plugin", L".plugin", false));
+  EXPECT_TRUE(EndsWith(L".plugin", L".plugin", true));
+  EXPECT_TRUE(EndsWith(L"", L"", false));
+  EXPECT_TRUE(EndsWith(L"", L"", true));
+}
+
+TEST(StringUtilTest, GetStringFWithOffsets) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("1"));
+  subst.push_back(ASCIIToUTF16("2"));
+  std::vector<size_t> offsets;
+
+  ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $1. Your number is $2."),
+                            subst,
+                            &offsets);
+  EXPECT_EQ(2U, offsets.size());
+  EXPECT_EQ(7U, offsets[0]);
+  EXPECT_EQ(25U, offsets[1]);
+  offsets.clear();
+
+  ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $2. Your number is $1."),
+                            subst,
+                            &offsets);
+  EXPECT_EQ(2U, offsets.size());
+  EXPECT_EQ(25U, offsets[0]);
+  EXPECT_EQ(7U, offsets[1]);
+  offsets.clear();
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersTooFew) {
+  // Test whether replacestringplaceholders works as expected when there
+  // are fewer inputs than outputs.
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("9a"));
+  subst.push_back(ASCIIToUTF16("8b"));
+  subst.push_back(ASCIIToUTF16("7c"));
+
+  string16 formatted =
+      ReplaceStringPlaceholders(
+          ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$1g,$2h,$3i"), subst, NULL);
+
+  EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,d,e,f,9ag,8bh,7ci"));
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholders) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("9a"));
+  subst.push_back(ASCIIToUTF16("8b"));
+  subst.push_back(ASCIIToUTF16("7c"));
+  subst.push_back(ASCIIToUTF16("6d"));
+  subst.push_back(ASCIIToUTF16("5e"));
+  subst.push_back(ASCIIToUTF16("4f"));
+  subst.push_back(ASCIIToUTF16("3g"));
+  subst.push_back(ASCIIToUTF16("2h"));
+  subst.push_back(ASCIIToUTF16("1i"));
+
+  string16 formatted =
+      ReplaceStringPlaceholders(
+          ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i"), subst, NULL);
+
+  EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii"));
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersMoreThan9Replacements) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("9a"));
+  subst.push_back(ASCIIToUTF16("8b"));
+  subst.push_back(ASCIIToUTF16("7c"));
+  subst.push_back(ASCIIToUTF16("6d"));
+  subst.push_back(ASCIIToUTF16("5e"));
+  subst.push_back(ASCIIToUTF16("4f"));
+  subst.push_back(ASCIIToUTF16("3g"));
+  subst.push_back(ASCIIToUTF16("2h"));
+  subst.push_back(ASCIIToUTF16("1i"));
+  subst.push_back(ASCIIToUTF16("0j"));
+  subst.push_back(ASCIIToUTF16("-1k"));
+  subst.push_back(ASCIIToUTF16("-2l"));
+  subst.push_back(ASCIIToUTF16("-3m"));
+  subst.push_back(ASCIIToUTF16("-4n"));
+
+  string16 formatted =
+      ReplaceStringPlaceholders(
+          ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i,"
+                       "$10j,$11k,$12l,$13m,$14n,$1"), subst, NULL);
+
+  EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,"
+                                    "1ii,0jj,-1kk,-2ll,-3mm,-4nn,9a"));
+}
+
+TEST(StringUtilTest, StdStringReplaceStringPlaceholders) {
+  std::vector<std::string> subst;
+  subst.push_back("9a");
+  subst.push_back("8b");
+  subst.push_back("7c");
+  subst.push_back("6d");
+  subst.push_back("5e");
+  subst.push_back("4f");
+  subst.push_back("3g");
+  subst.push_back("2h");
+  subst.push_back("1i");
+
+  std::string formatted =
+      ReplaceStringPlaceholders(
+          "$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i", subst, NULL);
+
+  EXPECT_EQ(formatted, "9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii");
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersConsecutiveDollarSigns) {
+  std::vector<std::string> subst;
+  subst.push_back("a");
+  subst.push_back("b");
+  subst.push_back("c");
+  EXPECT_EQ(ReplaceStringPlaceholders("$$1 $$$2 $$$$3", subst, NULL),
+            "$1 $$2 $$$3");
+}
+
+TEST(StringUtilTest, MatchPatternTest) {
+  EXPECT_TRUE(MatchPattern("www.google.com", "*.com"));
+  EXPECT_TRUE(MatchPattern("www.google.com", "*"));
+  EXPECT_FALSE(MatchPattern("www.google.com", "www*.g*.org"));
+  EXPECT_TRUE(MatchPattern("Hello", "H?l?o"));
+  EXPECT_FALSE(MatchPattern("www.google.com", "http://*)"));
+  EXPECT_FALSE(MatchPattern("www.msn.com", "*.COM"));
+  EXPECT_TRUE(MatchPattern("Hello*1234", "He??o\\*1*"));
+  EXPECT_FALSE(MatchPattern("", "*.*"));
+  EXPECT_TRUE(MatchPattern("", "*"));
+  EXPECT_TRUE(MatchPattern("", "?"));
+  EXPECT_TRUE(MatchPattern("", ""));
+  EXPECT_FALSE(MatchPattern("Hello", ""));
+  EXPECT_TRUE(MatchPattern("Hello*", "Hello*"));
+  // Stop after a certain recursion depth.
+  EXPECT_FALSE(MatchPattern("123456789012345678", "?????????????????*"));
+
+  // Test UTF8 matching.
+  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0", "*\xe2\x99\xa0"));
+  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0.", "heart: ?."));
+  EXPECT_TRUE(MatchPattern("hearts: \xe2\x99\xa0\xe2\x99\xa0", "*"));
+  // Invalid sequences should be handled as a single invalid character.
+  EXPECT_TRUE(MatchPattern("invalid: \xef\xbf\xbe", "invalid: ?"));
+  // If the pattern has invalid characters, it shouldn't match anything.
+  EXPECT_FALSE(MatchPattern("\xf4\x90\x80\x80", "\xf4\x90\x80\x80"));
+
+  // Test UTF16 character matching.
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("www.google.com"),
+                           UTF8ToUTF16("*.com")));
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello*1234"),
+                           UTF8ToUTF16("He??o\\*1*")));
+
+  // This test verifies that consecutive wild cards are collapsed into 1
+  // wildcard (when this doesn't occur, MatchPattern reaches it's maximum
+  // recursion depth).
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello"),
+                           UTF8ToUTF16("He********************************o")));
+}
+
+TEST(StringUtilTest, LcpyTest) {
+  // Test the normal case where we fit in our buffer.
+  {
+    char dst[10];
+    wchar_t wdst[10];
+    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
+    EXPECT_EQ(7U, base::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, base::strlcpy(dst, "abcdefg", 0));
+    EXPECT_EQ(1, dst[0]);
+    EXPECT_EQ(2, dst[1]);
+    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", 0));
+#if defined(WCHAR_T_IS_UNSIGNED)
+    EXPECT_EQ(1U, wdst[0]);
+    EXPECT_EQ(2U, wdst[1]);
+#else
+    EXPECT_EQ(1, wdst[0]);
+    EXPECT_EQ(2, wdst[1]);
+#endif
+  }
+
+  // Test the case were we _just_ competely fit including the null.
+  {
+    char dst[8];
+    wchar_t wdst[8];
+    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
+    EXPECT_EQ(7U, base::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, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "abcdef", 7));
+    EXPECT_EQ(7U, base::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, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "ab", 3));
+    EXPECT_EQ(7U, base::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_UNSAFE(cases); ++i)
+    EXPECT_EQ(cases[i].portable, base::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_UNSAFE(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("", ""));
+  EXPECT_FALSE(ContainsOnlyChars("Hello", ""));
+
+  EXPECT_TRUE(ContainsOnlyChars("", "1234"));
+  EXPECT_TRUE(ContainsOnlyChars("1", "1234"));
+  EXPECT_TRUE(ContainsOnlyChars("1", "4321"));
+  EXPECT_TRUE(ContainsOnlyChars("123", "4321"));
+  EXPECT_FALSE(ContainsOnlyChars("123a", "4321"));
+}
+
+class WriteIntoTest : public testing::Test {
+ protected:
+  static void WritesCorrectly(size_t num_chars) {
+    std::string buffer;
+    char kOriginal[] = "supercali";
+    strncpy(WriteInto(&buffer, num_chars + 1), kOriginal, num_chars);
+    // Using std::string(buffer.c_str()) instead of |buffer| truncates the
+    // string at the first \0.
+    EXPECT_EQ(std::string(kOriginal,
+                          std::min(num_chars, arraysize(kOriginal) - 1)),
+              std::string(buffer.c_str()));
+    EXPECT_EQ(num_chars, buffer.size());
+  }
+};
+
+TEST_F(WriteIntoTest, WriteInto) {
+  // Validate that WriteInto reserves enough space and
+  // sizes a string correctly.
+  WritesCorrectly(1);
+  WritesCorrectly(2);
+  WritesCorrectly(5000);
+
+  // Validate that WriteInto doesn't modify other strings
+  // when using a Copy-on-Write implementation.
+  const char kLive[] = "live";
+  const char kDead[] = "dead";
+  const std::string live = kLive;
+  std::string dead = live;
+  strncpy(WriteInto(&dead, 5), kDead, 4);
+  EXPECT_EQ(kDead, dead);
+  EXPECT_EQ(4u, dead.size());
+  EXPECT_EQ(kLive, live);
+  EXPECT_EQ(4u, live.size());
+}
+
+}  // namespace base
diff --git a/base/string_util_win.h b/base/string_util_win.h
new file mode 100644
index 0000000..2a4d3fd
--- /dev/null
+++ b/base/string_util_win.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRING_UTIL_WIN_H_
+#define BASE_STRING_UTIL_WIN_H_
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Chromium code style is to not use malloc'd strings; this is only for use
+// for interaction with APIs that require it.
+inline char* strdup(const char* str) {
+  return _strdup(str);
+}
+
+inline int strcasecmp(const char* s1, const char* s2) {
+  return _stricmp(s1, s2);
+}
+
+inline int strncasecmp(const char* s1, const char* s2, size_t count) {
+  return _strnicmp(s1, s2, count);
+}
+
+inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
+  return ::wcsncmp(s1, s2, count);
+}
+
+inline int vsnprintf(char* buffer, size_t size,
+                     const char* format, va_list arguments) {
+  int length = _vsprintf_p(buffer, size, format, arguments);
+  if (length < 0) {
+    if (size > 0)
+      buffer[0] = 0;
+    return _vscprintf_p(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 = _vswprintf_p(buffer, size, format, arguments);
+  if (length < 0) {
+    if (size > 0)
+      buffer[0] = 0;
+    return _vscwprintf_p(format, arguments);
+  }
+  return length;
+}
+
+}  // namespace base
+
+#endif  // BASE_STRING_UTIL_WIN_H_
diff --git a/base/stringize_macros.h b/base/stringize_macros.h
new file mode 100644
index 0000000..1d53e48
--- /dev/null
+++ b/base/stringize_macros.h
@@ -0,0 +1,56 @@
+// 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_STRINGIZE_MACROS_H_
+#define BASE_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)
+
+// The following are defined only on Windows (for use when interacting
+// with Windows APIs) as wide strings are otherwise deprecated.
+#if defined(OS_WIN)
+
+// Second-level utility macros to let us expand symbols.
+#define LSTRINGIZE_NO_EXPANSION(x) L ## #x
+#define TO_L_STRING_NO_EXPANSION(x) L ## x
+
+// L version of STRINGIZE(). For examples above,
+//   LSTRINGIZE(A) produces L"FOO"
+//   LSTRINGIZE(B(y)) produces L"myobj->FunctionCall(y)"
+#define LSTRINGIZE(x) LSTRINGIZE_NO_EXPANSION(x)
+
+// Adds an L in front of an existing ASCII string constant (after
+// expanding symbols). Does not do any quoting.
+//
+// For example, if:
+//   #define C "foo"
+//
+// Then:
+//   TO_L_STRING(C) produces L"foo"
+#define TO_L_STRING(x) TO_L_STRING_NO_EXPANSION(x)
+
+#endif  // defined(OS_WIN)
+
+#endif  // BASE_STRINGIZE_MACROS_H_
diff --git a/base/stringize_macros_unittest.cc b/base/stringize_macros_unittest.cc
new file mode 100644
index 0000000..8d92d53
--- /dev/null
+++ b/base/stringize_macros_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for stringize_macros.h
+
+#include "base/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));
+}
+
+#if defined(OS_WIN)
+
+TEST(StringizeTest, Wide) {
+  EXPECT_STREQ(
+      L"PREPROCESSOR_UTIL_UNITTEST_A",
+      LSTRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_A));
+  EXPECT_STREQ(
+      L"PREPROCESSOR_UTIL_UNITTEST_B(y)",
+      LSTRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_B(y)));
+  EXPECT_STREQ(
+      L"PREPROCESSOR_UTIL_UNITTEST_C",
+      LSTRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_C));
+
+  EXPECT_STREQ(L"FOO", LSTRINGIZE(PREPROCESSOR_UTIL_UNITTEST_A));
+  EXPECT_STREQ(L"myobj->FunctionCall(y)",
+               LSTRINGIZE(PREPROCESSOR_UTIL_UNITTEST_B(y)));
+  EXPECT_STREQ(L"\"foo\"", LSTRINGIZE(PREPROCESSOR_UTIL_UNITTEST_C));
+}
+
+TEST(ToLStringTest, Main) {
+  EXPECT_STREQ(L"blat", TO_L_STRING_NO_EXPANSION("blat"));
+
+  EXPECT_STREQ(L"foo", TO_L_STRING(PREPROCESSOR_UTIL_UNITTEST_C));
+  EXPECT_STREQ(L"blat", TO_L_STRING("blat"));
+}
+
+#endif  // defined(OS_WIN)
diff --git a/base/stringprintf.cc b/base/stringprintf.cc
new file mode 100644
index 0000000..79c6562
--- /dev/null
+++ b/base/stringprintf.cc
@@ -0,0 +1,185 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stringprintf.h"
+
+#include <errno.h>
+
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
+// is the size of the buffer. These return the number of characters in the
+// formatted string excluding the NUL terminator. If the buffer is not
+// large enough to accommodate the formatted string without truncation, they
+// return the number of characters that would be in the fully-formatted string
+// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
+inline int vsnprintfT(char* buffer,
+                      size_t buf_size,
+                      const char* format,
+                      va_list argptr) {
+  return base::vsnprintf(buffer, buf_size, format, argptr);
+}
+
+#if !defined(OS_ANDROID)
+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;
+  GG_VA_COPY(ap_copy, ap);
+
+#if !defined(OS_WIN)
+  errno = 0;
+#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.
+      if (errno != 0 && errno != EOVERFLOW)
+#endif
+      {
+        // If an error other than overflow occurred, it's never going to work.
+        DLOG(WARNING) << "Unable to printf the requested string due to error.";
+        return;
+      }
+      // Try doubling the buffer size.
+      mem_length *= 2;
+    } 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.
+    GG_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_ANDROID)
+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_ANDROID)
+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_ANDROID)
+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_ANDROID)
+void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
+  StringAppendVT(dst, format, ap);
+}
+#endif
+
+}  // namespace base
diff --git a/base/stringprintf.h b/base/stringprintf.h
new file mode 100644
index 0000000..9a99237
--- /dev/null
+++ b/base/stringprintf.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_STRINGPRINTF_H_
+#define BASE_STRINGPRINTF_H_
+
+#include <stdarg.h>   // va_list
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// Return a C++ string given printf-like input.
+BASE_EXPORT std::string StringPrintf(const char* format, ...)
+    PRINTF_FORMAT(1, 2);
+// OS_ANDROID's libc does not support wchar_t, so several overloads are omitted.
+#if !defined(OS_ANDROID)
+BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
+    WPRINTF_FORMAT(1, 2);
+#endif
+
+// Return a C++ string given vprintf-like input.
+BASE_EXPORT std::string StringPrintV(const char* format, va_list ap)
+    PRINTF_FORMAT(1, 0);
+
+// Store result into a supplied string and return it.
+BASE_EXPORT const std::string& SStringPrintf(std::string* dst,
+                                             const char* format, ...)
+    PRINTF_FORMAT(2, 3);
+#if !defined(OS_ANDROID)
+BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
+                                              const wchar_t* format, ...)
+    WPRINTF_FORMAT(2, 3);
+#endif
+
+// Append result to a supplied string.
+BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...)
+    PRINTF_FORMAT(2, 3);
+#if !defined(OS_ANDROID)
+// TODO(evanm): this is only used in a few places in the code;
+// replace with string16 version.
+BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
+    WPRINTF_FORMAT(2, 3);
+#endif
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string.  All other routines are just convenience wrappers around it.
+BASE_EXPORT void StringAppendV(std::string* dst, const char* format, va_list ap)
+    PRINTF_FORMAT(2, 0);
+#if !defined(OS_ANDROID)
+BASE_EXPORT void StringAppendV(std::wstring* dst,
+                               const wchar_t* format, va_list ap)
+    WPRINTF_FORMAT(2, 0);
+#endif
+
+}  // namespace base
+
+// Don't require the namespace for legacy code. New code should use "base::" or
+// have its own using decl.
+//
+// TODO(brettw) remove these when calling code is converted.
+using base::StringPrintf;
+
+#endif  // BASE_STRINGPRINTF_H_
diff --git a/base/stringprintf_unittest.cc b/base/stringprintf_unittest.cc
new file mode 100644
index 0000000..305d24a
--- /dev/null
+++ b/base/stringprintf_unittest.cc
@@ -0,0 +1,175 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/stringprintf.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_ANDROID)
+  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_ANDROID)
+  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_ANDROID)
+  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_ANDROID)
+  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_ANDROID)
+    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 string_util_buf_len = 1024;
+  // Our buffer should be one larger than the size of StringAppendVT's stack
+  // buffer.
+  const int buf_len = string_util_buf_len + 1;
+  char src[buf_len + 1];  // Need extra one for NULL-terminator.
+  for (int i = 0; i < buf_len; ++i)
+    src[i] = 'a';
+  src[buf_len] = 0;
+
+  std::string out;
+  SStringPrintf(&out, "%s", src);
+
+  EXPECT_STREQ(src, out.c_str());
+}
+
+// TODO(evanm): what's the proper cross-platform test here?
+#if defined(OS_WIN)
+// sprintf in Visual Studio fails when given U+FFFF. This tests that the
+// failure case is gracefuly handled.
+TEST(StringPrintfTest, Invalid) {
+  wchar_t invalid[2];
+  invalid[0] = 0xffff;
+  invalid[1] = 0;
+
+  std::wstring out;
+  SStringPrintf(&out, L"%ls", invalid);
+  EXPECT_STREQ(L"", out.c_str());
+}
+#endif
+
+// Test that the positional parameters work.
+TEST(StringPrintfTest, PositionalParameters) {
+  std::string out;
+  SStringPrintf(&out, "%1$s %1$s", "test");
+  EXPECT_STREQ("test test", out.c_str());
+
+#if defined(OS_WIN)
+  std::wstring wout;
+  SStringPrintf(&wout, L"%1$ls %1$ls", L"test");
+  EXPECT_STREQ(L"test test", wout.c_str());
+#endif
+}
+
+}  // namespace base
diff --git a/base/supports_user_data.cc b/base/supports_user_data.cc
new file mode 100644
index 0000000..2a0263e
--- /dev/null
+++ b/base/supports_user_data.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/supports_user_data.h"
+
+namespace base {
+
+SupportsUserData::SupportsUserData() {
+  // Harmless to construct on a different thread to subsequent usage.
+  thread_checker_.DetachFromThread();
+}
+
+SupportsUserData::Data* SupportsUserData::GetUserData(const void* key) const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DataMap::const_iterator found = user_data_.find(key);
+  if (found != user_data_.end())
+    return found->second.get();
+  return NULL;
+}
+
+void SupportsUserData::SetUserData(const void* key, Data* data) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  user_data_[key] = linked_ptr<Data>(data);
+}
+
+void SupportsUserData::RemoveUserData(const void* key) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  user_data_.erase(key);
+}
+
+void SupportsUserData::DetachUserDataThread() {
+  thread_checker_.DetachFromThread();
+}
+
+SupportsUserData::~SupportsUserData() {
+  DCHECK(thread_checker_.CalledOnValidThread() || user_data_.empty());
+}
+
+}  // namespace base
diff --git a/base/supports_user_data.h b/base/supports_user_data.h
new file mode 100644
index 0000000..7736755
--- /dev/null
+++ b/base/supports_user_data.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SUPPORTS_USER_DATA_H_
+#define BASE_SUPPORTS_USER_DATA_H_
+
+#include <map>
+
+#include "base/base_export.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+
+// This is a helper for classes that want to allow users to stash random data by
+// key. At destruction all the objects will be destructed.
+class BASE_EXPORT SupportsUserData {
+ public:
+  SupportsUserData();
+
+  // Derive from this class and add your own data members to associate extra
+  // information with this object. Alternatively, add this as a public base
+  // class to any class with a virtual destructor.
+  class BASE_EXPORT Data {
+   public:
+    virtual ~Data() {}
+  };
+
+  // The user data allows the clients to associate data with this object.
+  // Multiple user data values can be stored under different keys.
+  // This object will TAKE OWNERSHIP of the given data pointer, and will
+  // delete the object if it is changed or the object is destroyed.
+  Data* GetUserData(const void* key) const;
+  void SetUserData(const void* key, Data* data);
+  void RemoveUserData(const void* key);
+
+  // SupportsUserData is not thread-safe, and on debug build will assert it is
+  // only used on one thread. Calling this method allows the caller to hand
+  // the SupportsUserData instance across threads. Use only if you are taking
+  // full control of the synchronization of that hand over.
+  void DetachUserDataThread();
+
+ protected:
+  virtual ~SupportsUserData();
+
+ private:
+  typedef std::map<const void*, linked_ptr<Data> > DataMap;
+
+  // Externally-defined data accessible by key.
+  DataMap user_data_;
+  // Guards usage of |user_data_|
+  ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(SupportsUserData);
+};
+
+// Adapter class that releases a refcounted object when the
+// SupportsUserData::Data object is deleted.
+template <typename T>
+class UserDataAdapter : public base::SupportsUserData::Data {
+ public:
+  static T* Get(SupportsUserData* supports_user_data, const char* key) {
+    UserDataAdapter* data =
+      static_cast<UserDataAdapter*>(supports_user_data->GetUserData(key));
+    return data ? static_cast<T*>(data->object_.get()) : NULL;
+  }
+
+  UserDataAdapter(T* object) : object_(object) {}
+  T* release() { return object_.release(); }
+
+ private:
+  scoped_refptr<T> object_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserDataAdapter);
+};
+
+}  // namespace base
+
+#endif  // BASE_SUPPORTS_USER_DATA_H_
diff --git a/base/symbolize.target.mk b/base/symbolize.target.mk
new file mode 100644
index 0000000..bdac424
--- /dev/null
+++ b/base/symbolize.target.mk
@@ -0,0 +1,146 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := base_symbolize_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	base/third_party/symbolize/demangle.cc \
+	base/third_party/symbolize/symbolize.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS := \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-sign-compare \
+	-Wno-format \
+	-mthumb \
+	-march=armv7-a \
+	-mtune=cortex-a8 \
+	-mfloat-abi=softfp \
+	-mfpu=vfpv3-d16 \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-mthumb-interwork \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-Wno-error=extra \
+	-Wno-error=ignored-qualifiers \
+	-Wno-error=type-limits \
+	-Wno-error=non-virtual-dtor \
+	-Wno-error=sign-promo \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_CFLAGS_C :=
+
+MY_DEFS := \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_PEPPER_THREADING' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DUSE_SKIA=1' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_SYMBOLS_ID=""' \
+	'-DANDROID_UPSTREAM_BRINGUP=1' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH) \
+	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
+	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wno-deprecated \
+	-Wno-abi \
+	-Wno-error=c++0x-compat
+
+### Rules for final target.
+
+LOCAL_LDFLAGS := \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections
+
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: base_symbolize_gyp
+
+# Alias gyp target name.
+.PHONY: symbolize
+symbolize: base_symbolize_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/base/sync_socket.h b/base/sync_socket.h
new file mode 100644
index 0000000..eb3eeb5
--- /dev/null
+++ b/base/sync_socket.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNC_SOCKET_H_
+#define BASE_SYNC_SOCKET_H_
+
+// A socket abstraction used for sending and receiving plain
+// data.  Because the receiving is blocking, they can be used to perform
+// rudimentary cross-process synchronization with low latency.
+
+#include "base/basictypes.h"
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#include <sys/types.h>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+class BASE_EXPORT SyncSocket {
+ public:
+#if defined(OS_WIN)
+  typedef HANDLE Handle;
+#else
+  typedef int Handle;
+#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);
+
+  // 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);
+
+  // Returns the number of bytes available. If non-zero, Receive() will not
+  // not block when called. NOTE: Some implementations cannot reliably
+  // determine the number of bytes available so avoid using the returned
+  // size as a promise and simply test against zero.
+  size_t Peek();
+
+  // Extracts the contained handle.  Used for transferring between
+  // processes.
+  Handle handle() const { return handle_; }
+
+ protected:
+  Handle handle_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SyncSocket);
+};
+
+// Derives from SyncSocket and adds support for shutting down the socket from
+// another thread while a blocking Receive or Send is being done from the
+// thread that owns the socket.
+class BASE_EXPORT CancelableSyncSocket : public SyncSocket {
+ public:
+  CancelableSyncSocket();
+  explicit CancelableSyncSocket(Handle handle);
+  virtual ~CancelableSyncSocket() {}
+
+  // 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'.
+  virtual bool Close() OVERRIDE;
+  virtual size_t Receive(void* buffer, size_t length) 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.
+  virtual 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);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNC_SOCKET_H_
diff --git a/base/sync_socket_nacl.cc b/base/sync_socket_nacl.cc
new file mode 100644
index 0000000..6d6405d
--- /dev/null
+++ b/base/sync_socket_nacl.cc
@@ -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.
+
+#include "base/sync_socket.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+
+
+namespace base {
+
+const SyncSocket::Handle SyncSocket::kInvalidHandle = -1;
+
+SyncSocket::SyncSocket() : handle_(kInvalidHandle) {
+}
+
+SyncSocket::~SyncSocket() {
+}
+
+// static
+bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
+  return false;
+}
+
+bool SyncSocket::Close() {
+  if (handle_ != kInvalidHandle) {
+    if (close(handle_) < 0)
+      DPLOG(ERROR) << "close";
+    handle_ = -1;
+  }
+  return true;
+}
+
+size_t SyncSocket::Send(const void* buffer, size_t length) {
+  // Not implemented since it's not needed by any client code yet.
+  return -1;
+}
+
+size_t SyncSocket::Receive(void* buffer, size_t length) {
+  return read(handle_, buffer, length);
+}
+
+size_t SyncSocket::Peek() {
+  return -1;
+}
+
+CancelableSyncSocket::CancelableSyncSocket() {
+}
+
+CancelableSyncSocket::CancelableSyncSocket(Handle handle)
+    : SyncSocket(handle) {
+}
+
+size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
+  return -1;
+}
+
+bool CancelableSyncSocket::Shutdown() {
+  return false;
+}
+
+// static
+bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
+                                      CancelableSyncSocket* socket_b) {
+  return SyncSocket::CreatePair(socket_a, socket_b);
+}
+
+}  // namespace base
diff --git a/base/sync_socket_posix.cc b/base/sync_socket_posix.cc
new file mode 100644
index 0000000..257916d
--- /dev/null
+++ b/base/sync_socket_posix.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/sync_socket.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <fcntl.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/file_util.h"
+#include "base/logging.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);
+
+}  // 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(socket_a != socket_b);
+  DCHECK(socket_a->handle_ == kInvalidHandle);
+  DCHECK(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)
+    goto cleanup;
+
+#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)) {
+    goto cleanup;
+  }
+#endif
+
+  // Copy the handles out for successful return.
+  socket_a->handle_ = handles[0];
+  socket_b->handle_ = handles[1];
+
+  return true;
+
+ cleanup:
+  if (handles[0] != kInvalidHandle) {
+    if (HANDLE_EINTR(close(handles[0])) < 0)
+      DPLOG(ERROR) << "close";
+  }
+  if (handles[1] != kInvalidHandle) {
+    if (HANDLE_EINTR(close(handles[1])) < 0)
+      DPLOG(ERROR) << "close";
+  }
+
+  return false;
+}
+
+bool SyncSocket::Close() {
+  if (handle_ == kInvalidHandle) {
+    return false;
+  }
+  int retval = HANDLE_EINTR(close(handle_));
+  if (retval < 0)
+    DPLOG(ERROR) << "close";
+  handle_ = kInvalidHandle;
+  return (retval == 0);
+}
+
+size_t SyncSocket::Send(const void* buffer, size_t length) {
+  DCHECK_LE(length, kMaxMessageLength);
+  const char* charbuffer = static_cast<const char*>(buffer);
+  int len = file_util::WriteFileDescriptor(handle_, charbuffer, length);
+
+  return (len == -1) ? 0 : static_cast<size_t>(len);
+}
+
+size_t SyncSocket::Receive(void* buffer, size_t length) {
+  DCHECK_LE(length, kMaxMessageLength);
+  char* charbuffer = static_cast<char*>(buffer);
+  if (file_util::ReadFromFD(handle_, charbuffer, length))
+    return length;
+  return 0;
+}
+
+size_t SyncSocket::Peek() {
+  int number_chars;
+  if (-1 == ioctl(handle_, FIONREAD, &number_chars)) {
+    // If there is an error in ioctl, signal that the channel would block.
+    return 0;
+  }
+  return (size_t) number_chars;
+}
+
+CancelableSyncSocket::CancelableSyncSocket() {}
+CancelableSyncSocket::CancelableSyncSocket(Handle handle)
+    : SyncSocket(handle) {
+}
+
+bool CancelableSyncSocket::Shutdown() {
+  return HANDLE_EINTR(shutdown(handle(), SHUT_RDWR)) >= 0;
+}
+
+size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
+  long flags = 0;
+  flags = fcntl(handle_, F_GETFL, NULL);
+  if (flags != -1 && (flags & O_NONBLOCK) == 0) {
+    // Set the socket to non-blocking mode for sending if its original mode
+    // is blocking.
+    fcntl(handle_, F_SETFL, flags | O_NONBLOCK);
+  }
+
+  size_t len = SyncSocket::Send(buffer, length);
+
+  if (flags != -1 && (flags & O_NONBLOCK) == 0) {
+    // Restore the original flags.
+    fcntl(handle_, F_SETFL, flags);
+  }
+
+  return len;
+}
+
+// static
+bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
+                                      CancelableSyncSocket* socket_b) {
+  return SyncSocket::CreatePair(socket_a, socket_b);
+}
+
+}  // namespace base
diff --git a/base/sync_socket_win.cc b/base/sync_socket_win.cc
new file mode 100644
index 0000000..4fcd572
--- /dev/null
+++ b/base/sync_socket_win.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/sync_socket.h"
+
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+using win::ScopedHandle;
+
+namespace {
+// IMPORTANT: do not change how this name is generated because it will break
+// in sandboxed scenarios as we might have by-name policies that allow pipe
+// creation. Also keep the secure random number generation.
+const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\chrome.sync.%u.%u.%lu";
+const size_t kPipePathMax =  arraysize(kPipeNameFormat) + (3 * 10) + 1;
+
+// To avoid users sending negative message lengths to Send/Receive
+// we clamp message lengths, which are size_t, to no more than INT_MAX.
+const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
+
+const int kOutBufferSize = 4096;
+const int kInBufferSize = 4096;
+const int kDefaultTimeoutMilliSeconds = 1000;
+
+bool CreatePairImpl(HANDLE* socket_a, HANDLE* socket_b, bool overlapped) {
+  DCHECK(socket_a != socket_b);
+  DCHECK(*socket_a == SyncSocket::kInvalidHandle);
+  DCHECK(*socket_b == SyncSocket::kInvalidHandle);
+
+  wchar_t name[kPipePathMax];
+  ScopedHandle handle_a;
+  DWORD flags = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE;
+  if (overlapped)
+    flags |= FILE_FLAG_OVERLAPPED;
+
+  do {
+    unsigned int rnd_name;
+    if (rand_s(&rnd_name) != 0)
+      return false;
+
+    swprintf(name, kPipePathMax,
+             kPipeNameFormat,
+             GetCurrentProcessId(),
+             GetCurrentThreadId(),
+             rnd_name);
+
+    handle_a.Set(CreateNamedPipeW(
+        name,
+        flags,
+        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
+        1,
+        kOutBufferSize,
+        kInBufferSize,
+        kDefaultTimeoutMilliSeconds,
+        NULL));
+  } while (!handle_a.IsValid() &&
+           (GetLastError() == ERROR_PIPE_BUSY));
+
+  if (!handle_a.IsValid()) {
+    NOTREACHED();
+    return false;
+  }
+
+  // The SECURITY_ANONYMOUS flag means that the server side (handle_a) cannot
+  // impersonate the client (handle_b). This allows us not to care which side
+  // ends up in which side of a privilege boundary.
+  flags = SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS;
+  if (overlapped)
+    flags |= FILE_FLAG_OVERLAPPED;
+
+  ScopedHandle handle_b(CreateFileW(name,
+                                    GENERIC_READ | GENERIC_WRITE,
+                                    0,          // no sharing.
+                                    NULL,       // default security attributes.
+                                    OPEN_EXISTING,  // opens existing pipe.
+                                    flags,
+                                    NULL));     // no template file.
+  if (!handle_b.IsValid()) {
+    DPLOG(ERROR) << "CreateFileW failed";
+    return false;
+  }
+
+  if (!ConnectNamedPipe(handle_a, NULL)) {
+    DWORD error = GetLastError();
+    if (error != ERROR_PIPE_CONNECTED) {
+      DPLOG(ERROR) << "ConnectNamedPipe failed";
+      return false;
+    }
+  }
+
+  *socket_a = handle_a.Take();
+  *socket_b = handle_b.Take();
+
+  return true;
+}
+
+// Inline helper to avoid having the cast everywhere.
+DWORD GetNextChunkSize(size_t current_pos, size_t max_size) {
+  // The following statement is for 64 bit portability.
+  return static_cast<DWORD>(((max_size - current_pos) <= UINT_MAX) ?
+      (max_size - current_pos) : UINT_MAX);
+}
+
+// Template function that supports calling ReadFile or WriteFile in an
+// overlapped fashion and waits for IO completion.  The function also waits
+// on an event that can be used to cancel the operation.  If the operation
+// is cancelled, the function returns and closes the relevant socket object.
+template <typename BufferType, typename Function>
+size_t CancelableFileOperation(Function operation, HANDLE file,
+                               BufferType* buffer, size_t length,
+                               base::WaitableEvent* io_event,
+                               base::WaitableEvent* cancel_event,
+                               CancelableSyncSocket* socket,
+                               DWORD timeout_in_ms) {
+  // The buffer must be byte size or the length check won't make much sense.
+  COMPILE_ASSERT(sizeof(buffer[0]) == sizeof(char), incorrect_buffer_type);
+  DCHECK_LE(length, kMaxMessageLength);
+
+  OVERLAPPED ol = {0};
+  ol.hEvent = io_event->handle();
+  size_t count = 0;
+  while (count < length) {
+    DWORD chunk = GetNextChunkSize(count, length);
+    // This is either the ReadFile or WriteFile call depending on whether
+    // we're receiving or sending data.
+    DWORD len = 0;
+    BOOL ok = operation(file, static_cast<BufferType*>(buffer) + count, chunk,
+                        &len, &ol);
+    if (!ok) {
+      if (::GetLastError() == ERROR_IO_PENDING) {
+        HANDLE events[] = { io_event->handle(), cancel_event->handle() };
+        int wait_result = WaitForMultipleObjects(
+            arraysize(events), events, FALSE, timeout_in_ms);
+        if (wait_result == (WAIT_OBJECT_0 + 0)) {
+          GetOverlappedResult(file, &ol, &len, TRUE);
+        } else if (wait_result == (WAIT_OBJECT_0 + 1)) {
+          VLOG(1) << "Shutdown was signaled. Closing socket.";
+          CancelIo(file);
+          socket->Close();
+          count = 0;
+          break;
+        } else {
+          // Timeout happened.
+          DCHECK_EQ(WAIT_TIMEOUT, wait_result);
+          if (!CancelIo(file)){
+            DLOG(WARNING) << "CancelIo() failed";
+          }
+          break;
+        }
+      } else {
+        break;
+      }
+    }
+
+    count += len;
+
+    // Quit the operation if we can't write/read anymore.
+    if (len != chunk)
+      break;
+  }
+
+  return (count > 0) ? count : 0;
+}
+
+}  // namespace
+
+const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE;
+
+SyncSocket::SyncSocket() : handle_(kInvalidHandle) {}
+
+SyncSocket::~SyncSocket() {
+  Close();
+}
+
+// static
+bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
+  return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, false);
+}
+
+bool SyncSocket::Close() {
+  if (handle_ == kInvalidHandle)
+    return false;
+
+  BOOL retval = CloseHandle(handle_);
+  handle_ = kInvalidHandle;
+  return retval ? true : false;
+}
+
+size_t SyncSocket::Send(const void* buffer, size_t length) {
+  DCHECK_LE(length, kMaxMessageLength);
+  size_t count = 0;
+  while (count < length) {
+    DWORD len;
+    DWORD chunk = GetNextChunkSize(count, length);
+    if (WriteFile(handle_, static_cast<const char*>(buffer) + count,
+                  chunk, &len, NULL) == FALSE) {
+      return (0 < count) ? count : 0;
+    }
+    count += len;
+  }
+  return count;
+}
+
+size_t SyncSocket::Receive(void* buffer, size_t length) {
+  DCHECK_LE(length, kMaxMessageLength);
+  size_t count = 0;
+  while (count < length) {
+    DWORD len;
+    DWORD chunk = GetNextChunkSize(count, length);
+    if (ReadFile(handle_, static_cast<char*>(buffer) + count,
+                 chunk, &len, NULL) == FALSE) {
+      return (0 < count) ? count : 0;
+    }
+    count += len;
+  }
+  return count;
+}
+
+size_t SyncSocket::Peek() {
+  DWORD available = 0;
+  PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL);
+  return available;
+}
+
+CancelableSyncSocket::CancelableSyncSocket()
+    : shutdown_event_(true, false), file_operation_(true, false) {
+}
+
+CancelableSyncSocket::CancelableSyncSocket(Handle handle)
+    : SyncSocket(handle), shutdown_event_(true, false),
+      file_operation_(true, false) {
+}
+
+bool CancelableSyncSocket::Shutdown() {
+  // This doesn't shut down the pipe immediately, but subsequent Receive or Send
+  // methods will fail straight away.
+  shutdown_event_.Signal();
+  return true;
+}
+
+bool CancelableSyncSocket::Close() {
+  bool ret = SyncSocket::Close();
+  shutdown_event_.Reset();
+  return ret;
+}
+
+size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
+  static const DWORD kWaitTimeOutInMs = 500;
+  return CancelableFileOperation(
+      &WriteFile, handle_, reinterpret_cast<const char*>(buffer),
+      length, &file_operation_, &shutdown_event_, this, kWaitTimeOutInMs);
+}
+
+size_t CancelableSyncSocket::Receive(void* buffer, size_t length) {
+  return CancelableFileOperation(&ReadFile, handle_,
+      reinterpret_cast<char*>(buffer), length, &file_operation_,
+      &shutdown_event_, this, INFINITE);
+}
+
+// static
+bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
+                                      CancelableSyncSocket* socket_b) {
+  return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, true);
+}
+
+
+}  // namespace base
diff --git a/base/synchronization/cancellation_flag.cc b/base/synchronization/cancellation_flag.cc
new file mode 100644
index 0000000..ad3b551
--- /dev/null
+++ b/base/synchronization/cancellation_flag.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/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;
+}
+
+}  // namespace base
diff --git a/base/synchronization/cancellation_flag.h b/base/synchronization/cancellation_flag.h
new file mode 100644
index 0000000..51a4def
--- /dev/null
+++ b/base/synchronization/cancellation_flag.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_SYNCHRONIZATION_CANCELLATION_FLAG_H_
+#define BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
+
+#include "base/base_export.h"
+#include "base/atomicops.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// CancellationFlag allows one thread to cancel jobs executed on some worker
+// thread. Calling Set() from one thread and IsSet() from a number of threads
+// is thread-safe.
+//
+// This class IS NOT intended for synchronization between threads.
+class BASE_EXPORT CancellationFlag {
+ public:
+  CancellationFlag() : flag_(false) {
+#if !defined(NDEBUG)
+    set_on_ = PlatformThread::CurrentId();
+#endif
+  }
+  ~CancellationFlag() {}
+
+  // Set the flag. May only be called on the thread which owns the object.
+  void Set();
+  bool IsSet() const;  // Returns true iff the flag was set.
+
+ private:
+  base::subtle::Atomic32 flag_;
+#if !defined(NDEBUG)
+  PlatformThreadId set_on_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(CancellationFlag);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
diff --git a/base/synchronization/cancellation_flag_unittest.cc b/base/synchronization/cancellation_flag_unittest.cc
new file mode 100644
index 0000000..02a31b5
--- /dev/null
+++ b/base/synchronization/cancellation_flag_unittest.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.
+
+// Tests of CancellationFlag class.
+
+#include "base/synchronization/cancellation_flag.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/synchronization/spin_wait.h"
+#include "base/time.h"
+#include "base/threading/thread.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.message_loop()->PostTask(FROM_HERE, base::Bind(&CancelHelper, &flag));
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/synchronization/condition_variable.h b/base/synchronization/condition_variable.h
new file mode 100644
index 0000000..4f744f8
--- /dev/null
+++ b/base/synchronization/condition_variable.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ConditionVariable wraps pthreads condition variable synchronization or, on
+// Windows, simulates it.  This functionality is very helpful for having
+// several threads wait for an event, as is common with a thread pool managed
+// by a master.  The meaning of such an event in the (worker) thread pool
+// scenario is that additional tasks are now available for processing.  It is
+// used in Chrome in the DNS prefetching system to notify worker threads that
+// a queue now has items (tasks) which need to be tended to.  A related use
+// would have a pool manager waiting on a ConditionVariable, waiting for a
+// thread in the pool to announce (signal) that there is now more room in a
+// (bounded size) communications queue for the manager to deposit tasks, or,
+// as a second example, that the queue of tasks is completely empty and all
+// workers are waiting.
+//
+// USAGE NOTE 1: spurious signal events are possible with this and
+// most implementations of condition variables.  As a result, be
+// *sure* to retest your condition before proceeding.  The following
+// is a good example of doing this correctly:
+//
+// while (!work_to_be_done()) Wait(...);
+//
+// In contrast do NOT do the following:
+//
+// if (!work_to_be_done()) Wait(...);  // Don't do this.
+//
+// Especially avoid the above if you are relying on some other thread only
+// issuing a signal up *if* there is work-to-do.  There can/will
+// be spurious signals.  Recheck state on waiting thread before
+// assuming the signal was intentional. Caveat caller ;-).
+//
+// USAGE NOTE 2: Broadcast() frees up all waiting threads at once,
+// which leads to contention for the locks they all held when they
+// called Wait().  This results in POOR performance.  A much better
+// approach to getting a lot of threads out of Wait() is to have each
+// thread (upon exiting Wait()) call Signal() to free up another
+// Wait'ing thread.  Look at condition_variable_unittest.cc for
+// both examples.
+//
+// Broadcast() can be used nicely during teardown, as it gets the job
+// done, and leaves no sleeping threads... and performance is less
+// critical at that point.
+//
+// The semantics of Broadcast() are carefully crafted so that *all*
+// threads that were waiting when the request was made will indeed
+// get signaled.  Some implementations mess up, and don't signal them
+// all, while others allow the wait to be effectively turned off (for
+// a while while waiting threads come around).  This implementation
+// appears correct, as it will not "lose" any signals, and will guarantee
+// that all threads get signaled by Broadcast().
+//
+// This implementation offers support for "performance" in its selection of
+// which thread to revive.  Performance, in direct contrast with "fairness,"
+// assures that the thread that most recently began to Wait() is selected by
+// Signal to revive.  Fairness would (if publicly supported) assure that the
+// thread that has Wait()ed the longest is selected. The default policy
+// may improve performance, as the selected thread may have a greater chance of
+// having some of its stack data in various CPU caches.
+//
+// For a discussion of the many very subtle implementation details, see the FAQ
+// at the end of condition_variable_win.cc.
+
+#ifndef BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
+#define BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+class ConditionVarImpl;
+class TimeDelta;
+
+class BASE_EXPORT ConditionVariable {
+ public:
+  // Construct a cv for use with ONLY one user lock.
+  explicit ConditionVariable(Lock* user_lock);
+
+  ~ConditionVariable();
+
+  // Wait() releases the caller's critical section atomically as it starts to
+  // sleep, and the reacquires it when it is signaled.
+  void Wait();
+  void TimedWait(const TimeDelta& max_time);
+
+  // Broadcast() revives all waiting threads.
+  void Broadcast();
+  // Signal() revives one waiting thread.
+  void Signal();
+
+ private:
+
+#if defined(OS_WIN)
+  ConditionVarImpl* impl_;
+#elif defined(OS_POSIX)
+  pthread_cond_t condition_;
+  pthread_mutex_t* user_mutex_;
+#if !defined(NDEBUG)
+  base::Lock* user_lock_;     // Needed to adjust shadow lock state on wait.
+#endif
+
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
diff --git a/base/synchronization/condition_variable_posix.cc b/base/synchronization/condition_variable_posix.cc
new file mode 100644
index 0000000..25edf16
--- /dev/null
+++ b/base/synchronization/condition_variable_posix.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/condition_variable.h"
+
+#include <errno.h>
+#include <sys/time.h>
+
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time.h"
+
+namespace base {
+
+ConditionVariable::ConditionVariable(Lock* user_lock)
+    : user_mutex_(user_lock->lock_.os_lock())
+#if !defined(NDEBUG)
+    , user_lock_(user_lock)
+#endif
+{
+  int rv = pthread_cond_init(&condition_, NULL);
+  DCHECK_EQ(0, rv);
+}
+
+ConditionVariable::~ConditionVariable() {
+  int rv = pthread_cond_destroy(&condition_);
+  DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Wait() {
+  base::ThreadRestrictions::AssertWaitAllowed();
+#if !defined(NDEBUG)
+  user_lock_->CheckHeldAndUnmark();
+#endif
+  int rv = pthread_cond_wait(&condition_, user_mutex_);
+  DCHECK_EQ(0, rv);
+#if !defined(NDEBUG)
+  user_lock_->CheckUnheldAndMark();
+#endif
+}
+
+void ConditionVariable::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  int64 usecs = max_time.InMicroseconds();
+
+  // The timeout argument to pthread_cond_timedwait is in absolute time.
+  struct timeval now;
+  gettimeofday(&now, NULL);
+
+  struct timespec abstime;
+  abstime.tv_sec = now.tv_sec + (usecs / Time::kMicrosecondsPerSecond);
+  abstime.tv_nsec = (now.tv_usec + (usecs % Time::kMicrosecondsPerSecond)) *
+                    Time::kNanosecondsPerMicrosecond;
+  abstime.tv_sec += abstime.tv_nsec / Time::kNanosecondsPerSecond;
+  abstime.tv_nsec %= Time::kNanosecondsPerSecond;
+  DCHECK_GE(abstime.tv_sec, now.tv_sec);  // Overflow paranoia
+
+#if !defined(NDEBUG)
+  user_lock_->CheckHeldAndUnmark();
+#endif
+  int rv = pthread_cond_timedwait(&condition_, user_mutex_, &abstime);
+  DCHECK(rv == 0 || rv == ETIMEDOUT);
+#if !defined(NDEBUG)
+  user_lock_->CheckUnheldAndMark();
+#endif
+}
+
+void ConditionVariable::Broadcast() {
+  int rv = pthread_cond_broadcast(&condition_);
+  DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Signal() {
+  int rv = pthread_cond_signal(&condition_);
+  DCHECK_EQ(0, rv);
+}
+
+}  // namespace base
diff --git a/base/synchronization/condition_variable_unittest.cc b/base/synchronization/condition_variable_unittest.cc
new file mode 100644
index 0000000..4162d4f
--- /dev/null
+++ b/base/synchronization/condition_variable_unittest.cc
@@ -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.
+
+// Multi-threaded tests of ConditionVariable class.
+
+#include <time.h>
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/spin_wait.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_collision_warner.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+namespace {
+//------------------------------------------------------------------------------
+// Define our test class, with several common variables.
+//------------------------------------------------------------------------------
+
+class ConditionVariableTest : public PlatformTest {
+ public:
+  const TimeDelta kZeroMs;
+  const TimeDelta kTenMs;
+  const TimeDelta kThirtyMs;
+  const TimeDelta kFortyFiveMs;
+  const TimeDelta kSixtyMs;
+  const TimeDelta kOneHundredMs;
+
+  explicit 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);
+  virtual ~WorkQueue();
+
+  // PlatformThread::Delegate interface.
+  virtual 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;
+  TimeDelta GetWorkTime() const;
+
+  void SetWorkTime(TimeDelta delay);
+  void SetTaskCount(int count);
+  void SetAllowHelp(bool allow);
+
+  // The following must be called without locking, and will spin wait until the
+  // threads are all in a wait state.
+  void SpinUntilAllThreadsAreWaiting();
+  void SpinUntilTaskCountLessThan(int task_count);
+
+  // Caller must acquire lock before calling.
+  void SetShutdown();
+
+  // Compares the |shutdown_task_count_| to the |thread_count| and returns true
+  // if they are equal.  This check will acquire the |lock_| so the caller
+  // should not hold the lock when calling this method.
+  bool ThreadSafeCheckShutdown(int thread_count);
+
+ private:
+  // Both worker threads and controller use the following to synchronize.
+  Lock lock_;
+  ConditionVariable work_is_available_;  // To tell threads there is work.
+
+  // Conditions to notify the controlling process (if it is interested).
+  ConditionVariable all_threads_have_ids_;  // All threads are running.
+  ConditionVariable no_more_tasks_;  // Task count is zero.
+
+  const int thread_count_;
+  int waiting_thread_count_;
+  scoped_array<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();
+}
+
+
+// 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;
+}
+
+TimeDelta WorkQueue::GetWorkTime() const {
+  return worker_delay_;
+}
+
+void WorkQueue::SetWorkTime(TimeDelta delay) {
+  worker_delay_ = delay;
+}
+
+void WorkQueue::SetTaskCount(int count) {
+  task_count_ = count;
+}
+
+void WorkQueue::SetAllowHelp(bool allow) {
+  allow_help_requests_ = allow;
+}
+
+void WorkQueue::SetShutdown() {
+  lock_.AssertAcquired();
+  shutdown_ = true;
+}
+
+void WorkQueue::SpinUntilAllThreadsAreWaiting() {
+  while (true) {
+    {
+      base::AutoLock auto_lock(lock_);
+      if (waiting_thread_count_ == thread_count_)
+        break;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(30));
+  }
+}
+
+void WorkQueue::SpinUntilTaskCountLessThan(int task_count) {
+  while (true) {
+    {
+      base::AutoLock auto_lock(lock_);
+      if (task_count_ < task_count)
+        break;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(30));
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Define the standard worker task. Several tests will spin out many of these
+// threads.
+//------------------------------------------------------------------------------
+
+// The multithread tests involve several threads with a task to perform as
+// directed by an instance of the class WorkQueue.
+// The task is to:
+// a) Check to see if there are more tasks (there is a task counter).
+//    a1) Wait on condition variable if there are no tasks currently.
+// b) Call a function to see what should be done.
+// c) Do some computation based on the number of milliseconds returned in (b).
+// d) go back to (a).
+
+// WorkQueue::ThreadMain() implements the above task for all threads.
+// It calls the controlling object to tell the creator about progress, and to
+// ask about tasks.
+
+void WorkQueue::ThreadMain() {
+  int thread_id;
+  {
+    base::AutoLock auto_lock(lock_);
+    thread_id = GetThreadId();
+    if (EveryIdWasAllocated())
+      all_threads_have_ids()->Signal();  // Tell creator we're ready.
+  }
+
+  Lock private_lock;  // Used to waste time on "our work".
+  while (1) {  // This is the main consumer loop.
+    TimeDelta work_time;
+    bool could_use_help;
+    {
+      base::AutoLock auto_lock(lock_);
+      while (0 == task_count() && !shutdown()) {
+        ++waiting_thread_count_;
+        work_is_available()->Wait();
+        --waiting_thread_count_;
+      }
+      if (shutdown()) {
+        // Ack the notification of a shutdown message back to the controller.
+        thread_shutting_down();
+        return;  // Terminate.
+      }
+      // Get our task duration from the queue.
+      work_time = GetAnAssignment(thread_id);
+      could_use_help = (task_count() > 0) && allow_help_requests();
+    }  // Release lock
+
+    // Do work (outside of locked region.
+    if (could_use_help)
+      work_is_available()->Signal();  // Get help from other threads.
+
+    if (work_time > TimeDelta::FromMilliseconds(0)) {
+      // We could just sleep(), but we'll instead further exercise the
+      // condition variable class, and do a timed wait.
+      base::AutoLock auto_lock(private_lock);
+      ConditionVariable private_cv(&private_lock);
+      private_cv.TimedWait(work_time);  // Unsynchronized waiting.
+    }
+
+    {
+      base::AutoLock auto_lock(lock_);
+      // Send notification that we completed our "work."
+      WorkIsCompleted(thread_id);
+    }
+  }
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/synchronization/condition_variable_win.cc b/base/synchronization/condition_variable_win.cc
new file mode 100644
index 0000000..f32778f
--- /dev/null
+++ b/base/synchronization/condition_variable_win.cc
@@ -0,0 +1,669 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/condition_variable.h"
+
+#include <windows.h>
+#include <stack>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time.h"
+
+namespace {
+// We can't use the linker supported delay-load for kernel32 so all this
+// cruft here is to manually late-bind the needed functions.
+typedef void (WINAPI *InitializeConditionVariableFn)(PCONDITION_VARIABLE);
+typedef BOOL (WINAPI *SleepConditionVariableCSFn)(PCONDITION_VARIABLE,
+                                                  PCRITICAL_SECTION, DWORD);
+typedef void (WINAPI *WakeConditionVariableFn)(PCONDITION_VARIABLE);
+typedef void (WINAPI *WakeAllConditionVariableFn)(PCONDITION_VARIABLE);
+
+InitializeConditionVariableFn initialize_condition_variable_fn;
+SleepConditionVariableCSFn sleep_condition_variable_fn;
+WakeConditionVariableFn wake_condition_variable_fn;
+WakeAllConditionVariableFn wake_all_condition_variable_fn;
+
+bool BindVistaCondVarFunctions() {
+  HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
+  initialize_condition_variable_fn =
+      reinterpret_cast<InitializeConditionVariableFn>(
+          GetProcAddress(kernel32, "InitializeConditionVariable"));
+  if (!initialize_condition_variable_fn)
+    return false;
+  sleep_condition_variable_fn =
+      reinterpret_cast<SleepConditionVariableCSFn>(
+          GetProcAddress(kernel32, "SleepConditionVariableCS"));
+  if (!sleep_condition_variable_fn)
+    return false;
+  wake_condition_variable_fn =
+      reinterpret_cast<WakeConditionVariableFn>(
+          GetProcAddress(kernel32, "WakeConditionVariable"));
+  if (!wake_condition_variable_fn)
+    return false;
+  wake_all_condition_variable_fn =
+      reinterpret_cast<WakeAllConditionVariableFn>(
+          GetProcAddress(kernel32, "WakeAllConditionVariable"));
+  if (!wake_all_condition_variable_fn)
+    return false;
+  return true;
+}
+
+}  // namespace.
+
+namespace base {
+// Abstract base class of the pimpl idiom.
+class ConditionVarImpl {
+ public:
+  virtual ~ConditionVarImpl() {};
+  virtual void Wait() = 0;
+  virtual void TimedWait(const TimeDelta& max_time) = 0;
+  virtual void Broadcast() = 0;
+  virtual void Signal() = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Windows Vista and Win7 implementation.
+///////////////////////////////////////////////////////////////////////////////
+
+class WinVistaCondVar: public ConditionVarImpl {
+ public:
+  WinVistaCondVar(Lock* user_lock);
+  ~WinVistaCondVar() {};
+  // Overridden from ConditionVarImpl.
+  virtual void Wait() OVERRIDE;
+  virtual void TimedWait(const TimeDelta& max_time) OVERRIDE;
+  virtual void Broadcast() OVERRIDE;
+  virtual void Signal() OVERRIDE;
+
+ private:
+  base::Lock& user_lock_;
+  CONDITION_VARIABLE cv_;
+};
+
+WinVistaCondVar::WinVistaCondVar(Lock* user_lock)
+    : user_lock_(*user_lock) {
+  initialize_condition_variable_fn(&cv_);
+  DCHECK(user_lock);
+}
+
+void WinVistaCondVar::Wait() {
+  TimedWait(TimeDelta::FromMilliseconds(INFINITE));
+}
+
+void WinVistaCondVar::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds());
+  CRITICAL_SECTION* cs = user_lock_.lock_.os_lock();
+
+#if !defined(NDEBUG)
+  user_lock_.CheckHeldAndUnmark();
+#endif
+
+  if (FALSE == sleep_condition_variable_fn(&cv_, cs, timeout)) {
+    DCHECK(GetLastError() != WAIT_TIMEOUT);
+  }
+
+#if !defined(NDEBUG)
+  user_lock_.CheckUnheldAndMark();
+#endif
+}
+
+void WinVistaCondVar::Broadcast() {
+  wake_all_condition_variable_fn(&cv_);
+}
+
+void WinVistaCondVar::Signal() {
+  wake_condition_variable_fn(&cv_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Windows XP implementation.
+///////////////////////////////////////////////////////////////////////////////
+
+class WinXPCondVar : public ConditionVarImpl {
+ public:
+  WinXPCondVar(Lock* user_lock);
+  ~WinXPCondVar();
+  // Overridden from ConditionVarImpl.
+  virtual void Wait() OVERRIDE;
+  virtual void TimedWait(const TimeDelta& max_time) OVERRIDE;
+  virtual void Broadcast() OVERRIDE;
+  virtual void Signal() OVERRIDE;
+
+  // Define Event class that is used to form circularly linked lists.
+  // The list container is an element with NULL as its handle_ value.
+  // The actual list elements have a non-zero handle_ value.
+  // All calls to methods MUST be done under protection of a lock so that links
+  // can be validated.  Without the lock, some links might asynchronously
+  // change, and the assertions would fail (as would list change operations).
+  class Event {
+   public:
+    // Default constructor with no arguments creates a list container.
+    Event();
+    ~Event();
+
+    // InitListElement transitions an instance from a container, to an element.
+    void InitListElement();
+
+    // Methods for use on lists.
+    bool IsEmpty() const;
+    void PushBack(Event* other);
+    Event* PopFront();
+    Event* PopBack();
+
+    // Methods for use on list elements.
+    // Accessor method.
+    HANDLE handle() const;
+    // Pull an element from a list (if it's in one).
+    Event* Extract();
+
+    // Method for use on a list element or on a list.
+    bool IsSingleton() const;
+
+   private:
+    // Provide pre/post conditions to validate correct manipulations.
+    bool ValidateAsDistinct(Event* other) const;
+    bool ValidateAsItem() const;
+    bool ValidateAsList() const;
+    bool ValidateLinks() const;
+
+    HANDLE handle_;
+    Event* next_;
+    Event* prev_;
+    DISALLOW_COPY_AND_ASSIGN(Event);
+  };
+
+  // Note that RUNNING is an unlikely number to have in RAM by accident.
+  // This helps with defensive destructor coding in the face of user error.
+  enum RunState { SHUTDOWN = 0, RUNNING = 64213 };
+
+  // Internal implementation methods supporting Wait().
+  Event* GetEventForWaiting();
+  void RecycleEvent(Event* used_event);
+
+  RunState run_state_;
+
+  // Private critical section for access to member data.
+  base::Lock internal_lock_;
+
+  // Lock that is acquired before calling Wait().
+  base::Lock& user_lock_;
+
+  // Events that threads are blocked on.
+  Event waiting_list_;
+
+  // Free list for old events.
+  Event recycling_list_;
+  int recycling_list_size_;
+
+  // The number of allocated, but not yet deleted events.
+  int allocation_counter_;
+};
+
+WinXPCondVar::WinXPCondVar(Lock* user_lock)
+    : user_lock_(*user_lock),
+      run_state_(RUNNING),
+      allocation_counter_(0),
+      recycling_list_size_(0) {
+  DCHECK(user_lock);
+}
+
+WinXPCondVar::~WinXPCondVar() {
+  AutoLock auto_lock(internal_lock_);
+  run_state_ = SHUTDOWN;  // Prevent any more waiting.
+
+  DCHECK_EQ(recycling_list_size_, allocation_counter_);
+  if (recycling_list_size_ != allocation_counter_) {  // Rare shutdown problem.
+    // There are threads of execution still in this->TimedWait() and yet the
+    // caller has instigated the destruction of this instance :-/.
+    // A common reason for such "overly hasty" destruction is that the caller
+    // was not willing to wait for all the threads to terminate.  Such hasty
+    // actions are a violation of our usage contract, but we'll give the
+    // waiting thread(s) one last chance to exit gracefully (prior to our
+    // destruction).
+    // Note: waiting_list_ *might* be empty, but recycling is still pending.
+    AutoUnlock auto_unlock(internal_lock_);
+    Broadcast();  // Make sure all waiting threads have been signaled.
+    Sleep(10);  // Give threads a chance to grab internal_lock_.
+    // All contained threads should be blocked on user_lock_ by now :-).
+  }  // Reacquire internal_lock_.
+
+  DCHECK_EQ(recycling_list_size_, allocation_counter_);
+}
+
+void WinXPCondVar::Wait() {
+  // Default to "wait forever" timing, which means have to get a Signal()
+  // or Broadcast() to come out of this wait state.
+  TimedWait(TimeDelta::FromMilliseconds(INFINITE));
+}
+
+void WinXPCondVar::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  Event* waiting_event;
+  HANDLE handle;
+  {
+    AutoLock auto_lock(internal_lock_);
+    if (RUNNING != run_state_) return;  // Destruction in progress.
+    waiting_event = GetEventForWaiting();
+    handle = waiting_event->handle();
+    DCHECK(handle);
+  }  // Release internal_lock.
+
+  {
+    AutoUnlock unlock(user_lock_);  // Release caller's lock
+    WaitForSingleObject(handle, static_cast<DWORD>(max_time.InMilliseconds()));
+    // Minimize spurious signal creation window by recycling asap.
+    AutoLock auto_lock(internal_lock_);
+    RecycleEvent(waiting_event);
+    // Release internal_lock_
+  }  // Reacquire callers lock to depth at entry.
+}
+
+// Broadcast() is guaranteed to signal all threads that were waiting (i.e., had
+// a cv_event internally allocated for them) before Broadcast() was called.
+void WinXPCondVar::Broadcast() {
+  std::stack<HANDLE> handles;  // See FAQ-question-10.
+  {
+    AutoLock auto_lock(internal_lock_);
+    if (waiting_list_.IsEmpty())
+      return;
+    while (!waiting_list_.IsEmpty())
+      // This is not a leak from waiting_list_.  See FAQ-question 12.
+      handles.push(waiting_list_.PopBack()->handle());
+  }  // Release internal_lock_.
+  while (!handles.empty()) {
+    SetEvent(handles.top());
+    handles.pop();
+  }
+}
+
+// Signal() will select one of the waiting threads, and signal it (signal its
+// cv_event).  For better performance we signal the thread that went to sleep
+// most recently (LIFO).  If we want fairness, then we wake the thread that has
+// been sleeping the longest (FIFO).
+void WinXPCondVar::Signal() {
+  HANDLE handle;
+  {
+    AutoLock auto_lock(internal_lock_);
+    if (waiting_list_.IsEmpty())
+      return;  // No one to signal.
+    // Only performance option should be used.
+    // This is not a leak from waiting_list.  See FAQ-question 12.
+     handle = waiting_list_.PopBack()->handle();  // LIFO.
+  }  // Release internal_lock_.
+  SetEvent(handle);
+}
+
+// GetEventForWaiting() provides a unique cv_event for any caller that needs to
+// wait.  This means that (worst case) we may over time create as many cv_event
+// objects as there are threads simultaneously using this instance's Wait()
+// functionality.
+WinXPCondVar::Event* WinXPCondVar::GetEventForWaiting() {
+  // We hold internal_lock, courtesy of Wait().
+  Event* cv_event;
+  if (0 == recycling_list_size_) {
+    DCHECK(recycling_list_.IsEmpty());
+    cv_event = new Event();
+    cv_event->InitListElement();
+    allocation_counter_++;
+    DCHECK(cv_event->handle());
+  } else {
+    cv_event = recycling_list_.PopFront();
+    recycling_list_size_--;
+  }
+  waiting_list_.PushBack(cv_event);
+  return cv_event;
+}
+
+// RecycleEvent() takes a cv_event that was previously used for Wait()ing, and
+// recycles it for use in future Wait() calls for this or other threads.
+// Note that there is a tiny chance that the cv_event is still signaled when we
+// obtain it, and that can cause spurious signals (if/when we re-use the
+// cv_event), but such is quite rare (see FAQ-question-5).
+void WinXPCondVar::RecycleEvent(Event* used_event) {
+  // We hold internal_lock, courtesy of Wait().
+  // If the cv_event timed out, then it is necessary to remove it from
+  // waiting_list_.  If it was selected by Broadcast() or Signal(), then it is
+  // already gone.
+  used_event->Extract();  // Possibly redundant
+  recycling_list_.PushBack(used_event);
+  recycling_list_size_++;
+}
+//------------------------------------------------------------------------------
+// The next section provides the implementation for the private Event class.
+//------------------------------------------------------------------------------
+
+// Event provides a doubly-linked-list of events for use exclusively by the
+// ConditionVariable class.
+
+// This custom container was crafted because no simple combination of STL
+// classes appeared to support the functionality required.  The specific
+// unusual requirement for a linked-list-class is support for the Extract()
+// method, which can remove an element from a list, potentially for insertion
+// into a second list.  Most critically, the Extract() method is idempotent,
+// turning the indicated element into an extracted singleton whether it was
+// contained in a list or not.  This functionality allows one (or more) of
+// threads to do the extraction.  The iterator that identifies this extractable
+// element (in this case, a pointer to the list element) can be used after
+// arbitrary manipulation of the (possibly) enclosing list container.  In
+// general, STL containers do not provide iterators that can be used across
+// modifications (insertions/extractions) of the enclosing containers, and
+// certainly don't provide iterators that can be used if the identified
+// element is *deleted* (removed) from the container.
+
+// It is possible to use multiple redundant containers, such as an STL list,
+// and an STL map, to achieve similar container semantics.  This container has
+// only O(1) methods, while the corresponding (multiple) STL container approach
+// would have more complex O(log(N)) methods (yeah... N isn't that large).
+// Multiple containers also makes correctness more difficult to assert, as
+// data is redundantly stored and maintained, which is generally evil.
+
+WinXPCondVar::Event::Event() : handle_(0) {
+  next_ = prev_ = this;  // Self referencing circular.
+}
+
+WinXPCondVar::Event::~Event() {
+  if (0 == handle_) {
+    // This is the list holder
+    while (!IsEmpty()) {
+      Event* cv_event = PopFront();
+      DCHECK(cv_event->ValidateAsItem());
+      delete cv_event;
+    }
+  }
+  DCHECK(IsSingleton());
+  if (0 != handle_) {
+    int ret_val = CloseHandle(handle_);
+    DCHECK(ret_val);
+  }
+}
+
+// Change a container instance permanently into an element of a list.
+void WinXPCondVar::Event::InitListElement() {
+  DCHECK(!handle_);
+  handle_ = CreateEvent(NULL, false, false, NULL);
+  DCHECK(handle_);
+}
+
+// Methods for use on lists.
+bool WinXPCondVar::Event::IsEmpty() const {
+  DCHECK(ValidateAsList());
+  return IsSingleton();
+}
+
+void WinXPCondVar::Event::PushBack(Event* other) {
+  DCHECK(ValidateAsList());
+  DCHECK(other->ValidateAsItem());
+  DCHECK(other->IsSingleton());
+  // Prepare other for insertion.
+  other->prev_ = prev_;
+  other->next_ = this;
+  // Cut into list.
+  prev_->next_ = other;
+  prev_ = other;
+  DCHECK(ValidateAsDistinct(other));
+}
+
+WinXPCondVar::Event* WinXPCondVar::Event::PopFront() {
+  DCHECK(ValidateAsList());
+  DCHECK(!IsSingleton());
+  return next_->Extract();
+}
+
+WinXPCondVar::Event* WinXPCondVar::Event::PopBack() {
+  DCHECK(ValidateAsList());
+  DCHECK(!IsSingleton());
+  return prev_->Extract();
+}
+
+// Methods for use on list elements.
+// Accessor method.
+HANDLE WinXPCondVar::Event::handle() const {
+  DCHECK(ValidateAsItem());
+  return handle_;
+}
+
+// Pull an element from a list (if it's in one).
+WinXPCondVar::Event* WinXPCondVar::Event::Extract() {
+  DCHECK(ValidateAsItem());
+  if (!IsSingleton()) {
+    // Stitch neighbors together.
+    next_->prev_ = prev_;
+    prev_->next_ = next_;
+    // Make extractee into a singleton.
+    prev_ = next_ = this;
+  }
+  DCHECK(IsSingleton());
+  return this;
+}
+
+// Method for use on a list element or on a list.
+bool WinXPCondVar::Event::IsSingleton() const {
+  DCHECK(ValidateLinks());
+  return next_ == this;
+}
+
+// Provide pre/post conditions to validate correct manipulations.
+bool WinXPCondVar::Event::ValidateAsDistinct(Event* other) const {
+  return ValidateLinks() && other->ValidateLinks() && (this != other);
+}
+
+bool WinXPCondVar::Event::ValidateAsItem() const {
+  return (0 != handle_) && ValidateLinks();
+}
+
+bool WinXPCondVar::Event::ValidateAsList() const {
+  return (0 == handle_) && ValidateLinks();
+}
+
+bool WinXPCondVar::Event::ValidateLinks() const {
+  // Make sure both of our neighbors have links that point back to us.
+  // We don't do the O(n) check and traverse the whole loop, and instead only
+  // do a local check to (and returning from) our immediate neighbors.
+  return (next_->prev_ == this) && (prev_->next_ == this);
+}
+
+
+/*
+FAQ On WinXPCondVar subtle implementation details:
+
+1) What makes this problem subtle?  Please take a look at "Strategies
+for Implementing POSIX Condition Variables on Win32" by Douglas
+C. Schmidt and Irfan Pyarali.
+http://www.cs.wustl.edu/~schmidt/win32-cv-1.html It includes
+discussions of numerous flawed strategies for implementing this
+functionality.  I'm not convinced that even the final proposed
+implementation has semantics that are as nice as this implementation
+(especially with regard to Broadcast() and the impact on threads that
+try to Wait() after a Broadcast() has been called, but before all the
+original waiting threads have been signaled).
+
+2) Why can't you use a single wait_event for all threads that call
+Wait()?  See FAQ-question-1, or consider the following: If a single
+event were used, then numerous threads calling Wait() could release
+their cs locks, and be preempted just before calling
+WaitForSingleObject().  If a call to Broadcast() was then presented on
+a second thread, it would be impossible to actually signal all
+waiting(?) threads.  Some number of SetEvent() calls *could* be made,
+but there could be no guarantee that those led to to more than one
+signaled thread (SetEvent()'s may be discarded after the first!), and
+there could be no guarantee that the SetEvent() calls didn't just
+awaken "other" threads that hadn't even started waiting yet (oops).
+Without any limit on the number of requisite SetEvent() calls, the
+system would be forced to do many such calls, allowing many new waits
+to receive spurious signals.
+
+3) How does this implementation cause spurious signal events?  The
+cause in this implementation involves a race between a signal via
+time-out and a signal via Signal() or Broadcast().  The series of
+actions leading to this are:
+
+a) Timer fires, and a waiting thread exits the line of code:
+
+    WaitForSingleObject(waiting_event, max_time.InMilliseconds());
+
+b) That thread (in (a)) is randomly pre-empted after the above line,
+leaving the waiting_event reset (unsignaled) and still in the
+waiting_list_.
+
+c) A call to Signal() (or Broadcast()) on a second thread proceeds, and
+selects the waiting cv_event (identified in step (b)) as the event to revive
+via a call to SetEvent().
+
+d) The Signal() method (step c) calls SetEvent() on waiting_event (step b).
+
+e) The waiting cv_event (step b) is now signaled, but no thread is
+waiting on it.
+
+f) When that waiting_event (step b) is reused, it will immediately
+be signaled (spuriously).
+
+
+4) Why do you recycle events, and cause spurious signals?  First off,
+the spurious events are very rare.  They can only (I think) appear
+when the race described in FAQ-question-3 takes place.  This should be
+very rare.  Most(?)  uses will involve only timer expiration, or only
+Signal/Broadcast() actions.  When both are used, it will be rare that
+the race will appear, and it would require MANY Wait() and signaling
+activities.  If this implementation did not recycle events, then it
+would have to create and destroy events for every call to Wait().
+That allocation/deallocation and associated construction/destruction
+would be costly (per wait), and would only be a rare benefit (when the
+race was "lost" and a spurious signal took place). That would be bad
+(IMO) optimization trade-off.  Finally, such spurious events are
+allowed by the specification of condition variables (such as
+implemented in Vista), and hence it is better if any user accommodates
+such spurious events (see usage note in condition_variable.h).
+
+5) Why don't you reset events when you are about to recycle them, or
+about to reuse them, so that the spurious signals don't take place?
+The thread described in FAQ-question-3 step c may be pre-empted for an
+arbitrary length of time before proceeding to step d.  As a result,
+the wait_event may actually be re-used *before* step (e) is reached.
+As a result, calling reset would not help significantly.
+
+6) How is it that the callers lock is released atomically with the
+entry into a wait state?  We commit to the wait activity when we
+allocate the wait_event for use in a given call to Wait().  This
+allocation takes place before the caller's lock is released (and
+actually before our internal_lock_ is released).  That allocation is
+the defining moment when "the wait state has been entered," as that
+thread *can* now be signaled by a call to Broadcast() or Signal().
+Hence we actually "commit to wait" before releasing the lock, making
+the pair effectively atomic.
+
+8) Why do you need to lock your data structures during waiting, as the
+caller is already in possession of a lock?  We need to Acquire() and
+Release() our internal lock during Signal() and Broadcast().  If we tried
+to use a callers lock for this purpose, we might conflict with their
+external use of the lock.  For example, the caller may use to consistently
+hold a lock on one thread while calling Signal() on another, and that would
+block Signal().
+
+9) Couldn't a more efficient implementation be provided if you
+preclude using more than one external lock in conjunction with a
+single ConditionVariable instance?  Yes, at least it could be viewed
+as a simpler API (since you don't have to reiterate the lock argument
+in each Wait() call).  One of the constructors now takes a specific
+lock as an argument, and a there are corresponding Wait() calls that
+don't specify a lock now.  It turns that the resulting implmentation
+can't be made more efficient, as the internal lock needs to be used by
+Signal() and Broadcast(), to access internal data structures.  As a
+result, I was not able to utilize the user supplied lock (which is
+being used by the user elsewhere presumably) to protect the private
+member access.
+
+9) Since you have a second lock, how can be be sure that there is no
+possible deadlock scenario?  Our internal_lock_ is always the last
+lock acquired, and the first one released, and hence a deadlock (due
+to critical section problems) is impossible as a consequence of our
+lock.
+
+10) When doing a Broadcast(), why did you copy all the events into
+an STL queue, rather than making a linked-loop, and iterating over it?
+The iterating during Broadcast() is done so outside the protection
+of the internal lock. As a result, other threads, such as the thread
+wherein a related event is waiting, could asynchronously manipulate
+the links around a cv_event.  As a result, the link structure cannot
+be used outside a lock.  Broadcast() could iterate over waiting
+events by cycling in-and-out of the protection of the internal_lock,
+but that appears more expensive than copying the list into an STL
+stack.
+
+11) Why did the lock.h file need to be modified so much for this
+change?  Central to a Condition Variable is the atomic release of a
+lock during a Wait().  This places Wait() functionality exactly
+mid-way between the two classes, Lock and Condition Variable.  Given
+that there can be nested Acquire()'s of locks, and Wait() had to
+Release() completely a held lock, it was necessary to augment the Lock
+class with a recursion counter. Even more subtle is the fact that the
+recursion counter (in a Lock) must be protected, as many threads can
+access it asynchronously.  As a positive fallout of this, there are
+now some DCHECKS to be sure no one Release()s a Lock more than they
+Acquire()ed it, and there is ifdef'ed functionality that can detect
+nested locks (legal under windows, but not under Posix).
+
+12) Why is it that the cv_events removed from list in Broadcast() and Signal()
+are not leaked?  How are they recovered??  The cv_events that appear to leak are
+taken from the waiting_list_.  For each element in that list, there is currently
+a thread in or around the WaitForSingleObject() call of Wait(), and those
+threads have references to these otherwise leaked events. They are passed as
+arguments to be recycled just aftre returning from WaitForSingleObject().
+
+13) Why did you use a custom container class (the linked list), when STL has
+perfectly good containers, such as an STL list?  The STL list, as with any
+container, does not guarantee the utility of an iterator across manipulation
+(such as insertions and deletions) of the underlying container.  The custom
+double-linked-list container provided that assurance.  I don't believe any
+combination of STL containers provided the services that were needed at the same
+O(1) efficiency as the custom linked list.  The unusual requirement
+for the container class is that a reference to an item within a container (an
+iterator) needed to be maintained across an arbitrary manipulation of the
+container.  This requirement exposes itself in the Wait() method, where a
+waiting_event must be selected prior to the WaitForSingleObject(), and then it
+must be used as part of recycling to remove the related instance from the
+waiting_list.  A hash table (STL map) could be used, but I was embarrased to
+use a complex and relatively low efficiency container when a doubly linked list
+provided O(1) performance in all required operations.  Since other operations
+to provide performance-and/or-fairness required queue (FIFO) and list (LIFO)
+containers, I would also have needed to use an STL list/queue as well as an STL
+map.  In the end I decided it would be "fun" to just do it right, and I
+put so many assertions (DCHECKs) into the container class that it is trivial to
+code review and validate its correctness.
+
+*/
+
+ConditionVariable::ConditionVariable(Lock* user_lock)
+    : impl_(NULL) {
+  static bool use_vista_native_cv = BindVistaCondVarFunctions();
+  if (use_vista_native_cv)
+    impl_= new WinVistaCondVar(user_lock);
+  else
+    impl_ = new WinXPCondVar(user_lock);
+}
+
+ConditionVariable::~ConditionVariable() {
+  delete impl_;
+}
+
+void ConditionVariable::Wait() {
+  impl_->Wait();
+}
+
+void ConditionVariable::TimedWait(const TimeDelta& max_time) {
+  impl_->TimedWait(max_time);
+}
+
+void ConditionVariable::Broadcast() {
+  impl_->Broadcast();
+}
+
+void ConditionVariable::Signal() {
+  impl_->Signal();
+}
+
+}  // namespace base
diff --git a/base/synchronization/lock.cc b/base/synchronization/lock.cc
new file mode 100644
index 0000000..6445ce8
--- /dev/null
+++ b/base/synchronization/lock.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is used for debugging assertion support.  The Lock class
+// is functionally a wrapper around the LockImpl class, so the only
+// real intelligence in the class is in the debugging logic.
+
+#if !defined(NDEBUG)
+
+#include "base/synchronization/lock.h"
+#include "base/logging.h"
+
+namespace base {
+
+Lock::Lock() : lock_() {
+  owned_by_thread_ = false;
+  owning_thread_id_ = static_cast<PlatformThreadId>(0);
+}
+
+void Lock::AssertAcquired() const {
+  DCHECK(owned_by_thread_);
+  DCHECK_EQ(owning_thread_id_, PlatformThread::CurrentId());
+}
+
+void Lock::CheckHeldAndUnmark() {
+  DCHECK(owned_by_thread_);
+  DCHECK_EQ(owning_thread_id_, PlatformThread::CurrentId());
+  owned_by_thread_ = false;
+  owning_thread_id_ = static_cast<PlatformThreadId>(0);
+}
+
+void Lock::CheckUnheldAndMark() {
+  DCHECK(!owned_by_thread_);
+  owned_by_thread_ = true;
+  owning_thread_id_ = PlatformThread::CurrentId();
+}
+
+}  // namespace base
+
+#endif  // NDEBUG
diff --git a/base/synchronization/lock.h b/base/synchronization/lock.h
new file mode 100644
index 0000000..15de446
--- /dev/null
+++ b/base/synchronization/lock.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.
+
+#ifndef BASE_SYNCHRONIZATION_LOCK_H_
+#define BASE_SYNCHRONIZATION_LOCK_H_
+
+#include "base/base_export.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// A convenient wrapper for an OS specific critical section.  The only real
+// intelligence in this class is in debug mode for the support for the
+// AssertAcquired() method.
+class BASE_EXPORT Lock {
+ public:
+#if defined(NDEBUG)             // Optimized wrapper implementation
+  Lock() : lock_() {}
+  ~Lock() {}
+  void Acquire() { lock_.Lock(); }
+  void Release() { lock_.Unlock(); }
+
+  // If the lock is not held, take it and return true. If the lock is already
+  // held by another thread, immediately return false. This must not be called
+  // by a thread already holding the lock (what happens is undefined and an
+  // assertion may fail).
+  bool Try() { return lock_.Try(); }
+
+  // Null implementation if not debug.
+  void AssertAcquired() const {}
+#else
+  Lock();
+  ~Lock() {}
+
+  // NOTE: Although windows critical sections support recursive locks, we do not
+  // allow this, and we will commonly fire a DCHECK() if a thread attempts to
+  // acquire the lock a second time (while already holding it).
+  void Acquire() {
+    lock_.Lock();
+    CheckUnheldAndMark();
+  }
+  void Release() {
+    CheckHeldAndUnmark();
+    lock_.Unlock();
+  }
+
+  bool Try() {
+    bool rv = lock_.Try();
+    if (rv) {
+      CheckUnheldAndMark();
+    }
+    return rv;
+  }
+
+  void AssertAcquired() const;
+#endif                          // NDEBUG
+
+#if defined(OS_POSIX)
+  // The posix implementation of ConditionVariable needs to be able
+  // to see our lock and tweak our debugging counters, as it releases
+  // and acquires locks inside of pthread_cond_{timed,}wait.
+  friend class ConditionVariable;
+#elif defined(OS_WIN)
+  // The Windows Vista implementation of ConditionVariable needs the
+  // native handle of the critical section.
+  friend class WinVistaCondVar;
+#endif
+
+ private:
+#if !defined(NDEBUG)
+  // 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.
+
+  // Determines validity of owning_thread_id_.  Needed as we don't have
+  // a null owning_thread_id_ value.
+  bool owned_by_thread_;
+  base::PlatformThreadId owning_thread_id_;
+#endif  // NDEBUG
+
+  // 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:
+  explicit AutoLock(Lock& lock) : lock_(lock) {
+    lock_.Acquire();
+  }
+
+  ~AutoLock() {
+    lock_.AssertAcquired();
+    lock_.Release();
+  }
+
+ private:
+  Lock& lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoLock);
+};
+
+// AutoUnlock is a helper that will Release() the |lock| argument in the
+// constructor, and re-Acquire() it in the destructor.
+class AutoUnlock {
+ public:
+  explicit AutoUnlock(Lock& lock) : lock_(lock) {
+    // We require our caller to have the lock.
+    lock_.AssertAcquired();
+    lock_.Release();
+  }
+
+  ~AutoUnlock() {
+    lock_.Acquire();
+  }
+
+ private:
+  Lock& lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoUnlock);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_LOCK_H_
diff --git a/base/synchronization/lock_impl.h b/base/synchronization/lock_impl.h
new file mode 100644
index 0000000..0b04167
--- /dev/null
+++ b/base/synchronization/lock_impl.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace internal {
+
+// This class implements the underlying platform-specific spin-lock mechanism
+// used for the Lock class.  Most users should not use LockImpl directly, but
+// should instead use Lock.
+class BASE_EXPORT LockImpl {
+ public:
+#if defined(OS_WIN)
+  typedef CRITICAL_SECTION OSLockType;
+#elif defined(OS_POSIX)
+  typedef pthread_mutex_t OSLockType;
+#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.
+  OSLockType* os_lock() { return &os_lock_; }
+
+ private:
+  OSLockType os_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(LockImpl);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_LOCK_IMPL_H_
diff --git a/base/synchronization/lock_impl_posix.cc b/base/synchronization/lock_impl_posix.cc
new file mode 100644
index 0000000..f638fcd
--- /dev/null
+++ b/base/synchronization/lock_impl_posix.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/synchronization/lock_impl.h"
+
+#include <errno.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);
+  rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
+  DCHECK_EQ(rv, 0);
+  rv = pthread_mutex_init(&os_lock_, &mta);
+  DCHECK_EQ(rv, 0);
+  rv = pthread_mutexattr_destroy(&mta);
+  DCHECK_EQ(rv, 0);
+#else
+  // In release, go with the default lock attributes.
+  pthread_mutex_init(&os_lock_, NULL);
+#endif
+}
+
+LockImpl::~LockImpl() {
+  int rv = pthread_mutex_destroy(&os_lock_);
+  DCHECK_EQ(rv, 0);
+}
+
+bool LockImpl::Try() {
+  int rv = pthread_mutex_trylock(&os_lock_);
+  DCHECK(rv == 0 || rv == EBUSY);
+  return rv == 0;
+}
+
+void LockImpl::Lock() {
+  int rv = pthread_mutex_lock(&os_lock_);
+  DCHECK_EQ(rv, 0);
+}
+
+void LockImpl::Unlock() {
+  int rv = pthread_mutex_unlock(&os_lock_);
+  DCHECK_EQ(rv, 0);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/synchronization/lock_impl_win.cc b/base/synchronization/lock_impl_win.cc
new file mode 100644
index 0000000..bb8a23d
--- /dev/null
+++ b/base/synchronization/lock_impl_win.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/lock_impl.h"
+
+namespace base {
+namespace internal {
+
+LockImpl::LockImpl() {
+  // The second parameter is the spin count, for short-held locks it avoid the
+  // contending thread from going to sleep which helps performance greatly.
+  ::InitializeCriticalSectionAndSpinCount(&os_lock_, 2000);
+}
+
+LockImpl::~LockImpl() {
+  ::DeleteCriticalSection(&os_lock_);
+}
+
+bool LockImpl::Try() {
+  if (::TryEnterCriticalSection(&os_lock_) != FALSE) {
+    return true;
+  }
+  return false;
+}
+
+void LockImpl::Lock() {
+  ::EnterCriticalSection(&os_lock_);
+}
+
+void LockImpl::Unlock() {
+  ::LeaveCriticalSection(&os_lock_);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/synchronization/lock_unittest.cc b/base/synchronization/lock_unittest.cc
new file mode 100644
index 0000000..a048f85
--- /dev/null
+++ b/base/synchronization/lock_unittest.cc
@@ -0,0 +1,216 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/lock.h"
+
+#include <stdlib.h>
+
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
+
+class BasicLockTestThread : public PlatformThread::Delegate {
+ public:
+  BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
+
+  virtual 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 = kNullThreadHandle;
+
+  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:
+  TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
+
+  virtual 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 = kNullThreadHandle;
+
+    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 = kNullThreadHandle;
+
+    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();
+    }
+  }
+
+  virtual 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 = kNullThreadHandle;
+
+  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 = kNullThreadHandle;
+  PlatformThreadHandle handle2 = kNullThreadHandle;
+  PlatformThreadHandle handle3 = kNullThreadHandle;
+
+  ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
+  ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
+  ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
+
+  MutexLockTestThread::DoStuff(&lock, &value);
+
+  PlatformThread::Join(handle1);
+  PlatformThread::Join(handle2);
+  PlatformThread::Join(handle3);
+
+  EXPECT_EQ(4 * 40, value);
+}
+
+}  // namespace base
diff --git a/base/synchronization/spin_wait.h b/base/synchronization/spin_wait.h
new file mode 100644
index 0000000..ad54ca8
--- /dev/null
+++ b/base/synchronization/spin_wait.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides a macro ONLY for use in testing.
+// DO NOT USE IN PRODUCTION CODE.  There are much better ways to wait.
+
+// This code is very helpful in testing multi-threaded code, without depending
+// on almost any primitives.  This is especially helpful if you are testing
+// those primitive multi-threaded constructs.
+
+// We provide a simple one argument spin wait (for 1 second), and a generic
+// spin wait (for longer periods of time).
+
+#ifndef BASE_SYNCHRONIZATION_SPIN_WAIT_H_
+#define BASE_SYNCHRONIZATION_SPIN_WAIT_H_
+
+#include "base/threading/platform_thread.h"
+#include "base/time.h"
+
+// Provide a macro that will wait no longer than 1 second for an asynchronous
+// change is the value of an expression.
+// A typical use would be:
+//
+//   SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 == f(x));
+//
+// The expression will be evaluated repeatedly until it is true, or until
+// the time (1 second) expires.
+// Since tests generally have a 5 second watch dog timer, this spin loop is
+// typically used to get the padding needed on a given test platform to assure
+// that the test passes, even if load varies, and external events vary.
+
+#define SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(expression) \
+    SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(base::TimeDelta::FromSeconds(1), \
+                                     (expression))
+
+#define SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(delta, expression) do { \
+  base::TimeTicks start = base::TimeTicks::Now(); \
+  const base::TimeDelta kTimeout = delta; \
+    while (!(expression)) { \
+      if (kTimeout < base::TimeTicks::Now() - start) { \
+      EXPECT_LE((base::TimeTicks::Now() - start).InMilliseconds(), \
+                kTimeout.InMilliseconds()) << "Timed out"; \
+        break; \
+      } \
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); \
+    } \
+  } while (0)
+
+#endif  // BASE_SYNCHRONIZATION_SPIN_WAIT_H_
diff --git a/base/synchronization/waitable_event.h b/base/synchronization/waitable_event.h
new file mode 100644
index 0000000..26e2779
--- /dev/null
+++ b/base/synchronization/waitable_event.h
@@ -0,0 +1,182 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <list>
+#include <utility>
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#endif
+
+namespace base {
+
+// This replaces INFINITE from Win32
+static const int kNoTimeout = -1;
+
+class TimeDelta;
+
+// A WaitableEvent can be a useful thread synchronization tool when you want to
+// allow one thread to wait for another thread to finish some work. For
+// non-Windows systems, this can only be used from within a single address
+// space.
+//
+// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
+// protect a simple boolean value.  However, if you find yourself using a
+// WaitableEvent in conjunction with a Lock to wait for a more complex state
+// change (e.g., for an item to be added to a queue), then you should probably
+// be using a ConditionVariable instead of a WaitableEvent.
+//
+// NOTE: On Windows, this class provides a subset of the functionality afforded
+// by a Windows event object.  This is intentional.  If you are writing Windows
+// specific code and you need other features of a Windows event, then you might
+// be better off just using an Windows event directly.
+class BASE_EXPORT WaitableEvent {
+ public:
+  // If manual_reset is true, then to set the event state to non-signaled, a
+  // consumer must call the Reset method.  If this parameter is false, then the
+  // system automatically resets the event state to non-signaled after a single
+  // waiting thread has been released.
+  WaitableEvent(bool manual_reset, bool initially_signaled);
+
+#if defined(OS_WIN)
+  // Create a WaitableEvent from an Event HANDLE which has already been
+  // created. This objects takes ownership of the HANDLE and will close it when
+  // deleted.
+  explicit WaitableEvent(HANDLE event_handle);
+
+  // Releases ownership of the handle from this object.
+  HANDLE Release();
+#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.
+  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.
+  bool TimedWait(const TimeDelta& max_time);
+
+#if defined(OS_WIN)
+  HANDLE handle() const { return handle_; }
+#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.
+  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)
+  HANDLE handle_;
+#else
+  // On Windows, one can close a HANDLE which is currently being waited on. The
+  // MSDN documentation says that the resulting behaviour is 'undefined', but
+  // it doesn't crash. However, if we were to include the following members
+  // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an
+  // event which gets deleted. This mismatch has bitten us several times now,
+  // so we have a kernel of the WaitableEvent, which is reference counted.
+  // WaitableEventWatchers may then take a reference and thus match the Windows
+  // behaviour.
+  struct WaitableEventKernel :
+      public RefCountedThreadSafe<WaitableEventKernel> {
+   public:
+    WaitableEventKernel(bool manual_reset, bool initially_signaled);
+
+    bool Dequeue(Waiter* waiter, void* tag);
+
+    base::Lock lock_;
+    const bool manual_reset_;
+    bool signaled_;
+    std::list<Waiter*> waiters_;
+
+   private:
+    friend class RefCountedThreadSafe<WaitableEventKernel>;
+    ~WaitableEventKernel();
+  };
+
+  typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex;
+
+  // When dealing with arrays of WaitableEvent*, we want to sort by the address
+  // of the WaitableEvent in order to have a globally consistent locking order.
+  // In that case we keep them, in sorted order, in an array of pairs where the
+  // second element is the index of the WaitableEvent in the original,
+  // unsorted, array.
+  static size_t EnqueueMany(WaiterAndIndex* waitables,
+                            size_t count, Waiter* waiter);
+
+  bool SignalAll();
+  bool SignalOne();
+  void Enqueue(Waiter* waiter);
+
+  scoped_refptr<WaitableEventKernel> kernel_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
diff --git a/base/synchronization/waitable_event_posix.cc b/base/synchronization/waitable_event_posix.cc
new file mode 100644
index 0000000..714c111
--- /dev/null
+++ b/base/synchronization/waitable_event_posix.cc
@@ -0,0 +1,407 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+
+// -----------------------------------------------------------------------------
+// A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't
+// support cross-process events (where one process can signal an event which
+// others are waiting on). Because of this, we can avoid having one thread per
+// listener in several cases.
+//
+// The WaitableEvent maintains a list of waiters, protected by a lock. Each
+// waiter is either an async wait, in which case we have a Task and the
+// MessageLoop to run it on, or a blocking wait, in which case we have the
+// condition variable to signal.
+//
+// Waiting involves grabbing the lock and adding oneself to the wait list. Async
+// waits can be canceled, which means grabbing the lock and removing oneself
+// from the list.
+//
+// Waiting on multiple events is handled by adding a single, synchronous wait to
+// the wait-list of many events. An event passes a pointer to itself when
+// firing a waiter and so we can store that pointer to find out which event
+// triggered.
+// -----------------------------------------------------------------------------
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// This is just an abstract base class for waking the two types of waiters
+// -----------------------------------------------------------------------------
+WaitableEvent::WaitableEvent(bool manual_reset, bool initially_signaled)
+    : kernel_(new WaitableEventKernel(manual_reset, initially_signaled)) {
+}
+
+WaitableEvent::~WaitableEvent() {
+}
+
+void WaitableEvent::Reset() {
+  base::AutoLock locked(kernel_->lock_);
+  kernel_->signaled_ = false;
+}
+
+void WaitableEvent::Signal() {
+  base::AutoLock locked(kernel_->lock_);
+
+  if (kernel_->signaled_)
+    return;
+
+  if (kernel_->manual_reset_) {
+    SignalAll();
+    kernel_->signaled_ = true;
+  } else {
+    // In the case of auto reset, if no waiters were woken, we remain
+    // signaled.
+    if (!SignalOne())
+      kernel_->signaled_ = true;
+  }
+}
+
+bool WaitableEvent::IsSignaled() {
+  base::AutoLock locked(kernel_->lock_);
+
+  const bool result = kernel_->signaled_;
+  if (result && !kernel_->manual_reset_)
+    kernel_->signaled_ = false;
+  return result;
+}
+
+// -----------------------------------------------------------------------------
+// Synchronous waits
+
+// -----------------------------------------------------------------------------
+// This is a synchronous waiter. The thread is waiting on the given condition
+// variable and the fired flag in this object.
+// -----------------------------------------------------------------------------
+class SyncWaiter : public WaitableEvent::Waiter {
+ public:
+  SyncWaiter()
+      : fired_(false),
+        signaling_event_(NULL),
+        lock_(),
+        cv_(&lock_) {
+  }
+
+  virtual 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.
+  // ---------------------------------------------------------------------------
+  virtual 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 Time end_time(Time::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 Time current_time(Time::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();
+
+      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 {
+      signaled_index = i;
+    }
+  }
+
+  return signaled_index;
+}
+
+// -----------------------------------------------------------------------------
+// If return value == 0:
+//   The locks of the WaitableEvents have been taken in order and the Waiter has
+//   been enqueued in the wait-list of each. None of the WaitableEvents are
+//   currently signaled
+// else:
+//   None of the WaitableEvent locks are held. The Waiter has not been enqueued
+//   in any of them and the return value is the index of the first WaitableEvent
+//   which was signaled, from the end of the array.
+// -----------------------------------------------------------------------------
+// static
+size_t WaitableEvent::EnqueueMany
+    (std::pair<WaitableEvent*, size_t>* waitables,
+     size_t count, Waiter* waiter) {
+  if (!count)
+    return 0;
+
+  waitables[0].first->kernel_->lock_.Acquire();
+    if (waitables[0].first->kernel_->signaled_) {
+      if (!waitables[0].first->kernel_->manual_reset_)
+        waitables[0].first->kernel_->signaled_ = false;
+      waitables[0].first->kernel_->lock_.Release();
+      return count;
+    }
+
+    const size_t r = EnqueueMany(waitables + 1, count - 1, waiter);
+    if (r) {
+      waitables[0].first->kernel_->lock_.Release();
+    } else {
+      waitables[0].first->Enqueue(waiter);
+    }
+
+    return r;
+}
+
+// -----------------------------------------------------------------------------
+
+
+// -----------------------------------------------------------------------------
+// Private functions...
+
+WaitableEvent::WaitableEventKernel::WaitableEventKernel(bool manual_reset,
+                                                        bool initially_signaled)
+    : manual_reset_(manual_reset),
+      signaled_(initially_signaled) {
+}
+
+WaitableEvent::WaitableEventKernel::~WaitableEventKernel() {
+}
+
+// -----------------------------------------------------------------------------
+// Wake all waiting waiters. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::SignalAll() {
+  bool signaled_at_least_one = false;
+
+  for (std::list<Waiter*>::iterator
+       i = kernel_->waiters_.begin(); i != kernel_->waiters_.end(); ++i) {
+    if ((*i)->Fire(this))
+      signaled_at_least_one = true;
+  }
+
+  kernel_->waiters_.clear();
+  return signaled_at_least_one;
+}
+
+// ---------------------------------------------------------------------------
+// Try to wake a single waiter. Return true if one was woken. Called with lock
+// held.
+// ---------------------------------------------------------------------------
+bool WaitableEvent::SignalOne() {
+  for (;;) {
+    if (kernel_->waiters_.empty())
+      return false;
+
+    const bool r = (*kernel_->waiters_.begin())->Fire(this);
+    kernel_->waiters_.pop_front();
+    if (r)
+      return true;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Add a waiter to the list of those waiting. Called with lock held.
+// -----------------------------------------------------------------------------
+void WaitableEvent::Enqueue(Waiter* waiter) {
+  kernel_->waiters_.push_back(waiter);
+}
+
+// -----------------------------------------------------------------------------
+// Remove a waiter from the list of those waiting. Return true if the waiter was
+// actually removed. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) {
+  for (std::list<Waiter*>::iterator
+       i = waiters_.begin(); i != waiters_.end(); ++i) {
+    if (*i == waiter && (*i)->Compare(tag)) {
+      waiters_.erase(i);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// -----------------------------------------------------------------------------
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_unittest.cc b/base/synchronization/waitable_event_unittest.cc
new file mode 100644
index 0000000..d00adc7
--- /dev/null
+++ b/base/synchronization/waitable_event_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 "base/synchronization/waitable_event.h"
+
+#include "base/compiler_specific.h"
+#include "base/time.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(WaitableEventTest, ManualBasics) {
+  WaitableEvent event(true, false);
+
+  EXPECT_FALSE(event.IsSignaled());
+
+  event.Signal();
+  EXPECT_TRUE(event.IsSignaled());
+  EXPECT_TRUE(event.IsSignaled());
+
+  event.Reset();
+  EXPECT_FALSE(event.IsSignaled());
+  EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+
+  event.Signal();
+  event.Wait();
+  EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+}
+
+TEST(WaitableEventTest, AutoBasics) {
+  WaitableEvent event(false, false);
+
+  EXPECT_FALSE(event.IsSignaled());
+
+  event.Signal();
+  EXPECT_TRUE(event.IsSignaled());
+  EXPECT_FALSE(event.IsSignaled());
+
+  event.Reset();
+  EXPECT_FALSE(event.IsSignaled());
+  EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+
+  event.Signal();
+  event.Wait();
+  EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+
+  event.Signal();
+  EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+}
+
+TEST(WaitableEventTest, WaitManyShortcut) {
+  WaitableEvent* ev[5];
+  for (unsigned i = 0; i < 5; ++i)
+    ev[i] = new WaitableEvent(false, false);
+
+  ev[3]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u);
+
+  ev[3]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u);
+
+  ev[4]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 4u);
+
+  ev[0]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 0u);
+
+  for (unsigned i = 0; i < 5; ++i)
+    delete ev[i];
+}
+
+class WaitableEventSignaler : public PlatformThread::Delegate {
+ public:
+  WaitableEventSignaler(double seconds, WaitableEvent* ev)
+      : seconds_(seconds),
+        ev_(ev) {
+  }
+
+  virtual void ThreadMain() OVERRIDE {
+    PlatformThread::Sleep(TimeDelta::FromSeconds(static_cast<int>(seconds_)));
+    ev_->Signal();
+  }
+
+ private:
+  const double seconds_;
+  WaitableEvent *const ev_;
+};
+
+TEST(WaitableEventTest, WaitMany) {
+  WaitableEvent* ev[5];
+  for (unsigned i = 0; i < 5; ++i)
+    ev[i] = new WaitableEvent(false, false);
+
+  WaitableEventSignaler signaler(0.1, ev[2]);
+  PlatformThreadHandle thread;
+  PlatformThread::Create(0, &signaler, &thread);
+
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 2u);
+
+  PlatformThread::Join(thread);
+
+  for (unsigned i = 0; i < 5; ++i)
+    delete ev[i];
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_watcher.h b/base/synchronization/waitable_event_watcher.h
new file mode 100644
index 0000000..f5c1510
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher.h
@@ -0,0 +1,164 @@
+// Copyright (c) 2012 The Chromium Authors. All 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.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 base::WaitableEventWatcher::Delegate {
+//    public:
+//     void DoStuffWhenSignaled(WaitableEvent *waitable_event) {
+//       watcher_.StartWatching(waitable_event, this);
+//     }
+//     virtual void OnWaitableEventSignaled(WaitableEvent* waitable_event) {
+//       // OK, time to do stuff!
+//     }
+//    private:
+//     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 MessageLoop::DestructionObserver
+#endif
+{
+ public:
+
+  WaitableEventWatcher();
+  virtual ~WaitableEventWatcher();
+
+  class BASE_EXPORT Delegate {
+   public:
+    // -------------------------------------------------------------------------
+    // This is called on the MessageLoop thread when WaitableEvent has been
+    // signaled.
+    //
+    // Note: the event may not be signaled by the time that this function is
+    // called. This indicates only that it has been signaled at some point in
+    // the past.
+    // -------------------------------------------------------------------------
+    virtual void OnWaitableEventSignaled(WaitableEvent* waitable_event) = 0;
+
+   protected:
+    virtual ~Delegate() { }
+  };
+
+  // ---------------------------------------------------------------------------
+  // When @event is signaled, the given delegate is called on the thread of the
+  // current message loop when StartWatching is called. The delegate is not
+  // deleted.
+  // ---------------------------------------------------------------------------
+  bool StartWatching(WaitableEvent* event, Delegate* delegate);
+
+  // ---------------------------------------------------------------------------
+  // 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 delegate will *not* be called for the current watch after this
+  // function returns. Since the delegate 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 delegate, or NULL if there is no delegate.
+  // ---------------------------------------------------------------------------
+  Delegate* delegate() {
+    return delegate_;
+  }
+
+ private:
+#if defined(OS_WIN)
+  // ---------------------------------------------------------------------------
+  // The helper class exists because, if WaitableEventWatcher were to inherit
+  // from ObjectWatcher::Delegate, then it couldn't also have an inner class
+  // called Delegate (at least on Windows). Thus this object exists to proxy
+  // the callback function
+  // ---------------------------------------------------------------------------
+  class ObjectWatcherHelper : public win::ObjectWatcher::Delegate {
+   public:
+    ObjectWatcherHelper(WaitableEventWatcher* watcher);
+
+    // -------------------------------------------------------------------------
+    // Implementation of ObjectWatcher::Delegate
+    // -------------------------------------------------------------------------
+    void OnObjectSignaled(HANDLE h);
+
+   private:
+    WaitableEventWatcher *const watcher_;
+  };
+
+  void OnObjectSignaled();
+
+  ObjectWatcherHelper helper_;
+  win::ObjectWatcher watcher_;
+#else
+  // ---------------------------------------------------------------------------
+  // Implementation of MessageLoop::DestructionObserver
+  // ---------------------------------------------------------------------------
+  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
+
+  MessageLoop* message_loop_;
+  scoped_refptr<Flag> cancel_flag_;
+  AsyncWaiter* waiter_;
+  base::Closure callback_;
+  scoped_refptr<WaitableEvent::WaitableEventKernel> kernel_;
+#endif
+
+  WaitableEvent* event_;
+
+  Delegate* delegate_;
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_WAITABLE_EVENT_WATCHER_H_
diff --git a/base/synchronization/waitable_event_watcher_posix.cc b/base/synchronization/waitable_event_watcher_posix.cc
new file mode 100644
index 0000000..3180b4b
--- /dev/null
+++ b/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/message_loop.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) { }
+
+  virtual bool Fire(WaitableEvent* event) OVERRIDE {
+    // Post the callback if we haven't been cancelled.
+    if (!flag_->value()) {
+      message_loop_->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
+  virtual 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,
+                         WaitableEventWatcher::Delegate* delegate,
+                         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();
+    delegate->OnWaitableEventSignaled(event);
+  }
+}
+
+WaitableEventWatcher::WaitableEventWatcher()
+    : message_loop_(NULL),
+      cancel_flag_(NULL),
+      waiter_(NULL),
+      event_(NULL),
+      delegate_(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, WaitableEventWatcher::Delegate* delegate) {
+  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_ = base::Bind(&AsyncCallbackHelper, cancel_flag_, delegate, event);
+  WaitableEvent::WaitableEventKernel* kernel = event->kernel_.get();
+
+  AutoLock locked(kernel->lock_);
+
+  delegate_ = delegate;
+  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->PostTask(FROM_HERE, callback_);
+    return true;
+  }
+
+  message_loop_ = current_ml;
+  current_ml->AddDestructionObserver(this);
+
+  kernel_ = kernel;
+  waiter_ = new AsyncWaiter(current_ml, callback_, cancel_flag_);
+  event->Enqueue(waiter_);
+
+  return true;
+}
+
+void WaitableEventWatcher::StopWatching() {
+  delegate_ = NULL;
+
+  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_;
+    callback_.Reset();
+    cancel_flag_ = NULL;
+    return;
+  }
+
+  // Case 3: the waiter isn't on the wait-list, thus it was signaled. It may
+  // not have run yet, so we set the flag to tell it not to bother enqueuing the
+  // task on the MessageLoop, but to delete it instead. The Waiter deletes
+  // itself once run.
+  cancel_flag_->Set();
+  cancel_flag_ = NULL;
+
+  // If the waiter has already run then the task has been enqueued. If the Task
+  // hasn't yet run, the flag will stop the delegate from getting called. (This
+  // is thread safe because one may only delete a Handle from the MessageLoop
+  // thread.)
+  //
+  // If the delegate has already been called then we have nothing to do. The
+  // task has been deleted by the MessageLoop.
+}
+
+WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
+  if (!cancel_flag_.get())
+    return NULL;
+
+  if (cancel_flag_->value())
+    return NULL;
+
+  return event_;
+}
+
+// -----------------------------------------------------------------------------
+// This is called when the MessageLoop which the callback will be run it is
+// deleted. We need to cancel the callback as if we had been deleted, but we
+// will still be deleted at some point in the future.
+// -----------------------------------------------------------------------------
+void WaitableEventWatcher::WillDestroyCurrentMessageLoop() {
+  StopWatching();
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_watcher_unittest.cc b/base/synchronization/waitable_event_watcher_unittest.cc
new file mode 100644
index 0000000..8744aa2
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/synchronization/waitable_event_watcher.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// The message loops on which each waitable event timer should be tested.
+const MessageLoop::Type testing_message_loops[] = {
+  MessageLoop::TYPE_DEFAULT,
+  MessageLoop::TYPE_IO,
+#if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop.
+  MessageLoop::TYPE_UI,
+#endif
+};
+
+const int kNumTestingMessageLoops = arraysize(testing_message_loops);
+
+class QuitDelegate : public WaitableEventWatcher::Delegate {
+ public:
+  virtual void OnWaitableEventSignaled(WaitableEvent* event) OVERRIDE {
+    MessageLoop::current()->Quit();
+  }
+};
+
+class DecrementCountDelegate : public WaitableEventWatcher::Delegate {
+ public:
+  explicit DecrementCountDelegate(int* counter) : counter_(counter) {
+  }
+  virtual void OnWaitableEventSignaled(WaitableEvent* object) OVERRIDE {
+    --(*counter_);
+  }
+ private:
+  int* counter_;
+};
+
+void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  // A manual-reset event that is not yet signaled.
+  WaitableEvent event(true, false);
+
+  WaitableEventWatcher watcher;
+  EXPECT_TRUE(watcher.GetWatchedEvent() == NULL);
+
+  QuitDelegate delegate;
+  watcher.StartWatching(&event, &delegate);
+  EXPECT_EQ(&event, watcher.GetWatchedEvent());
+
+  event.Signal();
+
+  MessageLoop::current()->Run();
+
+  EXPECT_TRUE(watcher.GetWatchedEvent() == NULL);
+}
+
+void RunTest_BasicCancel(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  // A manual-reset event that is not yet signaled.
+  WaitableEvent event(true, false);
+
+  WaitableEventWatcher watcher;
+
+  QuitDelegate delegate;
+  watcher.StartWatching(&event, &delegate);
+
+  watcher.StopWatching();
+}
+
+void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  // A manual-reset event that is not yet signaled.
+  WaitableEvent event(true, false);
+
+  WaitableEventWatcher watcher;
+
+  int counter = 1;
+  DecrementCountDelegate delegate(&counter);
+
+  watcher.StartWatching(&event, &delegate);
+
+  event.Signal();
+
+  // Let the background thread do its business
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
+
+  watcher.StopWatching();
+
+  MessageLoop::current()->RunUntilIdle();
+
+  // Our delegate should not have fired.
+  EXPECT_EQ(1, counter);
+}
+
+void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) {
+  // Simulate a MessageLoop that dies before an WaitableEventWatcher.  This
+  // ordinarily doesn't happen when people use the Thread class, but it can
+  // happen when people use the Singleton pattern or atexit.
+  WaitableEvent event(true, false);
+  {
+    WaitableEventWatcher watcher;
+    {
+      MessageLoop message_loop(message_loop_type);
+
+      QuitDelegate delegate;
+      watcher.StartWatching(&event, &delegate);
+    }
+  }
+}
+
+void RunTest_DeleteUnder(MessageLoop::Type message_loop_type) {
+  // Delete the WaitableEvent out from under the Watcher. This is explictly
+  // allowed by the interface.
+
+  MessageLoop message_loop(message_loop_type);
+
+  {
+    WaitableEventWatcher watcher;
+
+    WaitableEvent* event = new WaitableEvent(false, false);
+    QuitDelegate delegate;
+    watcher.StartWatching(event, &delegate);
+    delete event;
+  }
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+
+TEST(WaitableEventWatcherTest, BasicSignal) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_BasicSignal(testing_message_loops[i]);
+  }
+}
+
+TEST(WaitableEventWatcherTest, BasicCancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_BasicCancel(testing_message_loops[i]);
+  }
+}
+
+TEST(WaitableEventWatcherTest, CancelAfterSet) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_CancelAfterSet(testing_message_loops[i]);
+  }
+}
+
+TEST(WaitableEventWatcherTest, OutlivesMessageLoop) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OutlivesMessageLoop(testing_message_loops[i]);
+  }
+}
+
+#if defined(OS_WIN)
+// Crashes sometimes on vista.  http://crbug.com/62119
+#define MAYBE_DeleteUnder DISABLED_DeleteUnder
+#else
+#define MAYBE_DeleteUnder DeleteUnder
+#endif
+TEST(WaitableEventWatcherTest, MAYBE_DeleteUnder) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DeleteUnder(testing_message_loops[i]);
+  }
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_watcher_win.cc b/base/synchronization/waitable_event_watcher_win.cc
new file mode 100644
index 0000000..43e3c47
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher_win.cc
@@ -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.
+
+#include "base/synchronization/waitable_event_watcher.h"
+
+#include "base/compiler_specific.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/win/object_watcher.h"
+
+namespace base {
+
+WaitableEventWatcher::ObjectWatcherHelper::ObjectWatcherHelper(
+    WaitableEventWatcher* watcher)
+    : watcher_(watcher) {
+};
+
+void WaitableEventWatcher::ObjectWatcherHelper::OnObjectSignaled(HANDLE h) {
+  watcher_->OnObjectSignaled();
+}
+
+
+WaitableEventWatcher::WaitableEventWatcher()
+    : ALLOW_THIS_IN_INITIALIZER_LIST(helper_(this)),
+      event_(NULL),
+      delegate_(NULL) {
+}
+
+WaitableEventWatcher::~WaitableEventWatcher() {
+}
+
+bool WaitableEventWatcher::StartWatching(WaitableEvent* event,
+                                         Delegate* delegate) {
+  delegate_ = delegate;
+  event_ = event;
+
+  return watcher_.StartWatching(event->handle(), &helper_);
+}
+
+void WaitableEventWatcher::StopWatching() {
+  delegate_ = NULL;
+  event_ = NULL;
+  watcher_.StopWatching();
+}
+
+WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
+  return event_;
+}
+
+void WaitableEventWatcher::OnObjectSignaled() {
+  WaitableEvent* event = event_;
+  Delegate* delegate = delegate_;
+  event_ = NULL;
+  delegate_ = NULL;
+  DCHECK(event);
+
+  delegate->OnWaitableEventSignaled(event);
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_win.cc b/base/synchronization/waitable_event_win.cc
new file mode 100644
index 0000000..28f8fc3
--- /dev/null
+++ b/base/synchronization/waitable_event_win.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 "base/synchronization/waitable_event.h"
+
+#include <math.h>
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time.h"
+
+namespace base {
+
+WaitableEvent::WaitableEvent(bool manual_reset, bool signaled)
+    : handle_(CreateEvent(NULL, manual_reset, signaled, NULL)) {
+  // We're probably going to crash anyways if this is ever NULL, so we might as
+  // well make our stack reports more informative by crashing here.
+  CHECK(handle_);
+}
+
+WaitableEvent::WaitableEvent(HANDLE handle)
+    : handle_(handle) {
+  CHECK(handle) << "Tried to create WaitableEvent from NULL handle";
+}
+
+WaitableEvent::~WaitableEvent() {
+  CloseHandle(handle_);
+}
+
+HANDLE WaitableEvent::Release() {
+  HANDLE rv = handle_;
+  handle_ = INVALID_HANDLE_VALUE;
+  return rv;
+}
+
+void WaitableEvent::Reset() {
+  ResetEvent(handle_);
+}
+
+void WaitableEvent::Signal() {
+  SetEvent(handle_);
+}
+
+bool WaitableEvent::IsSignaled() {
+  return TimedWait(TimeDelta::FromMilliseconds(0));
+}
+
+void WaitableEvent::Wait() {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DWORD result = WaitForSingleObject(handle_, INFINITE);
+  // It is most unexpected that this should ever fail.  Help consumers learn
+  // about it if it should ever fail.
+  DCHECK_EQ(WAIT_OBJECT_0, result) << "WaitForSingleObject failed";
+}
+
+bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DCHECK(max_time >= TimeDelta::FromMicroseconds(0));
+  // Be careful here.  TimeDelta has a precision of microseconds, but this API
+  // is in milliseconds.  If there are 5.5ms left, should the delay be 5 or 6?
+  // It should be 6 to avoid returning too early.
+  double timeout = ceil(max_time.InMillisecondsF());
+  DWORD result = WaitForSingleObject(handle_, static_cast<DWORD>(timeout));
+  switch (result) {
+    case WAIT_OBJECT_0:
+      return true;
+    case WAIT_TIMEOUT:
+      return false;
+  }
+  // It is most unexpected that this should ever fail.  Help consumers learn
+  // about it if it should ever fail.
+  NOTREACHED() << "WaitForSingleObject failed";
+  return false;
+}
+
+// static
+size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+  CHECK_LE(count, MAXIMUM_WAIT_OBJECTS)
+      << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany";
+
+  for (size_t i = 0; i < count; ++i)
+    handles[i] = events[i]->handle();
+
+  // The cast is safe because count is small - see the CHECK above.
+  DWORD result =
+      WaitForMultipleObjects(static_cast<DWORD>(count),
+                             handles,
+                             FALSE,      // don't wait for all the objects
+                             INFINITE);  // no timeout
+  if (result >= WAIT_OBJECT_0 + count) {
+    NOTREACHED() << "WaitForMultipleObjects failed: " << GetLastError();
+    return 0;
+  }
+
+  return result - WAIT_OBJECT_0;
+}
+
+}  // namespace base
diff --git a/base/sys_byteorder.h b/base/sys_byteorder.h
new file mode 100644
index 0000000..97e33ac
--- /dev/null
+++ b/base/sys_byteorder.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.
+
+// This header defines cross-platform ByteSwap() implementations for 16, 32 and
+// 64-bit values, and NetToHostXX() / HostToNextXX() functions equivalent to
+// the traditional ntohX() and htonX() functions.
+// Use the functions defined here rather than using the platform-specific
+// functions directly.
+
+#ifndef BASE_SYS_BYTEORDER_H_
+#define BASE_SYS_BYTEORDER_H_
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+// Include headers to provide byteswap for all platforms.
+#if defined(COMPILER_MSVC)
+#include <stdlib.h>
+#elif defined(OS_MACOSX)
+#include <libkern/OSByteOrder.h>
+#elif defined(OS_OPENBSD)
+#include <sys/endian.h>
+#else
+#include <byteswap.h>
+#endif
+
+
+namespace base {
+
+// Returns a value with all bytes in |x| swapped, i.e. reverses the endianness.
+inline uint16 ByteSwap(uint16 x) {
+#if defined(COMPILER_MSVC)
+  return _byteswap_ushort(x);
+#elif defined(OS_MACOSX)
+  return OSSwapInt16(x);
+#elif defined(OS_OPENBSD)
+  return swap16(x);
+#else
+  return bswap_16(x);
+#endif
+}
+inline uint32 ByteSwap(uint32 x) {
+#if defined(COMPILER_MSVC)
+  return _byteswap_ulong(x);
+#elif defined(OS_MACOSX)
+  return OSSwapInt32(x);
+#elif defined(OS_OPENBSD)
+  return swap32(x);
+#else
+  return bswap_32(x);
+#endif
+}
+inline uint64 ByteSwap(uint64 x) {
+#if defined(COMPILER_MSVC)
+  return _byteswap_uint64(x);
+#elif defined(OS_MACOSX)
+  return OSSwapInt64(x);
+#elif defined(OS_OPENBSD)
+  return swap64(x);
+#else
+  return bswap_64(x);
+#endif
+}
+
+// Converts the bytes in |x| from host order (endianness) to little endian, and
+// returns the result.
+inline uint16 ByteSwapToLE16(uint16 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+inline uint32 ByteSwapToLE32(uint32 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+inline uint64 ByteSwapToLE64(uint64 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+
+// Converts the bytes in |x| from network to host order (endianness), and
+// returns the result.
+inline uint16 NetToHost16(uint16 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint32 NetToHost32(uint32 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint64 NetToHost64(uint64 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+
+// Converts the bytes in |x| from host to network order (endianness), and
+// returns the result.
+inline uint16 HostToNet16(uint16 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint32 HostToNet32(uint32 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint64 HostToNet64(uint64 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+
+}  // namespace base
+
+
+#endif  // BASE_SYS_BYTEORDER_H_
diff --git a/base/sys_info.cc b/base/sys_info.cc
new file mode 100644
index 0000000..fa940bf
--- /dev/null
+++ b/base/sys_info.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/time.h"
+
+namespace base {
+
+// static
+int64 SysInfo::Uptime() {
+  // This code relies on an implementation detail of TimeTicks::Now() - that
+  // its return value happens to coincide with the system uptime value in
+  // microseconds, on Win/Mac/iOS/Linux/ChromeOS and Android.
+  int64 uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
+  return uptime_in_microseconds / 1000;
+}
+
+}  // namespace base
diff --git a/base/sys_info.h b/base/sys_info.h
new file mode 100644
index 0000000..97b17c4
--- /dev/null
+++ b/base/sys_info.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYS_INFO_H_
+#define BASE_SYS_INFO_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class BASE_EXPORT SysInfo {
+ public:
+  // Return the number of logical processors/cores on the current machine.
+  static int NumberOfProcessors();
+
+  // Return the number of bytes of physical memory on the current machine.
+  static int64 AmountOfPhysicalMemory();
+
+  // Return the number of bytes of current available physical memory on the
+  // machine.
+  static int64 AmountOfAvailablePhysicalMemory();
+
+  // Return the number of megabytes of physical memory on the current machine.
+  static int AmountOfPhysicalMemoryMB() {
+    return static_cast<int>(AmountOfPhysicalMemory() / 1024 / 1024);
+  }
+
+  // Return the available disk space in bytes on the volume containing |path|,
+  // or -1 on failure.
+  static int64 AmountOfFreeDiskSpace(const FilePath& path);
+
+  // Returns system uptime in milliseconds.
+  static int64 Uptime();
+
+  // Returns the name of the host operating system.
+  static std::string OperatingSystemName();
+
+  // Returns the version of the host operating system.
+  static std::string OperatingSystemVersion();
+
+  // Retrieves detailed numeric values for the OS version.
+  // TODO(port): Implement a Linux version of this method and enable the
+  // corresponding unit test.
+  // DON'T USE THIS ON THE MAC OR WINDOWS to determine the current OS release
+  // for OS version-specific feature checks and workarounds. If you must use
+  // an OS version check instead of a feature check, use the base::mac::IsOS*
+  // family from base/mac/mac_util.h, or base::win::GetVersion from
+  // base/win/windows_version.h.
+  static void OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version);
+
+  // Returns the architecture of the running operating system.
+  // Exact return value may differ across platforms.
+  // e.g. a 32-bit x86 kernel on a 64-bit capable CPU will return "x86",
+  //      whereas a x86-64 kernel on the same CPU will return "x86_64"
+  static std::string OperatingSystemArchitecture();
+
+  // Avoid using this. Use base/cpu.h to get information about the CPU instead.
+  // http://crbug.com/148884
+  // Returns the CPU model name of the system. If it can not be figured out,
+  // an empty string is returned.
+  static std::string CPUModelName();
+
+  // Return the smallest amount of memory (in bytes) which the VM system will
+  // allocate.
+  static size_t VMAllocationGranularity();
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+  // Returns the maximum SysV shared memory segment size.
+  static size_t MaxSharedMemorySize();
+#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
+
+#if defined(OS_CHROMEOS)
+  // Returns the name of the version entry we wish to look up in the
+  // Linux Standard Base release information file.
+  static std::string GetLinuxStandardBaseVersionKey();
+
+  // Parses /etc/lsb-release to get version information for Google Chrome OS.
+  // Declared here so it can be exposed for unit testing.
+  static void ParseLsbRelease(const std::string& lsb_release,
+                              int32* major_version,
+                              int32* minor_version,
+                              int32* bugfix_version);
+
+  // Returns the path to the lsb-release file.
+  static FilePath GetLsbReleaseFilePath();
+#endif  // defined(OS_CHROMEOS)
+
+#if defined(OS_ANDROID)
+  // Returns the Android build's codename.
+  static std::string GetAndroidBuildCodename();
+
+  // Returns the Android build ID.
+  static std::string GetAndroidBuildID();
+
+  // Returns the device's name.
+  static std::string GetDeviceName();
+
+  static int DalvikHeapSizeMB();
+#endif  // defined(OS_ANDROID)
+};
+
+}  // namespace base
+
+#endif  // BASE_SYS_INFO_H_
diff --git a/base/sys_info_android.cc b/base/sys_info_android.cc
new file mode 100644
index 0000000..c0bbe44
--- /dev/null
+++ b/base/sys_info_android.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <sys/system_properties.h>
+
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+
+namespace {
+
+// Default version of Android to fall back to when actual version numbers
+// cannot be acquired.
+// TODO(dfalcantara): Keep this reasonably up to date with the latest publicly
+//                    available version of Android.
+static const int kDefaultAndroidMajorVersion = 4;
+static const int kDefaultAndroidMinorVersion = 0;
+static const int kDefaultAndroidBugfixVersion = 3;
+
+// Parse out the OS version numbers from the system properties.
+void ParseOSVersionNumbers(const char* os_version_str,
+                           int32 *major_version,
+                           int32 *minor_version,
+                           int32 *bugfix_version) {
+  if (os_version_str[0]) {
+    // Try to parse out the version numbers from the string.
+    int num_read = sscanf(os_version_str, "%d.%d.%d", major_version,
+                          minor_version, bugfix_version);
+
+    if (num_read > 0) {
+      // If we don't have a full set of version numbers, make the extras 0.
+      if (num_read < 2) *minor_version = 0;
+      if (num_read < 3) *bugfix_version = 0;
+      return;
+    }
+  }
+
+  // For some reason, we couldn't parse the version number string.
+  *major_version = kDefaultAndroidMajorVersion;
+  *minor_version = kDefaultAndroidMinorVersion;
+  *bugfix_version = kDefaultAndroidBugfixVersion;
+}
+
+int ParseHeapSize(const base::StringPiece& str) {
+  const int64 KB = 1024;
+  const int64 MB = 1024 * KB;
+  const int64 GB = 1024 * MB;
+  CHECK_GT(str.size(), 0u);
+  int64 factor = 1;
+  size_t length = str.size();
+  if (str[length - 1] == 'k') {
+    factor = KB;
+    length--;
+  } else if (str[length - 1] == 'm') {
+    factor = MB;
+    length--;
+  } else if (str[length - 1] == 'g') {
+    factor = GB;
+    length--;
+  } else {
+    CHECK('0' <= str[length - 1] && str[length - 1] <= '9');
+  }
+  int64 result = 0;
+  bool parsed = base::StringToInt64(str.substr(0, length), &result);
+  CHECK(parsed);
+  result = result * factor / MB;
+  // dalvik.vm.heapsize property is writable by user,
+  // truncate it to reasonable value to avoid overflows later.
+  result = std::min<int64>(std::max<int64>(32, result), 1024);
+  return static_cast<int>(result);
+}
+
+int GetDalvikHeapSizeMB() {
+  char heap_size_str[PROP_VALUE_MAX];
+  __system_property_get("dalvik.vm.heapsize", heap_size_str);
+  return ParseHeapSize(heap_size_str);
+}
+
+}  // anonymous namespace
+
+namespace base {
+
+std::string SysInfo::OperatingSystemName() {
+  return "Android";
+}
+
+std::string SysInfo::GetAndroidBuildCodename() {
+  char os_version_codename_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.version.codename", os_version_codename_str);
+  return std::string(os_version_codename_str);
+}
+
+std::string SysInfo::GetAndroidBuildID() {
+  char os_build_id_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.id", os_build_id_str);
+  return std::string(os_build_id_str);
+}
+
+std::string SysInfo::GetDeviceName() {
+  char device_model_str[PROP_VALUE_MAX];
+  __system_property_get("ro.product.model", device_model_str);
+  return std::string(device_model_str);
+}
+
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  // Read the version number string out from the properties.
+  char os_version_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.version.release", os_version_str);
+
+  // Parse out the numbers.
+  ParseOSVersionNumbers(os_version_str, major_version, minor_version,
+                        bugfix_version);
+}
+
+int SysInfo::DalvikHeapSizeMB() {
+  static int heap_size = GetDalvikHeapSizeMB();
+  return heap_size;
+}
+
+}  // namespace base
diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc
new file mode 100644
index 0000000..92a3f0c
--- /dev/null
+++ b/base/sys_info_chromeos.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/sys_info.h"
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/string_tokenizer.h"
+#include "base/threading/thread_restrictions.h"
+
+#include <execinfo.h>
+
+namespace base {
+
+static const char* kLinuxStandardBaseVersionKeys[] = {
+  "CHROMEOS_RELEASE_VERSION",
+  "GOOGLE_RELEASE",
+  "DISTRIB_RELEASE",
+  NULL
+};
+
+const char kLinuxStandardBaseReleaseFile[] = "/etc/lsb-release";
+
+struct ChromeOSVersionNumbers {
+  ChromeOSVersionNumbers()
+      : major_version(0),
+        minor_version(0),
+        bugfix_version(0),
+        parsed(false) {
+  }
+
+  int32 major_version;
+  int32 minor_version;
+  int32 bugfix_version;
+  bool parsed;
+};
+
+static base::LazyInstance<ChromeOSVersionNumbers>
+    g_chrome_os_version_numbers = LAZY_INSTANCE_INITIALIZER;
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  if (!g_chrome_os_version_numbers.Get().parsed) {
+    // The other implementations of SysInfo don't block on the disk.
+    // See http://code.google.com/p/chromium/issues/detail?id=60394
+    // Perhaps the caller ought to cache this?
+    // Temporary allowing while we work the bug out.
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+    FilePath path(kLinuxStandardBaseReleaseFile);
+    std::string contents;
+    if (file_util::ReadFileToString(path, &contents)) {
+      g_chrome_os_version_numbers.Get().parsed = true;
+      ParseLsbRelease(contents,
+          &(g_chrome_os_version_numbers.Get().major_version),
+          &(g_chrome_os_version_numbers.Get().minor_version),
+          &(g_chrome_os_version_numbers.Get().bugfix_version));
+    }
+  }
+  *major_version = g_chrome_os_version_numbers.Get().major_version;
+  *minor_version = g_chrome_os_version_numbers.Get().minor_version;
+  *bugfix_version = g_chrome_os_version_numbers.Get().bugfix_version;
+}
+
+// static
+std::string SysInfo::GetLinuxStandardBaseVersionKey() {
+  return std::string(kLinuxStandardBaseVersionKeys[0]);
+}
+
+// static
+void SysInfo::ParseLsbRelease(const std::string& lsb_release,
+                              int32* major_version,
+                              int32* minor_version,
+                              int32* bugfix_version) {
+  size_t version_key_index = std::string::npos;
+  for (int i = 0; kLinuxStandardBaseVersionKeys[i] != NULL; ++i) {
+    version_key_index = lsb_release.find(kLinuxStandardBaseVersionKeys[i]);
+    if (std::string::npos != version_key_index) {
+      break;
+    }
+  }
+  if (std::string::npos == version_key_index) {
+    return;
+  }
+
+  size_t start_index = lsb_release.find_first_of('=', version_key_index);
+  start_index++;  // Move past '='.
+  size_t length = lsb_release.find_first_of('\n', start_index) - start_index;
+  std::string version = lsb_release.substr(start_index, length);
+  StringTokenizer tokenizer(version, ".");
+  for (int i = 0; i < 3 && tokenizer.GetNext(); ++i) {
+    if (0 == i) {
+      StringToInt(StringPiece(tokenizer.token_begin(),
+                              tokenizer.token_end()),
+                  major_version);
+      *minor_version = *bugfix_version = 0;
+    } else if (1 == i) {
+      StringToInt(StringPiece(tokenizer.token_begin(),
+                              tokenizer.token_end()),
+                  minor_version);
+    } else {  // 2 == i
+      StringToInt(StringPiece(tokenizer.token_begin(),
+                              tokenizer.token_end()),
+                  bugfix_version);
+    }
+  }
+}
+
+// static
+FilePath SysInfo::GetLsbReleaseFilePath() {
+  return FilePath(kLinuxStandardBaseReleaseFile);
+}
+
+}  // namespace base
diff --git a/base/sys_info_freebsd.cc b/base/sys_info_freebsd.cc
new file mode 100644
index 0000000..832b359
--- /dev/null
+++ b/base/sys_info_freebsd.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+int64 SysInfo::AmountOfPhysicalMemory() {
+  int pages, page_size;
+  size_t size = sizeof(pages);
+  sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0);
+  sysctlbyname("vm.stats.vm.v_page_size", &page_size, &size, NULL, 0);
+  if (pages == -1 || page_size == -1) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<int64>(pages) * page_size;
+}
+
+// static
+size_t SysInfo::MaxSharedMemorySize() {
+  size_t limit;
+  size_t size = sizeof(limit);
+  if (sysctlbyname("kern.ipc.shmmax", &limit, &size, NULL, 0) < 0) {
+    NOTREACHED();
+    return 0;
+  }
+  return limit;
+}
+
+}  // namespace base
diff --git a/base/sys_info_ios.mm b/base/sys_info_ios.mm
new file mode 100644
index 0000000..1ee0e54
--- /dev/null
+++ b/base/sys_info_ios.mm
@@ -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/sys_info.h"
+
+#import <UIKit/UIKit.h>
+#include <mach/mach.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/sys_string_conversions.h"
+
+namespace base {
+
+// static
+std::string SysInfo::OperatingSystemName() {
+  base::mac::ScopedNSAutoreleasePool pool;
+  // Examples of returned value: 'iPhone OS' on iPad 5.1.1
+  // and iPhone 5.1.1.
+  return SysNSStringToUTF8([[UIDevice currentDevice] systemName]);
+}
+
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  base::mac::ScopedNSAutoreleasePool pool;
+  return SysNSStringToUTF8([[UIDevice currentDevice] systemVersion]);
+}
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  base::mac::ScopedNSAutoreleasePool pool;
+  NSString* version = [[UIDevice currentDevice] systemVersion];
+  NSArray* version_info = [version componentsSeparatedByString:@"."];
+  NSUInteger length = [version_info count];
+
+  *major_version = [[version_info objectAtIndex:0] intValue];
+
+  if (length >= 2)
+    *minor_version = [[version_info objectAtIndex:1] intValue];
+  else
+    *minor_version = 0;
+
+  if (length >= 3)
+    *bugfix_version = [[version_info objectAtIndex:2] intValue];
+  else
+    *bugfix_version = 0;
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  struct host_basic_info hostinfo;
+  mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+  base::mac::ScopedMachPort host(mach_host_self());
+  int result = host_info(host,
+                         HOST_BASIC_INFO,
+                         reinterpret_cast<host_info_t>(&hostinfo),
+                         &count);
+  if (result != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+  DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
+  return static_cast<int64>(hostinfo.max_mem);
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  char name[256];
+  size_t len = arraysize(name);
+  if (sysctlbyname("machdep.cpu.brand_string", &name, &len, NULL, 0) == 0)
+    return name;
+  return std::string();
+}
+
+}  // namespace base
diff --git a/base/sys_info_linux.cc b/base/sys_info_linux.cc
new file mode 100644
index 0000000..6683674
--- /dev/null
+++ b/base/sys_info_linux.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <limits>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+
+namespace base {
+
+int64 SysInfo::AmountOfPhysicalMemory() {
+  long pages = sysconf(_SC_PHYS_PAGES);
+  long page_size = sysconf(_SC_PAGE_SIZE);
+  if (pages == -1 || page_size == -1) {
+    NOTREACHED();
+    return 0;
+  }
+
+  return static_cast<int64>(pages) * page_size;
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  long available_pages = sysconf(_SC_AVPHYS_PAGES);
+  long page_size = sysconf(_SC_PAGE_SIZE);
+  if (available_pages == -1 || page_size == -1) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<int64>(available_pages) * page_size;
+}
+
+// static
+size_t SysInfo::MaxSharedMemorySize() {
+  static int64 limit;
+  static bool limit_valid = false;
+  if (!limit_valid) {
+    std::string contents;
+    file_util::ReadFileToString(FilePath("/proc/sys/kernel/shmmax"), &contents);
+    DCHECK(!contents.empty());
+    if (!contents.empty() && contents[contents.length() - 1] == '\n') {
+      contents.erase(contents.length() - 1);
+    }
+    if (base::StringToInt64(contents, &limit)) {
+      DCHECK(limit >= 0);
+      DCHECK(static_cast<uint64>(limit) <= std::numeric_limits<size_t>::max());
+      limit_valid = true;
+    } else {
+      NOTREACHED();
+      return 0;
+    }
+  }
+  return static_cast<size_t>(limit);
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  const char kModelNamePrefix[] = "model name";
+  std::string contents;
+  file_util::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(kModelNamePrefix), kModelNamePrefix) == 0) {
+        size_t pos = line.find(": ");
+        return line.substr(pos + 2);
+      }
+    }
+  }
+  return std::string();
+}
+
+}  // namespace base
diff --git a/base/sys_info_mac.cc b/base/sys_info_mac.cc
new file mode 100644
index 0000000..223be3d
--- /dev/null
+++ b/base/sys_info_mac.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+#include <CoreServices/CoreServices.h>
+#include <mach/mach_host.h>
+#include <mach/mach_init.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/stringprintf.h"
+
+namespace base {
+
+// static
+std::string SysInfo::OperatingSystemName() {
+  return "Mac OS X";
+}
+
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  int32 major, minor, bugfix;
+  OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+  return base::StringPrintf("%d.%d.%d", major, minor, bugfix);
+}
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  Gestalt(gestaltSystemVersionMajor,
+      reinterpret_cast<SInt32*>(major_version));
+  Gestalt(gestaltSystemVersionMinor,
+      reinterpret_cast<SInt32*>(minor_version));
+  Gestalt(gestaltSystemVersionBugFix,
+      reinterpret_cast<SInt32*>(bugfix_version));
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  struct host_basic_info hostinfo;
+  mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+  base::mac::ScopedMachPort host(mach_host_self());
+  int result = host_info(host,
+                         HOST_BASIC_INFO,
+                         reinterpret_cast<host_info_t>(&hostinfo),
+                         &count);
+  if (result != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+  DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
+  return static_cast<int64>(hostinfo.max_mem);
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  base::mac::ScopedMachPort host(mach_host_self());
+  vm_statistics_data_t vm_info;
+  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+
+  if (host_statistics(host.get(),
+                      HOST_VM_INFO,
+                      reinterpret_cast<host_info_t>(&vm_info),
+                      &count) != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+
+  return static_cast<int64>(vm_info.free_count) * PAGE_SIZE;
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  char name[256];
+  size_t len = arraysize(name);
+  if (sysctlbyname("machdep.cpu.brand_string", &name, &len, NULL, 0) == 0)
+    return name;
+  return std::string();
+}
+
+}  // namespace base
diff --git a/base/sys_info_openbsd.cc b/base/sys_info_openbsd.cc
new file mode 100644
index 0000000..b9aec20
--- /dev/null
+++ b/base/sys_info_openbsd.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <sys/param.h>
+#include <sys/shm.h>
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+int SysInfo::NumberOfProcessors() {
+  int mib[] = { CTL_HW, HW_NCPU };
+  int ncpu;
+  size_t size = sizeof(ncpu);
+  if (sysctl(mib, arraysize(mib), &ncpu, &size, NULL, 0) == -1) {
+    NOTREACHED();
+    return 1;
+  }
+  return ncpu;
+}
+
+int64 SysInfo::AmountOfPhysicalMemory() {
+  long pages = sysconf(_SC_PHYS_PAGES);
+  long page_size = sysconf(_SC_PAGESIZE);
+  if (pages == -1 || page_size == -1) {
+    NOTREACHED();
+    return 0;
+  }
+
+  return static_cast<int64>(pages) * page_size;
+}
+
+size_t SysInfo::MaxSharedMemorySize() {
+  int mib[] = { CTL_KERN, KERN_SHMINFO, KERN_SHMINFO_SHMMAX };
+  size_t limit;
+  size_t size = sizeof(limit);
+  if (sysctl(mib, arraysize(mib), &limit, &size, NULL, 0) < 0) {
+    NOTREACHED();
+    return 0;
+  }
+  return limit;
+}
+
+}  // namespace base
diff --git a/base/sys_info_posix.cc b/base/sys_info_posix.cc
new file mode 100644
index 0000000..f2119cd
--- /dev/null
+++ b/base/sys_info_posix.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/utf_string_conversions.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 base {
+
+#if !defined(OS_OPENBSD)
+int SysInfo::NumberOfProcessors() {
+  // It seems that sysconf returns the number of "logical" processors on both
+  // Mac and Linux.  So we get the number of "online logical" processors.
+  long res = sysconf(_SC_NPROCESSORS_ONLN);
+  if (res == -1) {
+    NOTREACHED();
+    return 1;
+  }
+
+  return static_cast<int>(res);
+}
+#endif
+
+// static
+int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  struct statvfs stats;
+  if (statvfs(path.value().c_str(), &stats) != 0) {
+    return -1;
+  }
+  return static_cast<int64>(stats.f_bavail) * stats.f_frsize;
+}
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+// static
+std::string SysInfo::OperatingSystemName() {
+  struct utsname info;
+  if (uname(&info) < 0) {
+    NOTREACHED();
+    return "";
+  }
+  return std::string(info.sysname);
+}
+#endif
+
+#if !defined(OS_MACOSX)
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  struct utsname info;
+  if (uname(&info) < 0) {
+    NOTREACHED();
+    return "";
+  }
+  return std::string(info.release);
+}
+#endif
+
+// static
+std::string SysInfo::OperatingSystemArchitecture() {
+  struct utsname info;
+  if (uname(&info) < 0) {
+    NOTREACHED();
+    return "";
+  }
+  std::string arch(info.machine);
+  if (arch == "i386" || arch == "i486" || arch == "i586" || arch == "i686") {
+    arch = "x86";
+  } else if (arch == "amd64") {
+    arch = "x86_64";
+  }
+  return arch;
+}
+
+// static
+size_t SysInfo::VMAllocationGranularity() {
+  return getpagesize();
+}
+
+}  // namespace base
diff --git a/base/sys_info_unittest.cc b/base/sys_info_unittest.cc
new file mode 100644
index 0000000..55f9601
--- /dev/null
+++ b/base/sys_info_unittest.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/file_util.h"
+#include "base/sys_info.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest SysInfoTest;
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+TEST_F(SysInfoTest, MaxSharedMemorySize) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  EXPECT_GT(base::SysInfo::MaxSharedMemorySize(), 0u);
+}
+#endif
+
+TEST_F(SysInfoTest, NumProcs) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  EXPECT_GE(base::SysInfo::NumberOfProcessors(), 1);
+}
+
+TEST_F(SysInfoTest, AmountOfMem) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  EXPECT_GT(base::SysInfo::AmountOfPhysicalMemory(), 0);
+  EXPECT_GT(base::SysInfo::AmountOfPhysicalMemoryMB(), 0);
+}
+
+TEST_F(SysInfoTest, AmountOfFreeDiskSpace) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  FilePath tmp_path;
+  ASSERT_TRUE(file_util::GetTempDir(&tmp_path));
+  EXPECT_GT(base::SysInfo::AmountOfFreeDiskSpace(tmp_path), 0)
+            << tmp_path.value();
+}
+
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
+TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
+                                               &os_minor_version,
+                                               &os_bugfix_version);
+  EXPECT_GT(os_major_version, -1);
+  EXPECT_GT(os_minor_version, -1);
+  EXPECT_GT(os_bugfix_version, -1);
+}
+#endif
+
+TEST_F(SysInfoTest, Uptime) {
+  int64 up_time_1 = base::SysInfo::Uptime();
+  // UpTime() is implemented internally using TimeTicks::Now(), which documents
+  // system resolution as being 1-15ms. Sleep a little longer than that.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
+  int64 up_time_2 = base::SysInfo::Uptime();
+  EXPECT_GT(up_time_1, 0);
+  EXPECT_GT(up_time_2, up_time_1);
+}
+
+#if defined(OS_CHROMEOS)
+TEST_F(SysInfoTest, GoogleChromeOSVersionNumbers) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  std::string lsb_release("FOO=1234123.34.5\n");
+  lsb_release.append(base::SysInfo::GetLinuxStandardBaseVersionKey());
+  lsb_release.append("=1.2.3.4\n");
+  base::SysInfo::ParseLsbRelease(lsb_release,
+                                 &os_major_version,
+                                 &os_minor_version,
+                                 &os_bugfix_version);
+  EXPECT_EQ(1, os_major_version);
+  EXPECT_EQ(2, os_minor_version);
+  EXPECT_EQ(3, os_bugfix_version);
+}
+
+TEST_F(SysInfoTest, GoogleChromeOSVersionNumbersFirst) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  std::string lsb_release(base::SysInfo::GetLinuxStandardBaseVersionKey());
+  lsb_release.append("=1.2.3.4\n");
+  lsb_release.append("FOO=1234123.34.5\n");
+  base::SysInfo::ParseLsbRelease(lsb_release,
+                                 &os_major_version,
+                                 &os_minor_version,
+                                 &os_bugfix_version);
+  EXPECT_EQ(1, os_major_version);
+  EXPECT_EQ(2, os_minor_version);
+  EXPECT_EQ(3, os_bugfix_version);
+}
+
+TEST_F(SysInfoTest, GoogleChromeOSNoVersionNumbers) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  std::string lsb_release("FOO=1234123.34.5\n");
+  base::SysInfo::ParseLsbRelease(lsb_release,
+                                 &os_major_version,
+                                 &os_minor_version,
+                                 &os_bugfix_version);
+  EXPECT_EQ(-1, os_major_version);
+  EXPECT_EQ(-1, os_minor_version);
+  EXPECT_EQ(-1, os_bugfix_version);
+}
+
+#endif  // OS_CHROMEOS
diff --git a/base/sys_info_win.cc b/base/sys_info_win.cc
new file mode 100644
index 0000000..98d2f7c
--- /dev/null
+++ b/base/sys_info_win.cc
@@ -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.
+
+#include "base/sys_info.h"
+
+#include <windows.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+// static
+int SysInfo::NumberOfProcessors() {
+  return win::OSInfo::GetInstance()->processors();
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  MEMORYSTATUSEX memory_info;
+  memory_info.dwLength = sizeof(memory_info);
+  if (!GlobalMemoryStatusEx(&memory_info)) {
+    NOTREACHED();
+    return 0;
+  }
+
+  int64 rv = static_cast<int64>(memory_info.ullTotalPhys);
+  if (rv < 0)
+    rv = kint64max;
+  return rv;
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  MEMORYSTATUSEX memory_info;
+  memory_info.dwLength = sizeof(memory_info);
+  if (!GlobalMemoryStatusEx(&memory_info)) {
+    NOTREACHED();
+    return 0;
+  }
+
+  int64 rv = static_cast<int64>(memory_info.ullAvailPhys);
+  if (rv < 0)
+    rv = kint64max;
+  return rv;
+}
+
+// static
+int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  ULARGE_INTEGER available, total, free;
+  if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free)) {
+    return -1;
+  }
+  int64 rv = static_cast<int64>(available.QuadPart);
+  if (rv < 0)
+    rv = kint64max;
+  return rv;
+}
+
+// static
+std::string SysInfo::OperatingSystemName() {
+  return "Windows NT";
+}
+
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  win::OSInfo* os_info = win::OSInfo::GetInstance();
+  win::OSInfo::VersionNumber version_number = os_info->version_number();
+  std::string version(StringPrintf("%d.%d", version_number.major,
+                                   version_number.minor));
+  win::OSInfo::ServicePack service_pack = os_info->service_pack();
+  if (service_pack.major != 0) {
+    version += StringPrintf(" SP%d", service_pack.major);
+    if (service_pack.minor != 0)
+      version += StringPrintf(".%d", service_pack.minor);
+  }
+  return version;
+}
+
+// TODO: Implement OperatingSystemVersionComplete, which would include
+// patchlevel/service pack number.
+// See chrome/browser/feedback/feedback_util.h, FeedbackUtil::SetOSVersion.
+
+// static
+std::string SysInfo::OperatingSystemArchitecture() {
+  win::OSInfo::WindowsArchitecture arch =
+      win::OSInfo::GetInstance()->architecture();
+  switch (arch) {
+    case win::OSInfo::X86_ARCHITECTURE:
+      return "x86";
+    case win::OSInfo::X64_ARCHITECTURE:
+      return "x86_64";
+    case win::OSInfo::IA64_ARCHITECTURE:
+      return "ia64";
+    default:
+      return "";
+  }
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  return win::OSInfo::GetInstance()->processor_model_name();
+}
+
+// static
+size_t SysInfo::VMAllocationGranularity() {
+  return win::OSInfo::GetInstance()->allocation_granularity();
+}
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  win::OSInfo* os_info = win::OSInfo::GetInstance();
+  *major_version = os_info->version_number().major;
+  *minor_version = os_info->version_number().minor;
+  *bugfix_version = 0;
+}
+
+}  // namespace base
diff --git a/base/sys_string_conversions.h b/base/sys_string_conversions.h
new file mode 100644
index 0000000..3f7631c
--- /dev/null
+++ b/base/sys_string_conversions.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYS_STRING_CONVERSIONS_H_
+#define BASE_SYS_STRING_CONVERSIONS_H_
+
+// Provides system-dependent string type conversions for cases where it's
+// necessary to not use ICU. Generally, you should not need this in Chrome,
+// but it is used in some shared code. Dependencies should be minimal.
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/string16.h"
+#include "base/string_piece.h"
+
+#if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#ifdef __OBJC__
+@class NSString;
+#else
+class NSString;
+#endif
+#endif  // OS_MACOSX
+
+namespace base {
+
+// Converts between wide and UTF-8 representations of a string. On error, the
+// result is system-dependent.
+BASE_EXPORT std::string SysWideToUTF8(const std::wstring& wide);
+BASE_EXPORT std::wstring SysUTF8ToWide(const StringPiece& utf8);
+
+// Converts between wide and the system multi-byte representations of a string.
+// DANGER: This will lose information and can change (on Windows, this can
+// change between reboots).
+BASE_EXPORT std::string SysWideToNativeMB(const std::wstring& wide);
+BASE_EXPORT std::wstring SysNativeMBToWide(const StringPiece& native_mb);
+
+// Windows-specific ------------------------------------------------------------
+
+#if defined(OS_WIN)
+
+// Converts between 8-bit and wide strings, using the given code page. The
+// code page identifier is one accepted by the Windows function
+// MultiByteToWideChar().
+BASE_EXPORT std::wstring SysMultiByteToWide(const StringPiece& mb,
+                                            uint32 code_page);
+BASE_EXPORT std::string SysWideToMultiByte(const std::wstring& wide,
+                                           uint32 code_page);
+
+#endif  // defined(OS_WIN)
+
+// Mac-specific ----------------------------------------------------------------
+
+#if defined(OS_MACOSX)
+
+// Converts between STL strings and CFStringRefs/NSStrings.
+
+// Creates a string, and returns it with a refcount of 1. You are responsible
+// for releasing it. Returns NULL on failure.
+BASE_EXPORT CFStringRef SysUTF8ToCFStringRef(const std::string& utf8);
+BASE_EXPORT CFStringRef SysUTF16ToCFStringRef(const string16& utf16);
+
+// Same, but returns an autoreleased NSString.
+BASE_EXPORT NSString* SysUTF8ToNSString(const std::string& utf8);
+BASE_EXPORT NSString* SysUTF16ToNSString(const string16& utf16);
+
+// Converts a CFStringRef to an STL string. Returns an empty string on failure.
+BASE_EXPORT std::string SysCFStringRefToUTF8(CFStringRef ref);
+BASE_EXPORT string16 SysCFStringRefToUTF16(CFStringRef ref);
+
+// Same, but accepts NSString input. Converts nil NSString* to the appropriate
+// string type of length 0.
+BASE_EXPORT std::string SysNSStringToUTF8(NSString* ref);
+BASE_EXPORT string16 SysNSStringToUTF16(NSString* ref);
+
+#endif  // defined(OS_MACOSX)
+
+}  // namespace base
+
+#endif  // BASE_SYS_STRING_CONVERSIONS_H_
diff --git a/base/sys_string_conversions_mac.mm b/base/sys_string_conversions_mac.mm
new file mode 100644
index 0000000..d1e3743
--- /dev/null
+++ b/base/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/sys_string_conversions.h"
+
+#import <Foundation/Foundation.h>
+
+#include <vector>
+
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/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::mac::ScopedCFTypeRef<CFStringRef> cfstring(
+      CFStringCreateWithBytesNoCopy(NULL,
+                                    reinterpret_cast<const UInt8*>(in.data()),
+                                    in_length *
+                                      sizeof(typename InStringType::value_type),
+                                    in_encoding,
+                                    false,
+                                    kCFAllocatorNull));
+  if (!cfstring)
+    return OutStringType();
+
+  return CFStringToSTLStringWithEncodingT<OutStringType>(cfstring,
+                                                         out_encoding);
+}
+
+// Given an STL string |in| with an encoding specified by |in_encoding|,
+// return it as a CFStringRef.  Returns NULL on failure.
+template<typename StringType>
+static CFStringRef STLStringToCFStringWithEncodingsT(
+    const StringType& in,
+    CFStringEncoding in_encoding) {
+  typename StringType::size_type in_length = in.length();
+  if (in_length == 0)
+    return CFSTR("");
+
+  return CFStringCreateWithBytes(kCFAllocatorDefault,
+                                 reinterpret_cast<const UInt8*>(in.data()),
+                                 in_length *
+                                   sizeof(typename StringType::value_type),
+                                 in_encoding,
+                                 false);
+}
+
+// Specify the byte ordering explicitly, otherwise CFString will be confused
+// when strings don't carry BOMs, as they typically won't.
+static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8;
+#ifdef __BIG_ENDIAN__
+static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16BE;
+static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32BE;
+#elif defined(__LITTLE_ENDIAN__)
+static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16LE;
+static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32LE;
+#endif  // __LITTLE_ENDIAN__
+
+}  // namespace
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToUTF8(const std::wstring& wide) {
+  return STLStringToSTLStringWithEncodingsT<std::wstring, std::string>(
+      wide, kWideStringEncoding, kNarrowStringEncoding);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+  return STLStringToSTLStringWithEncodingsT<StringPiece, std::wstring>(
+      utf8, kNarrowStringEncoding, kWideStringEncoding);
+}
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  return SysWideToUTF8(wide);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  return SysUTF8ToWide(native_mb);
+}
+
+CFStringRef SysUTF8ToCFStringRef(const std::string& utf8) {
+  return STLStringToCFStringWithEncodingsT(utf8, kNarrowStringEncoding);
+}
+
+CFStringRef SysUTF16ToCFStringRef(const string16& utf16) {
+  return STLStringToCFStringWithEncodingsT(utf16, kMediumStringEncoding);
+}
+
+NSString* SysUTF8ToNSString(const std::string& utf8) {
+  return (NSString*)base::mac::CFTypeRefToNSObjectAutorelease(
+      SysUTF8ToCFStringRef(utf8));
+}
+
+NSString* SysUTF16ToNSString(const string16& utf16) {
+  return (NSString*)base::mac::CFTypeRefToNSObjectAutorelease(
+      SysUTF16ToCFStringRef(utf16));
+}
+
+std::string SysCFStringRefToUTF8(CFStringRef ref) {
+  return CFStringToSTLStringWithEncodingT<std::string>(ref,
+                                                       kNarrowStringEncoding);
+}
+
+string16 SysCFStringRefToUTF16(CFStringRef ref) {
+  return CFStringToSTLStringWithEncodingT<string16>(ref,
+                                                    kMediumStringEncoding);
+}
+
+std::string SysNSStringToUTF8(NSString* nsstring) {
+  if (!nsstring)
+    return std::string();
+  return SysCFStringRefToUTF8(reinterpret_cast<CFStringRef>(nsstring));
+}
+
+string16 SysNSStringToUTF16(NSString* nsstring) {
+  if (!nsstring)
+    return string16();
+  return SysCFStringRefToUTF16(reinterpret_cast<CFStringRef>(nsstring));
+}
+
+}  // namespace base
diff --git a/base/sys_string_conversions_mac_unittest.mm b/base/sys_string_conversions_mac_unittest.mm
new file mode 100644
index 0000000..8b0ac88
--- /dev/null
+++ b/base/sys_string_conversions_mac_unittest.mm
@@ -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.
+
+#import <Foundation/Foundation.h>
+
+#include "base/string16.h"
+#include "base/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SysStrings, ConversionsFromNSString) {
+  EXPECT_STREQ("Hello, world!",
+               base::SysNSStringToUTF8(@"Hello, world!").c_str());
+
+  // Conversions should be able to handle a NULL value without crashing.
+  EXPECT_STREQ("", base::SysNSStringToUTF8(nil).c_str());
+  EXPECT_EQ(string16(), base::SysNSStringToUTF16(nil));
+}
diff --git a/base/sys_string_conversions_posix.cc b/base/sys_string_conversions_posix.cc
new file mode 100644
index 0000000..a2bf52a
--- /dev/null
+++ b/base/sys_string_conversions_posix.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_string_conversions.h"
+
+#include <wchar.h>
+
+#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+std::string SysWideToUTF8(const std::wstring& wide) {
+  // In theory this should be using the system-provided conversion rather
+  // than our ICU, but this will do for now.
+  return WideToUTF8(wide);
+}
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+  // In theory this should be using the system-provided conversion rather
+  // than our ICU, but this will do for now.
+  std::wstring out;
+  UTF8ToWide(utf8.data(), utf8.size(), &out);
+  return out;
+}
+
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+// TODO(port): Consider reverting the OS_ANDROID when we have wcrtomb()
+// support and a better understanding of what calls these routines.
+
+// ChromeOS always runs in UTF-8 locale.
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  return WideToUTF8(wide);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  return SysUTF8ToWide(native_mb);
+}
+
+#else
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  mbstate_t ps;
+
+  // Calculate the number of multi-byte characters.  We walk through the string
+  // without writing the output, counting the number of multi-byte characters.
+  size_t num_out_chars = 0;
+  memset(&ps, 0, sizeof(ps));
+  for (size_t i = 0; i < wide.size(); ++i) {
+    const wchar_t src = wide[i];
+    // Use a temp buffer since calling wcrtomb with an output of NULL does not
+    // calculate the output length.
+    char buf[16];
+    // Skip NULLs to avoid wcrtomb's special handling of them.
+    size_t res = src ? wcrtomb(buf, src, &ps) : 0;
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-1):
+        return std::string();
+        break;
+      case 0:
+        // We hit an embedded null byte, keep going.
+        ++num_out_chars;
+        break;
+      default:
+        num_out_chars += res;
+        break;
+    }
+  }
+
+  if (num_out_chars == 0)
+    return std::string();
+
+  std::string out;
+  out.resize(num_out_chars);
+
+  // We walk the input string again, with |i| tracking the index of the
+  // wide input, and |j| tracking the multi-byte output.
+  memset(&ps, 0, sizeof(ps));
+  for (size_t i = 0, j = 0; i < wide.size(); ++i) {
+    const wchar_t src = wide[i];
+    // We don't want wcrtomb to do its funkiness for embedded NULLs.
+    size_t res = src ? wcrtomb(&out[j], src, &ps) : 0;
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-1):
+        return std::string();
+        break;
+      case 0:
+        // We hit an embedded null byte, keep going.
+        ++j;  // Output is already zeroed.
+        break;
+      default:
+        j += res;
+        break;
+    }
+  }
+
+  return out;
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  mbstate_t ps;
+
+  // Calculate the number of wide characters.  We walk through the string
+  // without writing the output, counting the number of wide characters.
+  size_t num_out_chars = 0;
+  memset(&ps, 0, sizeof(ps));
+  for (size_t i = 0; i < native_mb.size(); ) {
+    const char* src = native_mb.data() + i;
+    size_t res = mbrtowc(NULL, src, native_mb.size() - i, &ps);
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-2):
+      case static_cast<size_t>(-1):
+        return std::wstring();
+        break;
+      case 0:
+        // We hit an embedded null byte, keep going.
+        i += 1;  // Fall through.
+      default:
+        i += res;
+        ++num_out_chars;
+        break;
+    }
+  }
+
+  if (num_out_chars == 0)
+    return std::wstring();
+
+  std::wstring out;
+  out.resize(num_out_chars);
+
+  memset(&ps, 0, sizeof(ps));  // Clear the shift state.
+  // We walk the input string again, with |i| tracking the index of the
+  // multi-byte input, and |j| tracking the wide output.
+  for (size_t i = 0, j = 0; i < native_mb.size(); ++j) {
+    const char* src = native_mb.data() + i;
+    wchar_t* dst = &out[j];
+    size_t res = mbrtowc(dst, src, native_mb.size() - i, &ps);
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-2):
+      case static_cast<size_t>(-1):
+        return std::wstring();
+        break;
+      case 0:
+        i += 1;  // Skip null byte.
+        break;
+      default:
+        i += res;
+        break;
+    }
+  }
+
+  return out;
+}
+
+#endif  // OS_CHROMEOS
+
+}  // namespace base
diff --git a/base/sys_string_conversions_unittest.cc b/base/sys_string_conversions_unittest.cc
new file mode 100644
index 0000000..a3393ba
--- /dev/null
+++ b/base/sys_string_conversions_unittest.cc
@@ -0,0 +1,188 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/string_piece.h"
+#include "base/test/scoped_locale.h"
+#include "base/utf_string_conversions.h"
+#include "base/sys_string_conversions.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
+
+TEST(SysStrings, SysWideToUTF8) {
+  using base::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) {
+  using base::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) {
+  using base::SysWideToNativeMB;
+  base::ScopedLocale locale("en_US.utf-8");
+  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) {
+  using base::SysNativeMBToWide;
+  base::ScopedLocale locale("en_US.utf-8");
+  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) {
+  base::ScopedLocale locale("en_US.utf-8");
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::wstring wide = kConvertRoundtripCases[i];
+    std::wstring trip = base::SysNativeMBToWide(base::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 = base::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(base::SysWideToNativeMB(wide));
+    EXPECT_EQ(wide.size(), trip.size());
+    EXPECT_EQ(wide, trip);
+  }
+}
+#endif  // OS_LINUX
diff --git a/base/sys_string_conversions_win.cc b/base/sys_string_conversions_win.cc
new file mode 100644
index 0000000..8b2367b
--- /dev/null
+++ b/base/sys_string_conversions_win.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_string_conversions.h"
+
+#include <windows.h>
+
+#include "base/string_piece.h"
+
+namespace base {
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToUTF8(const std::wstring& wide) {
+  return SysWideToMultiByte(wide, CP_UTF8);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+  return SysMultiByteToWide(utf8, CP_UTF8);
+}
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  return SysWideToMultiByte(wide, CP_ACP);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  return SysMultiByteToWide(native_mb, CP_ACP);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysMultiByteToWide(const StringPiece& mb, uint32 code_page) {
+  if (mb.empty())
+    return std::wstring();
+
+  int mb_length = static_cast<int>(mb.length());
+  // Compute the length of the buffer.
+  int charcount = MultiByteToWideChar(code_page, 0,
+                                      mb.data(), mb_length, NULL, 0);
+  if (charcount == 0)
+    return std::wstring();
+
+  std::wstring wide;
+  wide.resize(charcount);
+  MultiByteToWideChar(code_page, 0, mb.data(), mb_length, &wide[0], charcount);
+
+  return wide;
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToMultiByte(const std::wstring& wide, uint32 code_page) {
+  int wide_length = static_cast<int>(wide.length());
+  if (wide_length == 0)
+    return std::string();
+
+  // Compute the length of the buffer we'll need.
+  int charcount = WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
+                                      NULL, 0, NULL, NULL);
+  if (charcount == 0)
+    return std::string();
+
+  std::string mb;
+  mb.resize(charcount);
+  WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
+                      &mb[0], charcount, NULL, NULL);
+
+  return mb;
+}
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor.cc b/base/system_monitor/system_monitor.cc
new file mode 100644
index 0000000..2616275
--- /dev/null
+++ b/base/system_monitor/system_monitor.cc
@@ -0,0 +1,202 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/system_monitor/system_monitor.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/stl_util.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+static SystemMonitor* g_system_monitor = NULL;
+
+#if defined(ENABLE_BATTERY_MONITORING)
+// The amount of time (in ms) to wait before running the initial
+// battery check.
+static int kDelayedBatteryCheckMs = 10 * 1000;
+#endif  // defined(ENABLE_BATTERY_MONITORING)
+
+SystemMonitor::RemovableStorageInfo::RemovableStorageInfo() {
+}
+
+SystemMonitor::RemovableStorageInfo::RemovableStorageInfo(
+    const std::string& id,
+    const string16& device_name,
+    const FilePath::StringType& device_location)
+    : device_id(id),
+      name(device_name),
+      location(device_location) {
+}
+
+SystemMonitor::SystemMonitor()
+    : power_observer_list_(new ObserverListThreadSafe<PowerObserver>()),
+      devices_changed_observer_list_(
+          new ObserverListThreadSafe<DevicesChangedObserver>()),
+      battery_in_use_(false),
+      suspended_(false) {
+  DCHECK(!g_system_monitor);
+  g_system_monitor = this;
+
+  DCHECK(MessageLoop::current());
+#if defined(ENABLE_BATTERY_MONITORING)
+  delayed_battery_check_.Start(FROM_HERE,
+      base::TimeDelta::FromMilliseconds(kDelayedBatteryCheckMs), this,
+      &SystemMonitor::BatteryCheck);
+#endif  // defined(ENABLE_BATTERY_MONITORING)
+#if defined(OS_MACOSX)
+  PlatformInit();
+#endif
+}
+
+SystemMonitor::~SystemMonitor() {
+#if defined(OS_MACOSX)
+  PlatformDestroy();
+#endif
+  DCHECK_EQ(this, g_system_monitor);
+  g_system_monitor = NULL;
+}
+
+// static
+SystemMonitor* SystemMonitor::Get() {
+  return g_system_monitor;
+}
+
+void SystemMonitor::ProcessPowerMessage(PowerEvent event_id) {
+  // Suppress duplicate notifications.  Some platforms may
+  // send multiple notifications of the same event.
+  switch (event_id) {
+    case POWER_STATE_EVENT:
+      {
+        bool on_battery = IsBatteryPower();
+        if (on_battery != battery_in_use_) {
+          battery_in_use_ = on_battery;
+          NotifyPowerStateChange();
+        }
+      }
+      break;
+    case RESUME_EVENT:
+      if (suspended_) {
+        suspended_ = false;
+        NotifyResume();
+      }
+      break;
+    case SUSPEND_EVENT:
+      if (!suspended_) {
+        suspended_ = true;
+        NotifySuspend();
+      }
+      break;
+  }
+}
+
+void SystemMonitor::ProcessDevicesChanged(DeviceType device_type) {
+  NotifyDevicesChanged(device_type);
+}
+
+void SystemMonitor::ProcessRemovableStorageAttached(
+    const std::string& id,
+    const string16& name,
+    const FilePath::StringType& location) {
+  {
+    base::AutoLock lock(removable_storage_lock_);
+    if (ContainsKey(removable_storage_map_, id)) {
+      // This can happen if our unique id scheme fails. Ignore the incoming
+      // non-unique attachment.
+      return;
+    }
+    RemovableStorageInfo info(id, name, location);
+    removable_storage_map_.insert(std::make_pair(id, info));
+  }
+  NotifyRemovableStorageAttached(id, name, location);
+}
+
+void SystemMonitor::ProcessRemovableStorageDetached(const std::string& id) {
+  {
+    base::AutoLock lock(removable_storage_lock_);
+    RemovableStorageMap::iterator it = removable_storage_map_.find(id);
+    if (it == removable_storage_map_.end())
+      return;
+    removable_storage_map_.erase(it);
+  }
+  NotifyRemovableStorageDetached(id);
+}
+
+std::vector<SystemMonitor::RemovableStorageInfo>
+SystemMonitor::GetAttachedRemovableStorage() const {
+  std::vector<RemovableStorageInfo> results;
+
+  base::AutoLock lock(removable_storage_lock_);
+  for (RemovableStorageMap::const_iterator it = removable_storage_map_.begin();
+       it != removable_storage_map_.end();
+       ++it) {
+    results.push_back(it->second);
+  }
+  return results;
+}
+
+void SystemMonitor::AddPowerObserver(PowerObserver* obs) {
+  power_observer_list_->AddObserver(obs);
+}
+
+void SystemMonitor::RemovePowerObserver(PowerObserver* obs) {
+  power_observer_list_->RemoveObserver(obs);
+}
+
+void SystemMonitor::AddDevicesChangedObserver(DevicesChangedObserver* obs) {
+  devices_changed_observer_list_->AddObserver(obs);
+}
+
+void SystemMonitor::RemoveDevicesChangedObserver(DevicesChangedObserver* obs) {
+  devices_changed_observer_list_->RemoveObserver(obs);
+}
+
+void SystemMonitor::NotifyDevicesChanged(DeviceType device_type) {
+  DVLOG(1) << "DevicesChanged with device type " << device_type;
+  devices_changed_observer_list_->Notify(
+      &DevicesChangedObserver::OnDevicesChanged, device_type);
+}
+
+void SystemMonitor::NotifyRemovableStorageAttached(
+    const std::string& id,
+    const string16& name,
+    const FilePath::StringType& location) {
+  DVLOG(1) << "RemovableStorageAttached with name " << UTF16ToUTF8(name)
+           << " and id " << id;
+  devices_changed_observer_list_->Notify(
+    &DevicesChangedObserver::OnRemovableStorageAttached, id, name, location);
+}
+
+void SystemMonitor::NotifyRemovableStorageDetached(const std::string& id) {
+  DVLOG(1) << "RemovableStorageDetached for id " << id;
+  devices_changed_observer_list_->Notify(
+    &DevicesChangedObserver::OnRemovableStorageDetached, id);
+}
+
+void SystemMonitor::NotifyPowerStateChange() {
+  DVLOG(1) << "PowerStateChange: " << (BatteryPower() ? "On" : "Off")
+           << " battery";
+  power_observer_list_->Notify(&PowerObserver::OnPowerStateChange,
+                               BatteryPower());
+}
+
+void SystemMonitor::NotifySuspend() {
+  DVLOG(1) << "Power Suspending";
+  power_observer_list_->Notify(&PowerObserver::OnSuspend);
+}
+
+void SystemMonitor::NotifyResume() {
+  DVLOG(1) << "Power Resuming";
+  power_observer_list_->Notify(&PowerObserver::OnResume);
+}
+
+void SystemMonitor::BatteryCheck() {
+  ProcessPowerMessage(SystemMonitor::POWER_STATE_EVENT);
+}
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor.h b/base/system_monitor/system_monitor.h
new file mode 100644
index 0000000..ea95da8
--- /dev/null
+++ b/base/system_monitor/system_monitor.h
@@ -0,0 +1,237 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
+#define BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/string16.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+
+// Windows HiRes timers drain the battery faster so we need to know the battery
+// status.  This isn't true for other platforms.
+#if defined(OS_WIN)
+#define ENABLE_BATTERY_MONITORING 1
+#else
+#undef ENABLE_BATTERY_MONITORING
+#endif  // !OS_WIN
+
+#include "base/observer_list_threadsafe.h"
+#if defined(ENABLE_BATTERY_MONITORING)
+#include "base/timer.h"
+#endif  // defined(ENABLE_BATTERY_MONITORING)
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <IOKit/IOMessage.h>
+#endif  // OS_MACOSX && !OS_IOS
+
+#if defined(OS_IOS)
+#include <objc/runtime.h>
+#endif  // OS_IOS
+
+namespace base {
+
+// Class for monitoring various system-related subsystems
+// such as power management, network status, etc.
+// TODO(mbelshe):  Add support beyond just power management.
+class BASE_EXPORT SystemMonitor {
+ public:
+  // 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.
+  };
+
+  // Type of devices whose change need to be monitored, such as add/remove.
+  enum DeviceType {
+    DEVTYPE_AUDIO_CAPTURE,  // Audio capture device, e.g., microphone.
+    DEVTYPE_VIDEO_CAPTURE,  // Video capture device, e.g., webcam.
+    DEVTYPE_UNKNOWN,  // Other devices.
+  };
+
+  struct BASE_EXPORT RemovableStorageInfo {
+    RemovableStorageInfo();
+    RemovableStorageInfo(const std::string& id,
+                         const string16& device_name,
+                         const FilePath::StringType& device_location);
+
+    // Unique device id - persists between device attachments.
+    std::string device_id;
+
+    // Human readable removable storage device name.
+    string16 name;
+
+    // Current attached removable storage device location.
+    FilePath::StringType location;
+  };
+
+  // Create SystemMonitor. Only one SystemMonitor instance per application
+  // is allowed.
+  SystemMonitor();
+  ~SystemMonitor();
+
+  // Get the application-wide SystemMonitor (if not present, returns NULL).
+  static SystemMonitor* Get();
+
+#if defined(OS_MACOSX)
+  // Allocate system resources needed by the SystemMonitor 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
+
+  // Returns information for attached removable storage.
+  std::vector<RemovableStorageInfo> GetAttachedRemovableStorage() const;
+
+  //
+  // Power-related APIs
+  //
+
+  // Is the computer currently on battery power.
+  // Can be called on any thread.
+  bool BatteryPower() const {
+    // Using a lock here is not necessary for just a bool.
+    return battery_in_use_;
+  }
+
+  // Callbacks will be called on the thread which creates the SystemMonitor.
+  // During the callback, Add/RemoveObserver will block until the callbacks
+  // are finished. Observers should implement quick callback functions; if
+  // lengthy operations are needed, the observer should take care to invoke
+  // the operation on an appropriate thread.
+  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() {}
+  };
+
+  class BASE_EXPORT DevicesChangedObserver {
+   public:
+    // Notification that the devices connected to the system have changed.
+    // This is only implemented on Windows currently.
+    virtual void OnDevicesChanged(DeviceType device_type) {}
+
+    // When a removable storage device is attached or detached, one of these
+    // two events is triggered.
+    virtual void OnRemovableStorageAttached(
+        const std::string& id,
+        const string16& name,
+        const FilePath::StringType& location) {}
+    virtual void OnRemovableStorageDetached(const std::string& id) {}
+
+   protected:
+    virtual ~DevicesChangedObserver() {}
+  };
+
+  // Add a new observer.
+  // Can be called from any thread.
+  // Must not be called from within a notification callback.
+  void AddPowerObserver(PowerObserver* obs);
+  void AddDevicesChangedObserver(DevicesChangedObserver* obs);
+
+  // Remove an existing observer.
+  // Can be called from any thread.
+  // Must not be called from within a notification callback.
+  void RemovePowerObserver(PowerObserver* obs);
+  void RemoveDevicesChangedObserver(DevicesChangedObserver* obs);
+
+  // The ProcessFoo() style methods are a broken pattern and should not
+  // be copied. Any significant addition to this class is blocked on
+  // refactoring to improve the state of affairs. See http://crbug.com/149059
+
+#if defined(OS_WIN)
+  // Windows-specific handling of a WM_POWERBROADCAST message.
+  // Embedders of this API should hook their top-level window
+  // message loop and forward WM_POWERBROADCAST through this call.
+  void ProcessWmPowerBroadcastMessage(int event_id);
+#endif
+
+  // Cross-platform handling of a power event.
+  void ProcessPowerMessage(PowerEvent event_id);
+
+  // Cross-platform handling of a device change event.
+  void ProcessDevicesChanged(DeviceType device_type);
+  void ProcessRemovableStorageAttached(const std::string& id,
+                                       const string16& name,
+                                       const FilePath::StringType& location);
+  void ProcessRemovableStorageDetached(const std::string& id);
+
+ private:
+  // Mapping of unique device id to device info tuple.
+  typedef std::map<std::string, RemovableStorageInfo> RemovableStorageMap;
+
+#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 IsBatteryPower();
+
+  // Checks the battery status and notifies observers if the battery
+  // status has changed.
+  void BatteryCheck();
+
+  // Functions to trigger notifications.
+  void NotifyDevicesChanged(DeviceType device_type);
+  void NotifyRemovableStorageAttached(const std::string& id,
+                                      const string16& name,
+                                      const FilePath::StringType& location);
+  void NotifyRemovableStorageDetached(const std::string& id);
+  void NotifyPowerStateChange();
+  void NotifySuspend();
+  void NotifyResume();
+
+  scoped_refptr<ObserverListThreadSafe<PowerObserver> > power_observer_list_;
+  scoped_refptr<ObserverListThreadSafe<DevicesChangedObserver> >
+      devices_changed_observer_list_;
+  bool battery_in_use_;
+  bool suspended_;
+
+#if defined(ENABLE_BATTERY_MONITORING)
+  base::OneShotTimer<SystemMonitor> delayed_battery_check_;
+#endif
+
+#if defined(OS_IOS)
+  // Holds pointers to system event notification observers.
+  std::vector<id> notification_observers_;
+#endif
+
+  // For manipulating removable_storage_map_ structure.
+  mutable base::Lock removable_storage_lock_;
+  // Map of all the attached removable storage devices.
+  RemovableStorageMap removable_storage_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMonitor);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
diff --git a/base/system_monitor/system_monitor_android.cc b/base/system_monitor/system_monitor_android.cc
new file mode 100644
index 0000000..4e1a16b
--- /dev/null
+++ b/base/system_monitor/system_monitor_android.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/system_monitor/system_monitor.h"
+#include "jni/SystemMonitor_jni.h"
+
+namespace base {
+
+namespace android {
+
+// Native implementation of SystemMonitor.java.
+void OnBatteryChargingChanged(JNIEnv* env,
+                              jclass clazz) {
+  SystemMonitor::Get()->ProcessPowerMessage(SystemMonitor::POWER_STATE_EVENT);
+}
+
+}  // namespace android
+
+bool SystemMonitor::IsBatteryPower() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return base::android::Java_SystemMonitor_isBatteryPower(env);
+}
+
+bool RegisterSystemMonitor(JNIEnv* env) {
+  return base::android::RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor_android.h b/base/system_monitor/system_monitor_android.h
new file mode 100644
index 0000000..9f60560
--- /dev/null
+++ b/base/system_monitor/system_monitor_android.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_ANDROID_H_
+#define BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_ANDROID_H_
+
+#include <jni.h>
+
+namespace base {
+
+// Registers the JNI bindings for SystemMonitor.
+bool RegisterSystemMonitor(JNIEnv* env);
+
+}  // namespace base
+
+#endif  // BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_ANDROID_H_
diff --git a/base/system_monitor/system_monitor_ios.mm b/base/system_monitor/system_monitor_ios.mm
new file mode 100644
index 0000000..f3251b6
--- /dev/null
+++ b/base/system_monitor/system_monitor_ios.mm
@@ -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/system_monitor/system_monitor.h"
+
+#import <UIKit/UIKit.h>
+
+namespace base {
+
+void SystemMonitor::PlatformInit() {
+  NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+  id foreground =
+      [nc addObserverForName:UIApplicationWillEnterForegroundNotification
+                      object:nil
+                       queue:nil
+                  usingBlock:^(NSNotification* notification) {
+                      ProcessPowerMessage(RESUME_EVENT);
+                  }];
+  id background =
+      [nc addObserverForName:UIApplicationDidEnterBackgroundNotification
+                      object:nil
+                       queue:nil
+                  usingBlock:^(NSNotification* notification) {
+                      ProcessPowerMessage(SUSPEND_EVENT);
+                  }];
+  notification_observers_.push_back(foreground);
+  notification_observers_.push_back(background);
+}
+
+void SystemMonitor::PlatformDestroy() {
+  NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+  for (std::vector<id>::iterator it = notification_observers_.begin();
+       it != notification_observers_.end(); ++it) {
+    [nc removeObserver:*it];
+  }
+  notification_observers_.clear();
+}
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor_mac.mm b/base/system_monitor/system_monitor_mac.mm
new file mode 100644
index 0000000..d0dbaab
--- /dev/null
+++ b/base/system_monitor/system_monitor_mac.mm
@@ -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.
+
+// Implementation based on sample code from
+// http://developer.apple.com/library/mac/#qa/qa1340/_index.html.
+
+#include "base/system_monitor/system_monitor.h"
+
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <IOKit/IOMessage.h>
+
+namespace base {
+
+namespace {
+
+io_connect_t g_system_power_io_port = 0;
+IONotificationPortRef g_notification_port_ref = 0;
+io_object_t g_notifier_object = 0;
+
+void SystemPowerEventCallback(void*,
+                              io_service_t service,
+                              natural_t message_type,
+                              void* message_argument) {
+  SystemMonitor* sys_monitor = SystemMonitor::Get();
+  DCHECK(sys_monitor);
+  switch (message_type) {
+    case kIOMessageSystemWillSleep:
+      sys_monitor->ProcessPowerMessage(SystemMonitor::SUSPEND_EVENT);
+      IOAllowPowerChange(g_system_power_io_port,
+          reinterpret_cast<intptr_t>(message_argument));
+      break;
+
+    case kIOMessageSystemWillPowerOn:
+      sys_monitor->ProcessPowerMessage(SystemMonitor::RESUME_EVENT);
+      break;
+  }
+}
+
+}  // namespace
+
+// The reason we can't include this code in the constructor is because
+// PlatformInit() requires an active runloop and the IO port needs to be
+// allocated at sandbox initialization time, before there's a runloop.
+// See crbug.com/83783 .
+
+// static
+void SystemMonitor::AllocateSystemIOPorts() {
+  DCHECK_EQ(g_system_power_io_port, 0u);
+
+  // Notification port allocated by IORegisterForSystemPower.
+
+  g_system_power_io_port = IORegisterForSystemPower(
+      NULL, &g_notification_port_ref, SystemPowerEventCallback,
+      &g_notifier_object);
+
+  DCHECK_NE(g_system_power_io_port, 0u);
+}
+
+void SystemMonitor::PlatformInit() {
+  // Need to call AllocateSystemIOPorts() before constructing a SystemMonitor
+  // object.
+  DCHECK_NE(g_system_power_io_port, 0u);
+  if (g_system_power_io_port == 0)
+    return;
+
+  // Add the notification port to the application runloop
+  CFRunLoopAddSource(
+      CFRunLoopGetCurrent(),
+      IONotificationPortGetRunLoopSource(g_notification_port_ref),
+      kCFRunLoopCommonModes);
+}
+
+void SystemMonitor::PlatformDestroy() {
+  DCHECK_NE(g_system_power_io_port, 0u);
+  if (g_system_power_io_port == 0)
+    return;
+
+  // Remove the sleep notification port from the application runloop
+  CFRunLoopRemoveSource(
+      CFRunLoopGetCurrent(),
+      IONotificationPortGetRunLoopSource(g_notification_port_ref),
+      kCFRunLoopCommonModes);
+
+  // Deregister for system sleep notifications
+  IODeregisterForSystemPower(&g_notifier_object);
+
+  // IORegisterForSystemPower implicitly opens the Root Power Domain IOService,
+  // so we close it here.
+  IOServiceClose(g_system_power_io_port);
+
+  g_system_power_io_port = 0;
+
+  // Destroy the notification port allocated by IORegisterForSystemPower.
+  IONotificationPortDestroy(g_notification_port_ref);
+}
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor_posix.cc b/base/system_monitor/system_monitor_posix.cc
new file mode 100644
index 0000000..6cf01bf
--- /dev/null
+++ b/base/system_monitor/system_monitor_posix.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/system_monitor/system_monitor.h"
+
+namespace base {
+
+bool SystemMonitor::IsBatteryPower() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor_unittest.cc b/base/system_monitor/system_monitor_unittest.cc
new file mode 100644
index 0000000..10bd7e7
--- /dev/null
+++ b/base/system_monitor/system_monitor_unittest.cc
@@ -0,0 +1,202 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/system_monitor/system_monitor.h"
+
+#include "base/file_path.h"
+#include "base/message_loop.h"
+#include "base/test/mock_devices_changed_observer.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class PowerTest : public SystemMonitor::PowerObserver {
+ public:
+  PowerTest()
+      : power_state_changes_(0),
+        suspends_(0),
+        resumes_(0) {
+  }
+
+  // PowerObserver callbacks.
+  virtual void OnPowerStateChange(bool on_battery_power) OVERRIDE {
+    power_state_changes_++;
+  }
+
+  virtual void OnSuspend() OVERRIDE {
+    suspends_++;
+  }
+
+  virtual void OnResume() OVERRIDE {
+    resumes_++;
+  }
+
+  // Test status counts.
+  int power_state_changes() { return power_state_changes_; }
+  int suspends() { return suspends_; }
+  int resumes() { return resumes_; }
+
+ private:
+  int power_state_changes_;  // Count of OnPowerStateChange notifications.
+  int suspends_;  // Count of OnSuspend notifications.
+  int resumes_;  // Count of OnResume notifications.
+};
+
+class SystemMonitorTest : public testing::Test {
+ protected:
+  SystemMonitorTest() {
+#if defined(OS_MACOSX)
+    // This needs to happen before SystemMonitor's ctor.
+    SystemMonitor::AllocateSystemIOPorts();
+#endif
+    system_monitor_.reset(new SystemMonitor);
+  }
+  virtual ~SystemMonitorTest() {}
+
+  MessageLoop message_loop_;
+  scoped_ptr<SystemMonitor> system_monitor_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMonitorTest);
+};
+
+TEST_F(SystemMonitorTest, PowerNotifications) {
+  const int kObservers = 5;
+
+  PowerTest test[kObservers];
+  for (int index = 0; index < kObservers; ++index)
+    system_monitor_->AddPowerObserver(&test[index]);
+
+  // Send a bunch of power changes.  Since the battery power hasn't
+  // actually changed, we shouldn't get notifications.
+  for (int index = 0; index < 5; index++) {
+    system_monitor_->ProcessPowerMessage(SystemMonitor::POWER_STATE_EVENT);
+    EXPECT_EQ(test[0].power_state_changes(), 0);
+  }
+
+  // Sending resume when not suspended should have no effect.
+  system_monitor_->ProcessPowerMessage(SystemMonitor::RESUME_EVENT);
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(test[0].resumes(), 0);
+
+  // Pretend we suspended.
+  system_monitor_->ProcessPowerMessage(SystemMonitor::SUSPEND_EVENT);
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(test[0].suspends(), 1);
+
+  // Send a second suspend notification.  This should be suppressed.
+  system_monitor_->ProcessPowerMessage(SystemMonitor::SUSPEND_EVENT);
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(test[0].suspends(), 1);
+
+  // Pretend we were awakened.
+  system_monitor_->ProcessPowerMessage(SystemMonitor::RESUME_EVENT);
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(test[0].resumes(), 1);
+
+  // Send a duplicate resume notification.  This should be suppressed.
+  system_monitor_->ProcessPowerMessage(SystemMonitor::RESUME_EVENT);
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(test[0].resumes(), 1);
+}
+
+TEST_F(SystemMonitorTest, DeviceChangeNotifications) {
+  const int kObservers = 5;
+  const string16 kDeviceName = ASCIIToUTF16("media device");
+  const std::string kDeviceId1 = "1";
+  const std::string kDeviceId2 = "2";
+
+  testing::Sequence mock_sequencer[kObservers];
+  MockDevicesChangedObserver observers[kObservers];
+  for (int index = 0; index < kObservers; ++index) {
+    system_monitor_->AddDevicesChangedObserver(&observers[index]);
+
+    EXPECT_CALL(observers[index],
+                OnDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN))
+        .Times(3)
+        .InSequence(mock_sequencer[index]);
+    EXPECT_CALL(observers[index], OnRemovableStorageAttached(kDeviceId1,
+                                                             kDeviceName,
+                                                             testing::_))
+        .InSequence(mock_sequencer[index]);
+    EXPECT_CALL(observers[index], OnRemovableStorageDetached(kDeviceId1))
+        .InSequence(mock_sequencer[index]);
+    EXPECT_CALL(observers[index], OnRemovableStorageDetached(kDeviceId2))
+        .Times(0).InSequence(mock_sequencer[index]);
+  }
+
+  system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN);
+  message_loop_.RunUntilIdle();
+
+  system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN);
+  system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN);
+  message_loop_.RunUntilIdle();
+
+  system_monitor_->ProcessRemovableStorageAttached(kDeviceId1,
+                                                   kDeviceName,
+                                                   FILE_PATH_LITERAL("path"));
+  message_loop_.RunUntilIdle();
+
+  system_monitor_->ProcessRemovableStorageDetached(kDeviceId1);
+  system_monitor_->ProcessRemovableStorageDetached(kDeviceId2);
+  message_loop_.RunUntilIdle();
+}
+
+TEST_F(SystemMonitorTest, GetAttachedRemovableStorageEmpty) {
+  std::vector<SystemMonitor::RemovableStorageInfo> devices =
+      system_monitor_->GetAttachedRemovableStorage();
+  EXPECT_EQ(0U, devices.size());
+}
+
+TEST_F(SystemMonitorTest, GetAttachedRemovableStorageAttachDetach) {
+  const std::string kDeviceId1 = "42";
+  const string16 kDeviceName1 = ASCIIToUTF16("test");
+  const FilePath kDevicePath1(FILE_PATH_LITERAL("/testfoo"));
+  system_monitor_->ProcessRemovableStorageAttached(kDeviceId1,
+                                                   kDeviceName1,
+                                                   kDevicePath1.value());
+  message_loop_.RunUntilIdle();
+  std::vector<SystemMonitor::RemovableStorageInfo> devices =
+      system_monitor_->GetAttachedRemovableStorage();
+  ASSERT_EQ(1U, devices.size());
+  EXPECT_EQ(kDeviceId1, devices[0].device_id);
+  EXPECT_EQ(kDeviceName1, devices[0].name);
+  EXPECT_EQ(kDevicePath1.value(), devices[0].location);
+
+  const std::string kDeviceId2 = "44";
+  const string16 kDeviceName2 = ASCIIToUTF16("test2");
+  const FilePath kDevicePath2(FILE_PATH_LITERAL("/testbar"));
+  system_monitor_->ProcessRemovableStorageAttached(kDeviceId2,
+                                                   kDeviceName2,
+                                                   kDevicePath2.value());
+  message_loop_.RunUntilIdle();
+  devices = system_monitor_->GetAttachedRemovableStorage();
+  ASSERT_EQ(2U, devices.size());
+  EXPECT_EQ(kDeviceId1, devices[0].device_id);
+  EXPECT_EQ(kDeviceName1, devices[0].name);
+  EXPECT_EQ(kDevicePath1.value(), devices[0].location);
+  EXPECT_EQ(kDeviceId2, devices[1].device_id);
+  EXPECT_EQ(kDeviceName2, devices[1].name);
+  EXPECT_EQ(kDevicePath2.value(), devices[1].location);
+
+  system_monitor_->ProcessRemovableStorageDetached(kDeviceId1);
+  message_loop_.RunUntilIdle();
+  devices = system_monitor_->GetAttachedRemovableStorage();
+  ASSERT_EQ(1U, devices.size());
+  EXPECT_EQ(kDeviceId2, devices[0].device_id);
+  EXPECT_EQ(kDeviceName2, devices[0].name);
+  EXPECT_EQ(kDevicePath2.value(), devices[0].location);
+
+  system_monitor_->ProcessRemovableStorageDetached(kDeviceId2);
+  message_loop_.RunUntilIdle();
+  devices = system_monitor_->GetAttachedRemovableStorage();
+  EXPECT_EQ(0U, devices.size());
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor_win.cc b/base/system_monitor/system_monitor_win.cc
new file mode 100644
index 0000000..a8cd54a
--- /dev/null
+++ b/base/system_monitor/system_monitor_win.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/system_monitor/system_monitor.h"
+
+namespace base {
+
+void SystemMonitor::ProcessWmPowerBroadcastMessage(int event_id) {
+  PowerEvent power_event;
+  switch (event_id) {
+    case PBT_APMPOWERSTATUSCHANGE:  // The power status changed.
+      power_event = POWER_STATE_EVENT;
+      break;
+    case PBT_APMRESUMEAUTOMATIC:  // Resume from suspend.
+    //case PBT_APMRESUMESUSPEND:  // User-initiated resume from suspend.
+                                  // We don't notify for this latter event
+                                  // because if it occurs it is always sent as a
+                                  // second event after PBT_APMRESUMEAUTOMATIC.
+      power_event = RESUME_EVENT;
+      break;
+    case PBT_APMSUSPEND:  // System has been suspended.
+      power_event = SUSPEND_EVENT;
+      break;
+    default:
+      return;
+
+    // Other Power Events:
+    // PBT_APMBATTERYLOW - removed in Vista.
+    // PBT_APMOEMEVENT - removed in Vista.
+    // PBT_APMQUERYSUSPEND - removed in Vista.
+    // PBT_APMQUERYSUSPENDFAILED - removed in Vista.
+    // PBT_APMRESUMECRITICAL - removed in Vista.
+    // PBT_POWERSETTINGCHANGE - user changed the power settings.
+  }
+  ProcessPowerMessage(power_event);
+}
+
+// Function to query the system to see if it is currently running on
+// battery power.  Returns true if running on battery.
+bool SystemMonitor::IsBatteryPower() {
+  SYSTEM_POWER_STATUS status;
+  if (!GetSystemPowerStatus(&status)) {
+    DLOG(ERROR) << "GetSystemPowerStatus failed: " << GetLastError();
+    return false;
+  }
+  return (status.ACLineStatus == 0);
+}
+
+}  // namespace base
diff --git a/base/task_runner.cc b/base/task_runner.cc
new file mode 100644
index 0000000..b0563d4
--- /dev/null
+++ b/base/task_runner.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/task_runner.h"
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/threading/post_task_and_reply_impl.h"
+
+namespace base {
+
+namespace {
+
+// TODO(akalin): There's only one other implementation of
+// PostTaskAndReplyImpl in WorkerPool.  Investigate whether it'll be
+// possible to merge the two.
+class PostTaskAndReplyTaskRunner : public internal::PostTaskAndReplyImpl {
+ public:
+  PostTaskAndReplyTaskRunner(TaskRunner* destination);
+
+ private:
+  virtual bool PostTask(const tracked_objects::Location& from_here,
+                        const Closure& task) OVERRIDE;
+
+  // Non-owning.
+  TaskRunner* destination_;
+};
+
+PostTaskAndReplyTaskRunner::PostTaskAndReplyTaskRunner(
+    TaskRunner* destination) : destination_(destination) {
+  DCHECK(destination_);
+}
+
+bool PostTaskAndReplyTaskRunner::PostTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return destination_->PostTask(from_here, task);
+}
+
+}  // namespace
+
+bool TaskRunner::PostTask(const tracked_objects::Location& from_here,
+                          const Closure& task) {
+  return PostDelayedTask(from_here, task, base::TimeDelta());
+}
+
+bool TaskRunner::PostTaskAndReply(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    const Closure& reply) {
+  return PostTaskAndReplyTaskRunner(this).PostTaskAndReply(
+      from_here, task, reply);
+}
+
+TaskRunner::TaskRunner() {}
+
+TaskRunner::~TaskRunner() {}
+
+void TaskRunner::OnDestruct() const {
+  delete this;
+}
+
+void TaskRunnerTraits::Destruct(const TaskRunner* task_runner) {
+  task_runner->OnDestruct();
+}
+
+}  // namespace base
diff --git a/base/task_runner.h b/base/task_runner.h
new file mode 100644
index 0000000..4fbea4d
--- /dev/null
+++ b/base/task_runner.h
@@ -0,0 +1,153 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TASK_RUNNER_H_
+#define BASE_TASK_RUNNER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/time.h"
+
+namespace tracked_objects {
+class Location;
+} // namespace tracked_objects
+
+namespace base {
+
+struct TaskRunnerTraits;
+
+// A TaskRunner is an object that runs posted tasks (in the form of
+// Closure objects).  The TaskRunner interface provides a way of
+// decoupling task posting from the mechanics of how each task will be
+// run.  TaskRunner provides very weak guarantees as to how posted
+// tasks are run (or if they're run at all).  In particular, it only
+// guarantees:
+//
+//   - Posting a task will not run it synchronously.  That is, no
+//     Post*Task method will call task.Run() directly.
+//
+//   - Increasing the delay can only delay when the task gets run.
+//     That is, increasing the delay may not affect when the task gets
+//     run, or it could make it run later than it normally would, but
+//     it won't make it run earlier than it normally would.
+//
+// TaskRunner does not guarantee the order in which posted tasks are
+// run, whether tasks overlap, or whether they're run on a particular
+// thread.  Also it does not guarantee a memory model for shared data
+// between tasks.  (In other words, you should use your own
+// synchronization/locking primitives if you need to share data
+// between tasks.)
+//
+// Implementations of TaskRunner should be thread-safe in that all
+// methods must be safe to call on any thread.  Ownership semantics
+// for TaskRunners are in general not clear, which is why the
+// interface itself is RefCountedThreadSafe.
+//
+// Some theoretical implementations of TaskRunner:
+//
+//   - A TaskRunner that uses a thread pool to run posted tasks.
+//
+//   - A TaskRunner that, for each task, spawns a non-joinable thread
+//     to run that task and immediately quit.
+//
+//   - A TaskRunner that stores the list of posted tasks and has a
+//     method Run() that runs each runnable task in random order.
+class BASE_EXPORT TaskRunner
+    : public RefCountedThreadSafe<TaskRunner, TaskRunnerTraits> {
+ public:
+  // Posts the given task to be run.  Returns true if the task may be
+  // run at some point in the future, and false if the task definitely
+  // will not be run.
+  //
+  // Equivalent to PostDelayedTask(from_here, task, 0).
+  bool PostTask(const tracked_objects::Location& from_here,
+                const Closure& task);
+
+  // Like PostTask, but tries to run the posted task only after
+  // |delay_ms| has passed.
+  //
+  // It is valid for an implementation to ignore |delay_ms|; that is,
+  // to have PostDelayedTask behave the same as PostTask.
+  virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               base::TimeDelta delay) = 0;
+
+  // Returns true if the current thread is a thread on which a task
+  // may be run, and false if no task will be run on the current
+  // thread.
+  //
+  // It is valid for an implementation to always return true, or in
+  // general to use 'true' as a default value.
+  virtual bool RunsTasksOnCurrentThread() const = 0;
+
+  // Posts |task| on the current TaskRunner.  On completion, |reply|
+  // is posted to the thread that called PostTaskAndReply().  Both
+  // |task| and |reply| are guaranteed to be deleted on the thread
+  // from which PostTaskAndReply() is invoked.  This allows objects
+  // that must be deleted on the originating thread to be bound into
+  // the |task| and |reply| Closures.  In particular, it can be useful
+  // to use WeakPtr<> in the |reply| Closure so that the reply
+  // operation can be canceled. See the following pseudo-code:
+  //
+  // class DataBuffer : public RefCountedThreadSafe<DataBuffer> {
+  //  public:
+  //   // Called to add data into a buffer.
+  //   void AddData(void* buf, size_t length);
+  //   ...
+  // };
+  //
+  //
+  // class DataLoader : public SupportsWeakPtr<DataLoader> {
+  //  public:
+  //    void GetData() {
+  //      scoped_refptr<DataBuffer> buffer = new DataBuffer();
+  //      target_thread_.message_loop_proxy()->PostTaskAndReply(
+  //          FROM_HERE,
+  //          base::Bind(&DataBuffer::AddData, buffer),
+  //          base::Bind(&DataLoader::OnDataReceived, AsWeakPtr(), buffer));
+  //    }
+  //
+  //  private:
+  //    void OnDataReceived(scoped_refptr<DataBuffer> buffer) {
+  //      // Do something with buffer.
+  //    }
+  // };
+  //
+  //
+  // Things to notice:
+  //   * Results of |task| are shared with |reply| by binding a shared argument
+  //     (a DataBuffer instance).
+  //   * The DataLoader object has no special thread safety.
+  //   * The DataLoader object can be deleted while |task| is still running,
+  //     and the reply will cancel itself safely because it is bound to a
+  //     WeakPtr<>.
+  bool PostTaskAndReply(const tracked_objects::Location& from_here,
+                        const Closure& task,
+                        const Closure& reply);
+
+ protected:
+  friend struct TaskRunnerTraits;
+
+  // Only the Windows debug build seems to need this: see
+  // http://crbug.com/112250.
+  friend class RefCountedThreadSafe<TaskRunner, TaskRunnerTraits>;
+
+  TaskRunner();
+  virtual ~TaskRunner();
+
+  // Called when this object should be destroyed.  By default simply
+  // deletes |this|, but can be overridden to do something else, like
+  // delete on a certain thread.
+  virtual void OnDestruct() const;
+};
+
+struct BASE_EXPORT TaskRunnerTraits {
+  static void Destruct(const TaskRunner* task_runner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TASK_RUNNER_H_
diff --git a/base/task_runner_util.h b/base/task_runner_util.h
new file mode 100644
index 0000000..d1b9f62
--- /dev/null
+++ b/base/task_runner_util.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TASK_RUNNER_UTIL_H_
+#define BASE_TASK_RUNNER_UTIL_H_
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_internal.h"
+#include "base/logging.h"
+#include "base/task_runner.h"
+
+namespace base {
+
+namespace internal {
+
+// Helper class for TaskRunner::PostTaskAndReplyWithResult.
+template <typename ReturnType>
+void ReturnAsParamAdapter(const Callback<ReturnType(void)>& func,
+                          ReturnType* result) {
+  if (!func.is_null())
+    *result = func.Run();
+}
+
+// Helper class for TaskRunner::PostTaskAndReplyWithResult.
+template <typename ReturnType>
+Closure ReturnAsParam(const Callback<ReturnType(void)>& func,
+                      ReturnType* result) {
+  DCHECK(result);
+  return Bind(&ReturnAsParamAdapter<ReturnType>, func, result);
+}
+
+// Helper class for TaskRunner::PostTaskAndReplyWithResult.
+template <typename ReturnType>
+void ReplyAdapter(const Callback<void(ReturnType)>& callback,
+                  ReturnType* result) {
+  DCHECK(result);
+  if(!callback.is_null())
+    callback.Run(CallbackForward(*result));
+}
+
+// Helper class for TaskRunner::PostTaskAndReplyWithResult.
+template <typename ReturnType, typename OwnedType>
+Closure ReplyHelper(const Callback<void(ReturnType)>& callback,
+                    OwnedType result) {
+  return Bind(&ReplyAdapter<ReturnType>, callback, result);
+}
+
+}  // namespace internal
+
+// When you have these methods
+//
+//   R DoWorkAndReturn();
+//   void Callback(const R& result);
+//
+// and want to call them in a PostTaskAndReply kind of fashion where the
+// result of DoWorkAndReturn is passed to the Callback, you can use
+// PostTaskAndReplyWithResult as in this example:
+//
+// PostTaskAndReplyWithResult(
+//     target_thread_.message_loop_proxy(),
+//     FROM_HERE,
+//     Bind(&DoWorkAndReturn),
+//     Bind(&Callback));
+template <typename ReturnType>
+bool PostTaskAndReplyWithResult(
+    TaskRunner* task_runner,
+    const tracked_objects::Location& from_here,
+    const Callback<ReturnType(void)>& task,
+    const Callback<void(ReturnType)>& reply) {
+  ReturnType* result = new ReturnType;
+  return task_runner->PostTaskAndReply(
+      from_here,
+      internal::ReturnAsParam<ReturnType>(task, result),
+      internal::ReplyHelper(reply, Owned(result)));
+}
+
+}  // namespace base
+
+#endif  // BASE_TASK_RUNNER_UTIL_H_
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc
new file mode 100644
index 0000000..e6430bf
--- /dev/null
+++ b/base/task_runner_util_unittest.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/task_runner_util.h"
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+int ReturnFourtyTwo() {
+  return 42;
+}
+
+void StoreValue(int* destination, int value) {
+  *destination = value;
+}
+
+int g_foo_destruct_count = 0;
+int g_foo_free_count = 0;
+
+struct Foo {
+  ~Foo() {
+    ++g_foo_destruct_count;
+  }
+};
+
+scoped_ptr<Foo> CreateFoo() {
+  return scoped_ptr<Foo>(new Foo);
+}
+
+void ExpectFoo(scoped_ptr<Foo> foo) {
+  EXPECT_TRUE(foo.get());
+  scoped_ptr<Foo> local_foo(foo.Pass());
+  EXPECT_TRUE(local_foo.get());
+  EXPECT_FALSE(foo.get());
+}
+
+struct FreeFooFunctor {
+  void operator()(Foo* foo) const {
+    ++g_foo_free_count;
+    delete foo;
+  };
+};
+
+scoped_ptr_malloc<Foo, FreeFooFunctor> CreateScopedFoo() {
+  return scoped_ptr_malloc<Foo, FreeFooFunctor>(new Foo);
+}
+
+void ExpectScopedFoo(scoped_ptr_malloc<Foo, FreeFooFunctor> foo) {
+  EXPECT_TRUE(foo.get());
+  scoped_ptr_malloc<Foo, FreeFooFunctor> local_foo(foo.Pass());
+  EXPECT_TRUE(local_foo.get());
+  EXPECT_FALSE(foo.get());
+}
+
+}  // namespace
+
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResult) {
+  MessageLoop message_loop;
+  int result = 0;
+
+  PostTaskAndReplyWithResult(
+      message_loop.message_loop_proxy(),
+      FROM_HERE,
+      Bind(&ReturnFourtyTwo),
+      Bind(&StoreValue, &result));
+
+  message_loop.RunUntilIdle();
+
+  EXPECT_EQ(42, result);
+}
+
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassed) {
+  g_foo_destruct_count = 0;
+  g_foo_free_count = 0;
+
+  MessageLoop message_loop;
+
+  PostTaskAndReplyWithResult(
+      message_loop.message_loop_proxy(),
+      FROM_HERE,
+      Bind(&CreateFoo),
+      Bind(&ExpectFoo));
+
+  message_loop.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.message_loop_proxy(),
+      FROM_HERE,
+      Bind(&CreateScopedFoo),
+      Bind(&ExpectScopedFoo));
+
+  message_loop.RunUntilIdle();
+
+  EXPECT_EQ(1, g_foo_destruct_count);
+  EXPECT_EQ(1, g_foo_free_count);
+}
+
+}  // namespace base
diff --git a/base/template_util.h b/base/template_util.h
new file mode 100644
index 0000000..e21d4dc
--- /dev/null
+++ b/base/template_util.h
@@ -0,0 +1,108 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEMPLATE_UTIL_H_
+#define BASE_TEMPLATE_UTIL_H_
+
+#include <cstddef>  // For size_t.
+
+#include "build/build_config.h"
+
+namespace base {
+
+// template definitions from tr1
+
+template<class T, T v>
+struct integral_constant {
+  static const T value = v;
+  typedef T value_type;
+  typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+
+template <class T> struct is_pointer : false_type {};
+template <class T> struct is_pointer<T*> : true_type {};
+
+template <class T, class U> struct is_same : public false_type {};
+template <class T> struct is_same<T,T> : true_type {};
+
+template<class> struct is_array : public false_type {};
+template<class T, size_t n> struct is_array<T[n]> : public true_type {};
+template<class T> struct is_array<T[]> : public true_type {};
+
+template <class T> struct is_non_const_reference : false_type {};
+template <class T> struct is_non_const_reference<T&> : true_type {};
+template <class T> struct is_non_const_reference<const T&> : false_type {};
+
+template <class T> struct is_void : false_type {};
+template <> struct is_void<void> : true_type {};
+
+namespace internal {
+
+// Types YesType and NoType are guaranteed such that sizeof(YesType) <
+// sizeof(NoType).
+typedef char YesType;
+
+struct NoType {
+  YesType dummy[2];
+};
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From.  See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+struct ConvertHelper {
+  template <typename To>
+  static YesType Test(To);
+
+  template <typename To>
+  static NoType Test(...);
+
+  template <typename From>
+  static From& Create();
+};
+
+// Used to determine if a type is a struct/union/class. Inspired by Boost's
+// is_class type_trait implementation.
+struct IsClassHelper {
+  template <typename C>
+  static YesType Test(void(C::*)(void));
+
+  template <typename C>
+  static NoType Test(...);
+};
+
+}  // namespace internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+//
+// Note that if the type is convertible, this will be a true_type REGARDLESS
+// of whether or not the conversion would emit a warning.
+template <typename From, typename To>
+struct is_convertible
+    : integral_constant<bool,
+                        sizeof(internal::ConvertHelper::Test<To>(
+                                   internal::ConvertHelper::Create<From>())) ==
+                        sizeof(internal::YesType)> {
+};
+
+template <typename T>
+struct is_class
+    : integral_constant<bool,
+                        sizeof(internal::IsClassHelper::Test<T>(0)) ==
+                            sizeof(internal::YesType)> {
+};
+
+}  // namespace base
+
+#endif  // BASE_TEMPLATE_UTIL_H_
diff --git a/base/template_util_unittest.cc b/base/template_util_unittest.cc
new file mode 100644
index 0000000..4cfa3e4
--- /dev/null
+++ b/base/template_util_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/template_util.h"
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct AStruct {};
+class AClass {};
+enum AnEnum {};
+
+class Parent {};
+class Child : public Parent {};
+
+// is_pointer<Type>
+COMPILE_ASSERT(!is_pointer<int>::value, IsPointer);
+COMPILE_ASSERT(!is_pointer<int&>::value, IsPointer);
+COMPILE_ASSERT(is_pointer<int*>::value, IsPointer);
+COMPILE_ASSERT(is_pointer<const int*>::value, IsPointer);
+
+// is_array<Type>
+COMPILE_ASSERT(!is_array<int>::value, IsArray);
+COMPILE_ASSERT(!is_array<int*>::value, IsArray);
+COMPILE_ASSERT(!is_array<int(*)[3]>::value, IsArray);
+COMPILE_ASSERT(is_array<int[]>::value, IsArray);
+COMPILE_ASSERT(is_array<const int[]>::value, IsArray);
+COMPILE_ASSERT(is_array<int[3]>::value, IsArray);
+
+// is_non_const_reference<Type>
+COMPILE_ASSERT(!is_non_const_reference<int>::value, IsNonConstReference);
+COMPILE_ASSERT(!is_non_const_reference<const int&>::value, IsNonConstReference);
+COMPILE_ASSERT(is_non_const_reference<int&>::value, IsNonConstReference);
+
+// is_convertible<From, To>
+
+// Extra parens needed to make preprocessor macro parsing happy. Otherwise,
+// it sees the equivalent of:
+//
+//     (is_convertible < Child), (Parent > ::value)
+//
+// Silly C++.
+COMPILE_ASSERT( (is_convertible<Child, Parent>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<Parent, Child>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<Parent, AStruct>::value), IsConvertible);
+COMPILE_ASSERT( (is_convertible<int, double>::value), IsConvertible);
+COMPILE_ASSERT( (is_convertible<int*, void*>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<void*, int*>::value), IsConvertible);
+
+// Array types are an easy corner case.  Make sure to test that
+// it does indeed compile.
+COMPILE_ASSERT(!(is_convertible<int[10], double>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<double, int[10]>::value), IsConvertible);
+COMPILE_ASSERT( (is_convertible<int[10], int*>::value), IsConvertible);
+
+// is_same<Type1, Type2>
+COMPILE_ASSERT(!(is_same<Child, Parent>::value), IsSame);
+COMPILE_ASSERT(!(is_same<Parent, Child>::value), IsSame);
+COMPILE_ASSERT( (is_same<Parent, Parent>::value), IsSame);
+COMPILE_ASSERT( (is_same<int*, int*>::value), IsSame);
+COMPILE_ASSERT( (is_same<int, int>::value), IsSame);
+COMPILE_ASSERT( (is_same<void, void>::value), IsSame);
+COMPILE_ASSERT(!(is_same<int, double>::value), IsSame);
+
+
+// is_class<Type>
+COMPILE_ASSERT(is_class<AStruct>::value, IsClass);
+COMPILE_ASSERT(is_class<AClass>::value, IsClass);
+COMPILE_ASSERT(!is_class<AnEnum>::value, IsClass);
+COMPILE_ASSERT(!is_class<int>::value, IsClass);
+COMPILE_ASSERT(!is_class<char*>::value, IsClass);
+COMPILE_ASSERT(!is_class<int&>::value, IsClass);
+COMPILE_ASSERT(!is_class<char[3]>::value, IsClass);
+
+}  // namespace
+}  // namespace base
diff --git a/base/test/OWNERS b/base/test/OWNERS
new file mode 100644
index 0000000..92ecc88
--- /dev/null
+++ b/base/test/OWNERS
@@ -0,0 +1 @@
+phajdan.jr@chromium.org
diff --git a/base/test/android/OWNERS b/base/test/android/OWNERS
new file mode 100644
index 0000000..737d4e4
--- /dev/null
+++ b/base/test/android/OWNERS
@@ -0,0 +1,5 @@
+jrg@chromium.org
+bulach@chromium.org
+joth@chromium.org
+jcivelli@chromium.org
+yfriedman@chromium.org
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java
new file mode 100644
index 0000000..c2b2ecd
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java
@@ -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.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is for disabled tests.
+ * <p>
+ * Tests with this annotation will not be run on any of the normal bots.
+ * Please note that they might eventually run on a special bot.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DisabledTest {
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java
new file mode 100644
index 0000000..9f8fa93
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is for enormous tests.
+ * <p>
+ * Examples of enormous tests are tests that depend on external web sites or
+ * tests that are long running.
+ * <p>
+ * Such tests are likely NOT reliable enough to run on tree closing bots and
+ * should only be run on FYI bots.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnormousTest {
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java b/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java
new file mode 100644
index 0000000..aa120ea
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java
@@ -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.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The java instrumentation tests are normally fairly large (in terms of
+ * dependencies), and the test suite ends up containing a large amount of
+ * tests that are not trivial to filter / group just by their names.
+ * Instead, we use this annotation: each test should be annotated as:
+ *     @Feature({"Foo", "Bar"})
+ * in order for the test runner scripts to be able to filter and group
+ * them accordingly (for instance, this enable us to run all tests that exercise
+ * feature Foo).
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Feature {
+    /**
+     * @return A list of feature names.
+     */
+    public String[] value();
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java
new file mode 100644
index 0000000..0dc730a
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java
@@ -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.
+
+package org.chromium.base.test.util;
+
+import android.app.Instrumentation;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+/**
+ * Utility methods built around the android.app.Instrumentation class.
+ */
+public final class InstrumentationUtils {
+
+    private InstrumentationUtils() {
+    }
+
+    public static <R> R runOnMainSyncAndGetResult(Instrumentation instrumentation,
+            Callable<R> callable) throws Throwable {
+        FutureTask<R> task = new FutureTask<R>(callable);
+        instrumentation.runOnMainSync(task);
+        try {
+            return task.get();
+        } catch (ExecutionException e) {
+            // Unwrap the cause of the exception and re-throw it.
+            throw e.getCause();
+        }
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java b/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java
new file mode 100644
index 0000000..a107b32
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java
@@ -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.
+
+package org.chromium.base.test.util;
+
+/**
+ * Utility class for scaling various timeouts by a common factor.
+ * For example, to run tests under Valgrind, you might want the following:
+ *   adb shell "echo 20.0 > /data/local/tmp/chrome_timeout_scale"
+ */
+public class ScalableTimeout {
+    private static Double sTimeoutScale = null;
+    private static final String PROPERTY_FILE = "/data/local/tmp/chrome_timeout_scale";
+
+    public static long ScaleTimeout(long timeout) {
+        if (sTimeoutScale == null) {
+            try {
+                char[] data = TestFileUtil.readUtf8File(PROPERTY_FILE, 32);
+                sTimeoutScale = Double.parseDouble(new String(data));
+            } catch (Exception e) {
+                // NumberFormatException, FileNotFoundException, IOException
+                sTimeoutScale = 1.0;
+            }
+        }
+        return (long)(timeout * sTimeoutScale);
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java b/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java
new file mode 100644
index 0000000..1afbc11
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Arrays;
+
+/**
+ * Utility class for dealing with files for test.
+ */
+public class TestFileUtil {
+    public static void createNewHtmlFile(String name, String title, String body)
+            throws IOException {
+        File file = new File(name);
+        if (!file.createNewFile()) {
+            throw new IOException("File \"" + name + "\" already exists");
+        }
+
+        Writer writer = null;
+        try {
+            writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
+            writer.write("<html><meta charset=\"UTF-8\" />" +
+                         "<head><title>" + title + "</title></head>" +
+                         "<body>" +
+                         (body != null ? body : "") +
+                         "</body>" +
+                         "</html>");
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
+
+    public static void deleteFile(String name) {
+        File file = new File(name);
+        file.delete();
+    }
+
+    /**
+     * @param fileName the file to read in.
+     * @param sizeLimit cap on the file size: will throw an exception if exceeded
+     * @return Array of chars read from the file
+     * @throws FileNotFoundException file does not exceed
+     * @throws IOException error encountered accessing the file
+     */
+    public static char[] readUtf8File(String fileName, int sizeLimit) throws
+            FileNotFoundException, IOException {
+        Reader reader = null;
+        try {
+            File f = new File(fileName);
+            if (f.length() > sizeLimit) {
+                throw new IOException("File " + fileName + " length " + f.length() +
+                        " exceeds limit " + sizeLimit);
+            }
+            char[] buffer = new char[(int) f.length()];
+            reader = new InputStreamReader(new FileInputStream(f), "UTF-8");
+            int charsRead = reader.read(buffer);
+            // Debug check that we've exhausted the input stream (will fail e.g. if the
+            // file grew after we inspected its length).
+            assert !reader.ready();
+            return charsRead < buffer.length ? Arrays.copyOfRange(buffer, 0, charsRead) : buffer;
+        } finally {
+            if (reader != null) reader.close();
+        }
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java
new file mode 100644
index 0000000..7c13a32
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java
@@ -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.
+
+package org.chromium.base.test.util;
+
+import org.chromium.base.PathUtils;
+
+/**
+ * Collection of URL utilities.
+ */
+public class UrlUtils {
+    private final static String DATA_DIR = "/chrome/test/data/";
+
+    /**
+     * Construct a suitable URL for loading a test data file.
+     *
+     * @param path Pathname relative to external/chrome/testing/data
+     */
+    public static String getTestFileUrl(String path) {
+        return "file://" + PathUtils.getExternalStorageDirectory() + DATA_DIR + path;
+    }
+}
diff --git a/base/test/main_hook.cc b/base/test/main_hook.cc
new file mode 100644
index 0000000..f1f1961
--- /dev/null
+++ b/base/test/main_hook.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/main_hook.h"
+
+#if !defined(OS_IOS)
+MainHook::MainHook(MainType main_func, int argc, char* argv[]) {}
+#endif
diff --git a/base/test/main_hook.h b/base/test/main_hook.h
new file mode 100644
index 0000000..46b71ce
--- /dev/null
+++ b/base/test/main_hook.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+#include "base/basictypes.h"
+
+// Provides a way of running code before gtest-based tests with access to
+// argv and argc.
+class MainHook {
+ public:
+  typedef int (*MainType)(int, char*[]);
+  MainHook(MainType main_func, int argc, char* argv[]);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MainHook);
+};
diff --git a/base/test/main_hook_ios.mm b/base/test/main_hook_ios.mm
new file mode 100644
index 0000000..6d7bc44
--- /dev/null
+++ b/base/test/main_hook_ios.mm
@@ -0,0 +1,108 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/main_hook.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/debug/debugger.h"
+#include "base/logging.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/memory/scoped_nsobject.h"
+
+// Springboard will kill any iOS app that fails to check in after launch within
+// a given time. These two classes prevent this from happening.
+
+// MainHook saves the chrome main() and calls UIApplicationMain(),
+// providing an application delegate class: ChromeUnitTestDelegate. The delegate
+// listens for UIApplicationDidFinishLaunchingNotification. When the
+// notification is received, it fires main() again to have the real work done.
+
+// Example usage:
+// int main(int argc, char** argv) {
+//   MainHook hook(main, argc, argv);
+//   // Testing code goes here. There should be no code above MainHook. If
+//   // there is, it will be run twice.
+// }
+
+// Since the executable isn't likely to be a real iOS UI, the delegate puts up a
+// window displaying the app name. If a bunch of apps using MainHook are being
+// run in a row, this provides an indication of which one is currently running.
+
+static MainHook::MainType g_main_func = NULL;
+static int g_argc;
+static char** g_argv;
+
+@interface UIApplication (Testing)
+- (void) _terminateWithStatus:(int)status;
+@end
+
+@interface ChromeUnitTestDelegate : NSObject {
+@private
+  scoped_nsobject<UIWindow> window_;
+}
+- (void)runTests;
+@end
+
+@implementation ChromeUnitTestDelegate
+
+- (BOOL)application:(UIApplication *)application
+    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+  CGRect bounds = [[UIScreen mainScreen] bounds];
+
+  // Yes, this is leaked, it's just to make what's running visible.
+  window_.reset([[UIWindow alloc] initWithFrame:bounds]);
+  [window_ makeKeyAndVisible];
+
+  // Add a label with the app name.
+  UILabel* label = [[[UILabel alloc] initWithFrame:bounds] autorelease];
+  label.text = [[NSProcessInfo processInfo] processName];
+  label.textAlignment = UITextAlignmentCenter;
+  [window_ addSubview:label];
+
+  // Queue up the test run.
+  [self performSelector:@selector(runTests)
+             withObject:nil
+             afterDelay:0.1];
+  return YES;
+}
+
+- (void)runTests {
+  int exitStatus = g_main_func(g_argc, g_argv);
+
+  // If a test app is too fast, it will exit before Instruments has has a
+  // a chance to initialize and no test results will be seen.
+  // TODO(ios): crbug.com/137010 Figure out how much time is actually needed,
+  // and sleep only to make sure that much time has elapsed since launch.
+  [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
+  window_.reset();
+
+  // Use the hidden selector to try and cleanly take down the app (otherwise
+  // things can think the app crashed even on a zero exit status).
+  UIApplication* application = [UIApplication sharedApplication];
+  [application _terminateWithStatus:exitStatus];
+
+  exit(exitStatus);
+}
+
+@end
+
+#pragma mark -
+
+MainHook::MainHook(MainType main_func, int argc, char* argv[]) {
+  static bool ran_hook = false;
+  if (!ran_hook) {
+    ran_hook = true;
+
+    g_main_func = main_func;
+    g_argc = argc;
+    g_argv = argv;
+
+    base::mac::ScopedNSAutoreleasePool pool;
+    int exit_status = UIApplicationMain(argc, argv, nil,
+                                        @"ChromeUnitTestDelegate");
+    exit(exit_status);
+  }
+}
diff --git a/base/test/mock_chrome_application_mac.h b/base/test/mock_chrome_application_mac.h
new file mode 100644
index 0000000..5cd1d19
--- /dev/null
+++ b/base/test/mock_chrome_application_mac.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
+#define BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
+
+#if defined(__OBJC__)
+
+#import <AppKit/AppKit.h>
+
+#include "base/mac/scoped_sending_event.h"
+#include "base/message_pump_mac.h"
+
+// A basic implementation of CrAppProtocol and
+// CrAppControlProtocol. This can be used in tests that need an
+// NSApplication and use a runloop, or which need a ScopedSendingEvent
+// when handling a nested event loop.
+@interface MockCrApp : NSApplication<CrAppProtocol,
+                                     CrAppControlProtocol> {
+ @private
+  BOOL handlingSendEvent_;
+}
+@end
+
+#endif
+
+// To be used to instantiate MockCrApp from C++ code.
+namespace mock_cr_app {
+void RegisterMockCrApp();
+}  // namespace mock_cr_app
+
+#endif  // BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
diff --git a/base/test/mock_chrome_application_mac.mm b/base/test/mock_chrome_application_mac.mm
new file mode 100644
index 0000000..9135293
--- /dev/null
+++ b/base/test/mock_chrome_application_mac.mm
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_chrome_application_mac.h"
+
+#include "base/auto_reset.h"
+#include "base/logging.h"
+
+@implementation MockCrApp
+
++ (NSApplication*)sharedApplication {
+  NSApplication* app = [super sharedApplication];
+  DCHECK([app conformsToProtocol:@protocol(CrAppControlProtocol)])
+      << "Existing NSApp (class " << [[app className] UTF8String]
+      << ") does not conform to required protocol.";
+  DCHECK(base::MessagePumpMac::UsingCrApp())
+      << "MessagePumpMac::Create() was called before "
+      << "+[MockCrApp sharedApplication]";
+  return app;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+  AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
+  [super sendEvent:event];
+}
+
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
+  handlingSendEvent_ = handlingSendEvent;
+}
+
+- (BOOL)isHandlingSendEvent {
+  return handlingSendEvent_;
+}
+
+@end
+
+namespace mock_cr_app {
+
+void RegisterMockCrApp() {
+  [MockCrApp sharedApplication];
+}
+
+}  // namespace mock_cr_app
diff --git a/base/test/mock_devices_changed_observer.cc b/base/test/mock_devices_changed_observer.cc
new file mode 100644
index 0000000..c05f26a
--- /dev/null
+++ b/base/test/mock_devices_changed_observer.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_devices_changed_observer.h"
+
+namespace base {
+
+MockDevicesChangedObserver::MockDevicesChangedObserver() {
+}
+
+MockDevicesChangedObserver::~MockDevicesChangedObserver() {
+}
+
+}  // namespace base
diff --git a/base/test/mock_devices_changed_observer.h b/base/test/mock_devices_changed_observer.h
new file mode 100644
index 0000000..1d0f3dd
--- /dev/null
+++ b/base/test/mock_devices_changed_observer.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_MOCK_DEVICES_CHANGED_OBSERVER_H_
+#define BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
+
+#include <string>
+
+#include "base/system_monitor/system_monitor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+
+class MockDevicesChangedObserver
+    : public base::SystemMonitor::DevicesChangedObserver {
+ public:
+  MockDevicesChangedObserver();
+  ~MockDevicesChangedObserver();
+
+  MOCK_METHOD1(OnDevicesChanged,
+               void(base::SystemMonitor::DeviceType device_type));
+  MOCK_METHOD3(OnRemovableStorageAttached,
+               void(const std::string& id,
+                    const string16& name,
+                    const FilePath::StringType& location));
+  MOCK_METHOD1(OnRemovableStorageDetached, void(const std::string& id));
+
+  DISALLOW_COPY_AND_ASSIGN(MockDevicesChangedObserver);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
diff --git a/base/test/mock_time_provider.cc b/base/test/mock_time_provider.cc
new file mode 100644
index 0000000..9e5547f
--- /dev/null
+++ b/base/test/mock_time_provider.cc
@@ -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.
+
+#include "base/logging.h"
+#include "base/test/mock_time_provider.h"
+
+using ::testing::DefaultValue;
+
+namespace base {
+
+MockTimeProvider* MockTimeProvider::instance_ = NULL;
+
+MockTimeProvider::MockTimeProvider() {
+  DCHECK(!instance_) << "Only one instance of MockTimeProvider can exist";
+  DCHECK(!DefaultValue<Time>::IsSet());
+  instance_ = this;
+  DefaultValue<Time>::Set(Time::FromInternalValue(0));
+}
+
+MockTimeProvider::~MockTimeProvider() {
+  instance_ = NULL;
+  DefaultValue<Time>::Clear();
+}
+
+// static
+Time MockTimeProvider::StaticNow() {
+  return instance_->Now();
+}
+
+}  // namespace base
diff --git a/base/test/mock_time_provider.h b/base/test/mock_time_provider.h
new file mode 100644
index 0000000..81240f7
--- /dev/null
+++ b/base/test/mock_time_provider.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.
+
+// A helper class used to mock out calls to the static method base::Time::Now.
+//
+// Example usage:
+//
+// typedef base::Time(TimeProvider)();
+// class StopWatch {
+//  public:
+//   StopWatch(TimeProvider* time_provider);
+//   void Start();
+//   base::TimeDelta Stop();
+//  private:
+//   TimeProvider* time_provider_;
+//   ...
+// }
+//
+// Normally, you would instantiate a StopWatch with the real Now function:
+//
+// StopWatch watch(&base::Time::Now);
+//
+// But when testing, you want to instantiate it with
+// MockTimeProvider::StaticNow, which calls an internally mocked out member.
+// This allows you to set expectations on the Now method. For example:
+//
+// TEST_F(StopWatchTest, BasicTest) {
+//   InSequence s;
+//   StrictMock<MockTimeProvider> mock_time;
+//   EXPECT_CALL(mock_time, Now())
+//       .WillOnce(Return(Time::FromDoubleT(4)));
+//   EXPECT_CALL(mock_time, Now())
+//       .WillOnce(Return(Time::FromDoubleT(10)));
+//
+//   StopWatch sw(&MockTimeProvider::StaticNow);
+//   sw.Start();  // First call to Now.
+//   TimeDelta elapsed = sw.stop();  // Second call to Now.
+//   ASSERT_EQ(elapsed, TimeDelta::FromSeconds(6));
+// }
+
+#ifndef BASE_TEST_MOCK_TIME_PROVIDER_H_
+#define BASE_TEST_MOCK_TIME_PROVIDER_H_
+
+#include "base/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+
+class MockTimeProvider {
+ public:
+  MockTimeProvider();
+  ~MockTimeProvider();
+
+  MOCK_METHOD0(Now, Time());
+
+  static Time StaticNow();
+
+ private:
+  static MockTimeProvider* instance_;
+  DISALLOW_COPY_AND_ASSIGN(MockTimeProvider);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_MOCK_TIME_PROVIDER_H_
diff --git a/base/test/multiprocess_test.cc b/base/test/multiprocess_test.cc
new file mode 100644
index 0000000..27f9970
--- /dev/null
+++ b/base/test/multiprocess_test.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/multiprocess_test.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+
+namespace base {
+
+MultiProcessTest::MultiProcessTest() {
+}
+
+ProcessHandle MultiProcessTest::SpawnChild(const std::string& procname,
+                                           bool debug_on_start) {
+  FileHandleMappingVector empty_file_list;
+  return SpawnChildImpl(procname, empty_file_list, debug_on_start);
+}
+
+#if defined(OS_POSIX)
+ProcessHandle MultiProcessTest::SpawnChild(
+    const std::string& procname,
+    const FileHandleMappingVector& fds_to_map,
+    bool debug_on_start) {
+  return SpawnChildImpl(procname, fds_to_map, debug_on_start);
+}
+#endif
+
+CommandLine MultiProcessTest::MakeCmdLine(const std::string& procname,
+                                          bool debug_on_start) {
+  CommandLine cl(*CommandLine::ForCurrentProcess());
+  cl.AppendSwitchASCII(switches::kTestChildProcess, procname);
+  if (debug_on_start)
+    cl.AppendSwitch(switches::kDebugOnStart);
+  return cl;
+}
+
+#if !defined(OS_ANDROID)
+ProcessHandle MultiProcessTest::SpawnChildImpl(
+    const std::string& procname,
+    const FileHandleMappingVector& fds_to_map,
+    bool debug_on_start) {
+  ProcessHandle handle = kNullProcessHandle;
+  base::LaunchOptions options;
+#if defined(OS_WIN)
+  options.start_hidden = true;
+#else
+  options.fds_to_remap = &fds_to_map;
+#endif
+  base::LaunchProcess(MakeCmdLine(procname, debug_on_start), options, &handle);
+  return handle;
+}
+#endif  // !defined(OS_ANDROID)
+
+}  // namespace base
diff --git a/base/test/multiprocess_test.h b/base/test/multiprocess_test.h
new file mode 100644
index 0000000..7c3af33
--- /dev/null
+++ b/base/test/multiprocess_test.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_MULTIPROCESS_TEST_H_
+#define BASE_TEST_MULTIPROCESS_TEST_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/process.h"
+#include "base/process_util.h"
+#include "build/build_config.h"
+#include "testing/platform_test.h"
+
+class CommandLine;
+
+namespace base {
+
+// 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 handle to the child, or NULL on failure
+  ProcessHandle SpawnChild(const std::string& procname, bool debug_on_start);
+
+#if defined(OS_POSIX)
+  // TODO(evan): see if we can delete this via more refactoring.
+  // SpawnChild() should just take a base::LaunchOptions so that we don't
+  // need multiple versions of it.
+  ProcessHandle SpawnChild(const std::string& procname,
+                           const FileHandleMappingVector& fds_to_map,
+                           bool debug_on_start);
+#endif
+
+  // Set up the command line used to spawn the child process.
+  virtual CommandLine MakeCmdLine(const std::string& procname,
+                                  bool debug_on_start);
+
+ private:
+  // Shared implementation of SpawnChild.
+  // TODO: |fds_to_map| is unused on Windows; see above TODO about
+  // further refactoring.
+  ProcessHandle SpawnChildImpl(const std::string& procname,
+                               const FileHandleMappingVector& fds_to_map,
+                               bool debug_on_start);
+
+  DISALLOW_COPY_AND_ASSIGN(MultiProcessTest);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_MULTIPROCESS_TEST_H_
diff --git a/base/test/multiprocess_test_android.cc b/base/test/multiprocess_test_android.cc
new file mode 100644
index 0000000..cc45d06
--- /dev/null
+++ b/base/test/multiprocess_test_android.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/test/multiprocess_test.h"
+
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/process.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+
+// A very basic implementation for android. On Android tests can run in an APK
+// and we don't have an executable to exec*. This implementation does the bare
+// minimum to execute the method specified by procname (in the child process).
+//  - File descriptors are not closed and hence |fds_to_map| is ignored.
+//  - |debug_on_start| is ignored.
+ProcessHandle MultiProcessTest::SpawnChildImpl(
+    const std::string& procname,
+    const FileHandleMappingVector& fds_to_map,
+    bool debug_on_start) {
+  pid_t pid = fork();
+
+  if (pid < 0) {
+    DPLOG(ERROR) << "fork";
+    return kNullProcessHandle;
+  } else if (pid == 0) {
+    // Child process.
+    _exit(multi_process_function_list::InvokeChildProcessTest(procname));
+  }
+
+  // Parent process.
+  return pid;
+}
+
+}  // namespace base
diff --git a/base/test/perf_test_suite.cc b/base/test/perf_test_suite.cc
new file mode 100644
index 0000000..232766a
--- /dev/null
+++ b/base/test/perf_test_suite.cc
@@ -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.
+
+#include "base/test/perf_test_suite.h"
+
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/file_path.h"
+#include "base/path_service.h"
+#include "base/perftimer.h"
+#include "base/process_util.h"
+#include "base/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+PerfTestSuite::PerfTestSuite(int argc, char** argv) : TestSuite(argc, argv) {
+}
+
+void PerfTestSuite::Initialize() {
+  TestSuite::Initialize();
+
+  // Initialize the perf timer log
+  FilePath log_path =
+      CommandLine::ForCurrentProcess()->GetSwitchValuePath("log-file");
+  if (log_path.empty()) {
+    FilePath exe;
+    PathService::Get(base::FILE_EXE, &exe);
+    log_path = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
+    log_path = log_path.InsertBeforeExtension(FILE_PATH_LITERAL("_perf"));
+  }
+  ASSERT_TRUE(InitPerfLog(log_path));
+
+  // Raise to high priority to have more precise measurements. Since we don't
+  // aim at 1% precision, it is not necessary to run at realtime level.
+  if (!base::debug::BeingDebugged())
+    base::RaiseProcessToHighPriority();
+}
+
+void PerfTestSuite::Shutdown() {
+  TestSuite::Shutdown();
+  FinalizePerfLog();
+}
+
+}  // namespace base
diff --git a/base/test/perf_test_suite.h b/base/test/perf_test_suite.h
new file mode 100644
index 0000000..85bfc41
--- /dev/null
+++ b/base/test/perf_test_suite.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_PERF_TEST_SUITE_H_
+#define BASE_TEST_PERF_TEST_SUITE_H_
+
+#include "base/test/test_suite.h"
+
+namespace base {
+
+class PerfTestSuite : public TestSuite {
+ public:
+  PerfTestSuite(int argc, char** argv);
+
+  virtual void Initialize() OVERRIDE;
+  virtual void Shutdown() OVERRIDE;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_PERF_TEST_SUITE_H_
diff --git a/base/test/run_all_perftests.cc b/base/test/run_all_perftests.cc
new file mode 100644
index 0000000..6d9817c
--- /dev/null
+++ b/base/test/run_all_perftests.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/test/main_hook.h"
+#include "base/test/perf_test_suite.h"
+
+int main(int argc, char** argv) {
+  MainHook hook(main, argc, argv);
+  return base::PerfTestSuite(argc, argv).Run();
+}
diff --git a/base/test/run_all_unittests.cc b/base/test/run_all_unittests.cc
new file mode 100644
index 0000000..969b091
--- /dev/null
+++ b/base/test/run_all_unittests.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/test/main_hook.h"
+#include "base/test/test_suite.h"
+
+int main(int argc, char** argv) {
+  MainHook hook(main, argc, argv);
+  return base::TestSuite(argc, argv).Run();
+}
diff --git a/base/test/scoped_locale.cc b/base/test/scoped_locale.cc
new file mode 100644
index 0000000..35b3fbe
--- /dev/null
+++ b/base/test/scoped_locale.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_locale.h"
+
+#include <locale.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+ScopedLocale::ScopedLocale(const std::string& locale) {
+  prev_locale_ = setlocale(LC_ALL, NULL);
+  EXPECT_TRUE(setlocale(LC_ALL, locale.c_str()) != NULL) <<
+      "Failed to set locale: " << locale;
+}
+
+ScopedLocale::~ScopedLocale() {
+  EXPECT_STREQ(prev_locale_.c_str(), setlocale(LC_ALL, prev_locale_.c_str()));
+}
+
+}  // namespace base
diff --git a/base/test/scoped_locale.h b/base/test/scoped_locale.h
new file mode 100644
index 0000000..a9f9348
--- /dev/null
+++ b/base/test/scoped_locale.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_LOCALE_H_
+#define BASE_TEST_SCOPED_LOCALE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Sets the given |locale| on construction, and restores the previous locale
+// on destruction.
+class ScopedLocale {
+ public:
+  explicit ScopedLocale(const std::string& locale);
+  ~ScopedLocale();
+
+ private:
+  std::string prev_locale_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedLocale);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SCOPED_LOCALE_H_
diff --git a/base/test/scoped_path_override.cc b/base/test/scoped_path_override.cc
new file mode 100644
index 0000000..bb38c7f
--- /dev/null
+++ b/base/test/scoped_path_override.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_path_override.h"
+
+#include "base/logging.h"
+#include "base/path_service.h"
+
+namespace base {
+
+ScopedPathOverride::ScopedPathOverride(int key) : key_(key) {
+  bool result = temp_dir_.CreateUniqueTempDir();
+  CHECK(result);
+  result = PathService::Override(key, temp_dir_.path());
+  CHECK(result);
+}
+
+ScopedPathOverride::ScopedPathOverride(int key, const FilePath& dir)
+    : key_(key) {
+  bool result = PathService::Override(key, dir);
+  CHECK(result);
+}
+
+ScopedPathOverride::~ScopedPathOverride() {
+   bool result = PathService::RemoveOverride(key_);
+   CHECK(result) << "The override seems to have been removed already!";
+}
+
+}  // namespace base
diff --git a/base/test/scoped_path_override.h b/base/test/scoped_path_override.h
new file mode 100644
index 0000000..cf5c810
--- /dev/null
+++ b/base/test/scoped_path_override.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_TEST_SCOPED_PATH_OVERRIDE_H_
+#define BASE_TEST_SCOPED_PATH_OVERRIDE_H_
+
+#include "base/basictypes.h"
+#include "base/scoped_temp_dir.h"
+
+class FilePath;
+
+namespace base {
+
+// Sets a path override on construction, and removes it when the object goes out
+// of scope. This class is intended to be used by tests that need to override
+// paths to ensure their overrides are properly handled and reverted when the
+// scope of the test is left.
+class ScopedPathOverride {
+ public:
+  // Contructor that intializes the override to a scoped temp directory.
+  explicit ScopedPathOverride(int key);
+  // Constructor that would use a path provided by the user.
+  ScopedPathOverride(int key, const FilePath& dir);
+  ~ScopedPathOverride();
+
+ private:
+  int key_;
+  ScopedTempDir temp_dir_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPathOverride);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SCOPED_PATH_OVERRIDE_H_
diff --git a/base/test/sequenced_task_runner_test_template.cc b/base/test/sequenced_task_runner_test_template.cc
new file mode 100644
index 0000000..50487d2
--- /dev/null
+++ b/base/test/sequenced_task_runner_test_template.cc
@@ -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.
+
+#include "base/test/sequenced_task_runner_test_template.h"
+
+#include <ostream>
+
+#include "base/location.h"
+
+namespace base {
+
+namespace internal {
+
+TaskEvent::TaskEvent(int i, Type type)
+  : i(i), type(type) {
+}
+
+SequencedTaskTracker::SequencedTaskTracker() : next_post_i_(0) {
+}
+
+void SequencedTaskTracker::PostWrappedNonNestableTask(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    const Closure& task) {
+  AutoLock event_lock(lock_);
+  const int post_i = next_post_i_++;
+  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+                              task, post_i);
+  task_runner->PostNonNestableTask(FROM_HERE, wrapped_task);
+  TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostWrappedNestableTask(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    const Closure& task) {
+  AutoLock event_lock(lock_);
+  const int post_i = next_post_i_++;
+  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+                              task, post_i);
+  task_runner->PostTask(FROM_HERE, wrapped_task);
+  TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostWrappedDelayedNonNestableTask(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    const Closure& task,
+    TimeDelta delay) {
+  AutoLock event_lock(lock_);
+  const int post_i = next_post_i_++;
+  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+                              task, post_i);
+  task_runner->PostNonNestableDelayedTask(FROM_HERE, wrapped_task, delay);
+  TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostNonNestableTasks(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    int task_count) {
+  for (int i = 0; i < task_count; ++i) {
+    PostWrappedNonNestableTask(task_runner, Closure());
+  }
+}
+
+void SequencedTaskTracker::RunTask(const Closure& task, int task_i) {
+  TaskStarted(task_i);
+  if (!task.is_null())
+    task.Run();
+  TaskEnded(task_i);
+}
+
+void SequencedTaskTracker::TaskPosted(int i) {
+  // Caller must own |lock_|.
+  events_.push_back(TaskEvent(i, TaskEvent::POST));
+}
+
+void SequencedTaskTracker::TaskStarted(int i) {
+  AutoLock lock(lock_);
+  events_.push_back(TaskEvent(i, TaskEvent::START));
+}
+
+void SequencedTaskTracker::TaskEnded(int i) {
+  AutoLock lock(lock_);
+  events_.push_back(TaskEvent(i, TaskEvent::END));
+}
+
+const std::vector<TaskEvent>&
+SequencedTaskTracker::GetTaskEvents() const {
+  return events_;
+}
+
+SequencedTaskTracker::~SequencedTaskTracker() {
+}
+
+void PrintTo(const TaskEvent& event, std::ostream* os) {
+  *os << "(i=" << event.i << ", type=";
+  switch (event.type) {
+    case TaskEvent::POST: *os << "POST"; break;
+    case TaskEvent::START: *os << "START"; break;
+    case TaskEvent::END: *os << "END"; break;
+  }
+  *os << ")";
+}
+
+namespace {
+
+// Returns the task ordinals for the task event type |type| in the order that
+// they were recorded.
+std::vector<int> GetEventTypeOrder(const std::vector<TaskEvent>& events,
+                                   TaskEvent::Type type) {
+  std::vector<int> tasks;
+  std::vector<TaskEvent>::const_iterator event;
+  for (event = events.begin(); event != events.end(); ++event) {
+    if (event->type == type)
+      tasks.push_back(event->i);
+  }
+  return tasks;
+}
+
+// Returns all task events for task |task_i|.
+std::vector<TaskEvent::Type> GetEventsForTask(
+    const std::vector<TaskEvent>& events,
+    int task_i) {
+  std::vector<TaskEvent::Type> task_event_orders;
+  std::vector<TaskEvent>::const_iterator event;
+  for (event = events.begin(); event != events.end(); ++event) {
+    if (event->i == task_i)
+      task_event_orders.push_back(event->type);
+  }
+  return task_event_orders;
+}
+
+// Checks that the task events for each task in |events| occur in the order
+// {POST, START, END}, and that there is only one instance of each event type
+// per task.
+::testing::AssertionResult CheckEventOrdersForEachTask(
+    const std::vector<TaskEvent>& events,
+    int task_count) {
+  std::vector<TaskEvent::Type> expected_order;
+  expected_order.push_back(TaskEvent::POST);
+  expected_order.push_back(TaskEvent::START);
+  expected_order.push_back(TaskEvent::END);
+
+  // This is O(n^2), but it runs fast enough currently so is not worth
+  // optimizing.
+  for (int i = 0; i < task_count; ++i) {
+    const std::vector<TaskEvent::Type> task_events =
+        GetEventsForTask(events, i);
+    if (task_events != expected_order) {
+      return ::testing::AssertionFailure()
+          << "Events for task " << i << " are out of order; expected: "
+          << ::testing::PrintToString(expected_order) << "; actual: "
+          << ::testing::PrintToString(task_events);
+    }
+  }
+  return ::testing::AssertionSuccess();
+}
+
+// Checks that no two tasks were running at the same time. I.e. the only
+// events allowed between the START and END of a task are the POSTs of other
+// tasks.
+::testing::AssertionResult CheckNoTaskRunsOverlap(
+    const std::vector<TaskEvent>& events) {
+  // If > -1, we're currently inside a START, END pair.
+  int current_task_i = -1;
+
+  std::vector<TaskEvent>::const_iterator event;
+  for (event = events.begin(); event != events.end(); ++event) {
+    bool spurious_event_found = false;
+
+    if (current_task_i == -1) {  // Not inside a START, END pair.
+      switch (event->type) {
+        case TaskEvent::POST:
+          break;
+        case TaskEvent::START:
+          current_task_i = event->i;
+          break;
+        case TaskEvent::END:
+          spurious_event_found = true;
+          break;
+      }
+
+    } else {  // Inside a START, END pair.
+      bool interleaved_task_detected = false;
+
+      switch (event->type) {
+        case TaskEvent::POST:
+          if (event->i == current_task_i)
+            spurious_event_found = true;
+          break;
+        case TaskEvent::START:
+          interleaved_task_detected = true;
+          break;
+        case TaskEvent::END:
+          if (event->i != current_task_i)
+            interleaved_task_detected = true;
+          else
+            current_task_i = -1;
+          break;
+      }
+
+      if (interleaved_task_detected) {
+        return ::testing::AssertionFailure()
+            << "Found event " << ::testing::PrintToString(*event)
+            << " between START and END events for task " << current_task_i
+            << "; event dump: " << ::testing::PrintToString(events);
+      }
+    }
+
+    if (spurious_event_found) {
+      const int event_i = event - events.begin();
+      return ::testing::AssertionFailure()
+          << "Spurious event " << ::testing::PrintToString(*event)
+          << " at position " << event_i << "; event dump: "
+          << ::testing::PrintToString(events);
+    }
+  }
+
+  return ::testing::AssertionSuccess();
+}
+
+}  // namespace
+
+::testing::AssertionResult CheckNonNestableInvariants(
+    const std::vector<TaskEvent>& events,
+    int task_count) {
+  const std::vector<int> post_order =
+      GetEventTypeOrder(events, TaskEvent::POST);
+  const std::vector<int> start_order =
+      GetEventTypeOrder(events, TaskEvent::START);
+  const std::vector<int> end_order =
+      GetEventTypeOrder(events, TaskEvent::END);
+
+  if (start_order != post_order) {
+    return ::testing::AssertionFailure()
+        << "Expected START order (which equals actual POST order): \n"
+        << ::testing::PrintToString(post_order)
+        << "\n Actual START order:\n"
+        << ::testing::PrintToString(start_order);
+  }
+
+  if (end_order != post_order) {
+    return ::testing::AssertionFailure()
+        << "Expected END order (which equals actual POST order): \n"
+        << ::testing::PrintToString(post_order)
+        << "\n Actual END order:\n"
+        << ::testing::PrintToString(end_order);
+  }
+
+  const ::testing::AssertionResult result =
+      CheckEventOrdersForEachTask(events, task_count);
+  if (!result)
+    return result;
+
+  return CheckNoTaskRunsOverlap(events);
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/test/sequenced_task_runner_test_template.h b/base/test/sequenced_task_runner_test_template.h
new file mode 100644
index 0000000..0c8d135
--- /dev/null
+++ b/base/test/sequenced_task_runner_test_template.h
@@ -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.
+
+// This class defines tests that implementations of SequencedTaskRunner should
+// pass in order to be conformant. See task_runner_test_template.h for a
+// description of how to use the constructs in this file; these work the same.
+
+#ifndef BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
+#define BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
+
+#include <cstddef>
+#include <iosfwd>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace internal {
+
+struct TaskEvent {
+  enum Type { POST, START, END };
+  TaskEvent(int i, Type type);
+  int i;
+  Type type;
+};
+
+// Utility class used in the tests below.
+class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
+ public:
+  SequencedTaskTracker();
+
+  // Posts the non-nestable task |task|, and records its post event.
+  void PostWrappedNonNestableTask(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      const Closure& task);
+
+  // Posts the nestable task |task|, and records its post event.
+  void PostWrappedNestableTask(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      const Closure& task);
+
+  // Posts the delayed non-nestable task |task|, and records its post event.
+  void PostWrappedDelayedNonNestableTask(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      const Closure& task,
+      TimeDelta delay);
+
+  // Posts |task_count| non-nestable tasks.
+  void PostNonNestableTasks(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      int task_count);
+
+  const std::vector<TaskEvent>& GetTaskEvents() const;
+
+ private:
+  friend class RefCountedThreadSafe<SequencedTaskTracker>;
+
+  ~SequencedTaskTracker();
+
+  // A task which runs |task|, recording the start and end events.
+  void RunTask(const Closure& task, int task_i);
+
+  // Records a post event for task |i|. The owner is expected to be holding
+  // |lock_| (unlike |TaskStarted| and |TaskEnded|).
+  void TaskPosted(int i);
+
+  // Records a start event for task |i|.
+  void TaskStarted(int i);
+
+  // Records a end event for task |i|.
+  void TaskEnded(int i);
+
+  // Protects events_ and next_post_i_.
+  Lock lock_;
+
+  // The events as they occurred for each task (protected by lock_).
+  std::vector<TaskEvent> events_;
+
+  // The ordinal to be used for the next task-posting task (protected by
+  // lock_).
+  int next_post_i_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker);
+};
+
+void PrintTo(const TaskEvent& event, std::ostream* os);
+
+// Checks the non-nestable task invariants for all tasks in |events|.
+//
+// The invariants are:
+// 1) Events started and ended in the same order that they were posted.
+// 2) Events for an individual tasks occur in the order {POST, START, END},
+//    and there is only one instance of each event type for a task.
+// 3) The only events between a task's START and END events are the POSTs of
+//    other tasks. I.e. tasks were run sequentially, not interleaved.
+::testing::AssertionResult CheckNonNestableInvariants(
+    const std::vector<TaskEvent>& events,
+    int task_count);
+
+}  // namespace internal
+
+template <typename TaskRunnerTestDelegate>
+class SequencedTaskRunnerTest : public testing::Test {
+ protected:
+  SequencedTaskRunnerTest()
+  : task_tracker_(new internal::SequencedTaskTracker()) {}
+
+  const scoped_refptr<internal::SequencedTaskTracker> task_tracker_;
+  TaskRunnerTestDelegate delegate_;
+};
+
+TYPED_TEST_CASE_P(SequencedTaskRunnerTest);
+
+// This test posts N non-nestable tasks in sequence, and expects them to run
+// in FIFO order, with no part of any two tasks' execution
+// overlapping. I.e. that each task starts only after the previously-posted
+// one has finished.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) {
+  const int kTaskCount = 1000;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedNonNestableTask(
+      task_runner, Bind(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
+  for (int i = 1; i < kTaskCount; ++i) {
+    this->task_tracker_->PostWrappedNonNestableTask(task_runner, Closure());
+  }
+
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts N nestable tasks in sequence. It has the same expectations
+// as SequentialNonNestable because even though the tasks are nestable, they
+// will not be run nestedly in this case.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNestable) {
+  const int kTaskCount = 1000;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedNestableTask(
+      task_runner,
+      Bind(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
+  for (int i = 1; i < kTaskCount; ++i) {
+    this->task_tracker_->PostWrappedNestableTask(task_runner, Closure());
+  }
+
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts non-nestable tasks in order of increasing delay, and checks
+// that that the tasks are run in FIFO order and that there is no execution
+// overlap whatsoever between any two tasks.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) {
+  // TODO(akalin): Remove this check (http://crbug.com/149144).
+  if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) {
+    DLOG(INFO) << "This SequencedTaskRunner doesn't handle "
+        "non-zero delays; skipping";
+    return;
+  }
+
+  const int kTaskCount = 20;
+  const int kDelayIncrementMs = 50;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  for (int i = 0; i < kTaskCount; ++i) {
+    this->task_tracker_->PostWrappedDelayedNonNestableTask(
+        task_runner,
+        Closure(),
+        TimeDelta::FromMilliseconds(kDelayIncrementMs * i));
+  }
+
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts a fast, non-nestable task from within each of a number of
+// slow, non-nestable tasks and checks that they all run in the sequence they
+// were posted in and that there is no execution overlap whatsoever.
+TYPED_TEST_P(SequencedTaskRunnerTest, NonNestablePostFromNonNestableTask) {
+  const int kParentCount = 10;
+  const int kChildrenPerParent = 10;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  for (int i = 0; i < kParentCount; ++i) {
+    Closure task = Bind(
+        &internal::SequencedTaskTracker::PostNonNestableTasks,
+        this->task_tracker_,
+        task_runner,
+        kChildrenPerParent);
+    this->task_tracker_->PostWrappedNonNestableTask(task_runner, task);
+  }
+
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(
+      this->task_tracker_->GetTaskEvents(),
+      kParentCount * (kChildrenPerParent + 1)));
+}
+
+// This test posts a delayed task, and checks that the task is run later than
+// the specified time.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskBasic) {
+  // TODO(akalin): Remove this check (http://crbug.com/149144).
+  if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) {
+    DLOG(INFO) << "This SequencedTaskRunner doesn't handle "
+        "non-zero delays; skipping";
+    return;
+  }
+
+  const int kTaskCount = 1;
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  Time time_before_run = Time::Now();
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), kDelay);
+  this->delegate_.StopTaskRunner();
+  Time time_after_run = Time::Now();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+  EXPECT_LE(kDelay, time_after_run - time_before_run);
+}
+
+// This test posts two tasks with the same delay, and checks that the tasks are
+// run in the order in which they were posted.
+//
+// NOTE: This is actually an approximate test since the API only takes a
+// "delay" parameter, so we are not exactly simulating two tasks that get
+// posted at the exact same time. It would be nice if the API allowed us to
+// specify the desired run time.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTasksSameDelay) {
+  // TODO(akalin): Remove this check (http://crbug.com/149144).
+  if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) {
+    DLOG(INFO) << "This SequencedTaskRunner doesn't handle "
+        "non-zero delays; skipping";
+    return;
+  }
+
+  const int kTaskCount = 2;
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), kDelay);
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), kDelay);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts a normal task and a delayed task, and checks that the
+// delayed task runs after the normal task even if the normal task takes
+// a long time to run.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterLongTask) {
+  // TODO(akalin): Remove this check (http://crbug.com/149144).
+  if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) {
+    DLOG(INFO) << "This SequencedTaskRunner doesn't handle "
+        "non-zero delays; skipping";
+    return;
+  }
+
+  const int kTaskCount = 2;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedNonNestableTask(
+      task_runner, base::Bind(&PlatformThread::Sleep,
+                              TimeDelta::FromMilliseconds(50)));
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), TimeDelta::FromMilliseconds(10));
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// Test that a pile of normal tasks and a delayed task run in the
+// time-to-run order.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterManyLongTasks) {
+  // TODO(akalin): Remove this check (http://crbug.com/149144).
+  if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) {
+    DLOG(INFO) << "This SequencedTaskRunner doesn't handle "
+        "non-zero delays; skipping";
+    return;
+  }
+
+  const int kTaskCount = 11;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  for (int i = 0; i < kTaskCount - 1; i++) {
+    this->task_tracker_->PostWrappedNonNestableTask(
+        task_runner, base::Bind(&PlatformThread::Sleep,
+                                TimeDelta::FromMilliseconds(50)));
+  }
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), TimeDelta::FromMilliseconds(10));
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+
+// TODO(francoisk777@gmail.com) Add a test, similiar to the above, which runs
+// some tasked nestedly (which should be implemented in the test
+// delegate). Also add, to the the test delegate, a predicate which checks
+// whether the implementation supports nested tasks.
+//
+
+REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest,
+                           SequentialNonNestable,
+                           SequentialNestable,
+                           SequentialDelayedNonNestable,
+                           NonNestablePostFromNonNestableTask,
+                           DelayedTaskBasic,
+                           DelayedTasksSameDelay,
+                           DelayedTaskAfterLongTask,
+                           DelayedTaskAfterManyLongTasks);
+
+}  // namespace base
+
+#endif  // BASE_TASK_RUNNER_TEST_TEMPLATE_H_
diff --git a/base/test/sequenced_worker_pool_owner.cc b/base/test/sequenced_worker_pool_owner.cc
new file mode 100644
index 0000000..3d124fa
--- /dev/null
+++ b/base/test/sequenced_worker_pool_owner.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/sequenced_worker_pool_owner.h"
+
+#include "base/location.h"
+#include "base/message_loop.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,
+          ALLOW_THIS_IN_INITIALIZER_LIST(this))),
+      has_work_call_count_(0) {}
+
+SequencedWorkerPoolOwner::~SequencedWorkerPoolOwner() {
+  pool_ = NULL;
+  MessageLoop::current()->Run();
+}
+
+const scoped_refptr<SequencedWorkerPool>& SequencedWorkerPoolOwner::pool() {
+  return pool_;
+}
+
+void SequencedWorkerPoolOwner::SetWillWaitForShutdownCallback(
+    const Closure& callback) {
+  will_wait_for_shutdown_callback_ = callback;
+}
+
+int SequencedWorkerPoolOwner::has_work_call_count() const {
+  AutoLock lock(has_work_lock_);
+  return has_work_call_count_;
+}
+
+void SequencedWorkerPoolOwner::OnHasWork() {
+  AutoLock lock(has_work_lock_);
+  ++has_work_call_count_;
+}
+
+void SequencedWorkerPoolOwner::WillWaitForShutdown() {
+  if (!will_wait_for_shutdown_callback_.is_null()) {
+    will_wait_for_shutdown_callback_.Run();
+  }
+}
+
+void SequencedWorkerPoolOwner::OnDestruct() {
+  constructor_message_loop_->PostTask(
+      FROM_HERE,
+      constructor_message_loop_->QuitClosure());
+}
+
+}  // namespace base
diff --git a/base/test/sequenced_worker_pool_owner.h b/base/test/sequenced_worker_pool_owner.h
new file mode 100644
index 0000000..c6c8d67
--- /dev/null
+++ b/base/test/sequenced_worker_pool_owner.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_SEQUENCED_WORKER_POOL_UNITTEST_H_
+#define BASE_THREADING_SEQUENCED_WORKER_POOL_UNITTEST_H_
+
+#include <cstddef>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/sequenced_worker_pool.h"
+
+class MessageLoop;
+
+namespace base {
+
+// Wrapper around SequencedWorkerPool for testing that blocks destruction
+// until the pool is actually destroyed.  This is so that a
+// SequencedWorkerPool from one test doesn't outlive its test and cause
+// strange races with other tests that touch global stuff (like histograms and
+// logging).  However, this requires that nothing else on this thread holds a
+// ref to the pool when the SequencedWorkerPoolOwner is destroyed.
+class SequencedWorkerPoolOwner : public SequencedWorkerPool::TestingObserver {
+ public:
+  SequencedWorkerPoolOwner(size_t max_threads,
+                           const std::string& thread_name_prefix);
+
+  virtual ~SequencedWorkerPoolOwner();
+
+  // 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.
+  virtual void OnHasWork() OVERRIDE;
+  virtual void WillWaitForShutdown() OVERRIDE;
+  virtual void OnDestruct() OVERRIDE;
+
+  MessageLoop* const constructor_message_loop_;
+  scoped_refptr<SequencedWorkerPool> pool_;
+  Closure will_wait_for_shutdown_callback_;
+
+  mutable Lock has_work_lock_;
+  int has_work_call_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolOwner);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SEQUENCED_WORKER_POOL_UNITTEST_H_
diff --git a/base/test/task_runner_test_template.cc b/base/test/task_runner_test_template.cc
new file mode 100644
index 0000000..239a99f
--- /dev/null
+++ b/base/test/task_runner_test_template.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/task_runner_test_template.h"
+
+namespace base {
+
+namespace internal {
+
+TaskTracker::TaskTracker() {}
+
+TaskTracker::~TaskTracker() {}
+
+Closure TaskTracker::WrapTask(const Closure& task, int i) {
+  return Bind(&TaskTracker::RunTask, this, task, i);
+}
+
+void TaskTracker::RunTask(const Closure& task, int i) {
+  AutoLock lock(task_run_counts_lock_);
+  if (!task.is_null()) {
+    task.Run();
+  }
+  ++task_run_counts_[i];
+}
+
+std::map<int, int> TaskTracker::GetTaskRunCounts() const {
+  AutoLock lock(task_run_counts_lock_);
+  return task_run_counts_;
+}
+
+void ExpectRunsTasksOnCurrentThread(
+    bool expected_value,
+    const scoped_refptr<TaskRunner>& task_runner) {
+  EXPECT_EQ(expected_value, task_runner->RunsTasksOnCurrentThread());
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/test/task_runner_test_template.h b/base/test/task_runner_test_template.h
new file mode 100644
index 0000000..437a7d9
--- /dev/null
+++ b/base/test/task_runner_test_template.h
@@ -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.
+
+// This class defines tests that implementations of TaskRunner should
+// pass in order to be conformant.  Here's how you use it to test your
+// implementation.
+//
+// Say your class is called MyTaskRunner.  Then you need to define a
+// class called MyTaskRunnerTestDelegate in my_task_runner_unittest.cc
+// like this:
+//
+//   class MyTaskRunnerTestDelegate {
+//    public:
+//     // Tasks posted to the task runner after this and before
+//     // StopTaskRunner() is called is called should run successfully.
+//     void StartTaskRunner() {
+//       ...
+//     }
+//
+//     // Should return the task runner implementation.  Only called
+//     // after StartTaskRunner and before StopTaskRunner.
+//     scoped_refptr<MyTaskRunner> GetTaskRunner() {
+//       ...
+//     }
+//
+//     // Stop the task runner and make sure all tasks posted before
+//     // this is called are run.
+//     void StopTaskRunner() {
+//       ...
+//     }
+//
+//     // Returns whether or not the task runner obeys non-zero delays.
+//     bool TaskRunnerHandlesNonZeroDelays() const {
+//       return true;
+//     }
+//   };
+//
+// The TaskRunnerTest test harness will have a member variable of
+// this delegate type and will call its functions in the various
+// tests.
+//
+// Then you simply #include this file as well as gtest.h and add the
+// following statement to my_task_runner_unittest.cc:
+//
+//   INSTANTIATE_TYPED_TEST_CASE_P(
+//       MyTaskRunner, TaskRunnerTest, MyTaskRunnerTestDelegate);
+//
+// Easy!
+
+#ifndef BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
+#define BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
+
+#include <cstddef>
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/task_runner.h"
+#include "base/threading/thread.h"
+#include "base/tracked_objects.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace internal {
+
+// Utility class that keeps track of how many times particular tasks
+// are run.
+class TaskTracker : public RefCountedThreadSafe<TaskTracker> {
+ public:
+  TaskTracker();
+
+  // Returns a closure that runs the given task and increments the run
+  // count of |i| by one.  |task| may be null.  It is guaranteed that
+  // only one task wrapped by a given tracker will be run at a time.
+  Closure WrapTask(const Closure& task, int i);
+
+  std::map<int, int> GetTaskRunCounts() const;
+
+ private:
+  friend class RefCountedThreadSafe<TaskTracker>;
+
+  ~TaskTracker();
+
+  void RunTask(const Closure& task, int i);
+
+  mutable Lock task_run_counts_lock_;
+  std::map<int, int> task_run_counts_;
+
+  DISALLOW_COPY_AND_ASSIGN(TaskTracker);
+};
+
+}  // namespace internal
+
+template <typename TaskRunnerTestDelegate>
+class TaskRunnerTest : public testing::Test {
+ protected:
+  TaskRunnerTest() : task_tracker_(new internal::TaskTracker()) {}
+
+  const scoped_refptr<internal::TaskTracker> task_tracker_;
+  TaskRunnerTestDelegate delegate_;
+};
+
+TYPED_TEST_CASE_P(TaskRunnerTest);
+
+// We can't really test much, since TaskRunner provides very few
+// guarantees.
+
+// Post a bunch of tasks to the task runner.  They should all
+// complete.
+TYPED_TEST_P(TaskRunnerTest, Basic) {
+  std::map<int, int> expected_task_run_counts;
+
+  this->delegate_.StartTaskRunner();
+  scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+  // Post each ith task i+1 times.
+  for (int i = 0; i < 20; ++i) {
+    const Closure& ith_task = this->task_tracker_->WrapTask(Closure(), i);
+    for (int j = 0; j < i + 1; ++j) {
+      task_runner->PostTask(FROM_HERE, ith_task);
+      ++expected_task_run_counts[i];
+    }
+  }
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_EQ(expected_task_run_counts,
+            this->task_tracker_->GetTaskRunCounts());
+}
+
+// Post a bunch of delayed tasks to the task runner.  They should all
+// complete.
+TYPED_TEST_P(TaskRunnerTest, Delayed) {
+  if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) {
+    DLOG(INFO) << "This TaskRunner doesn't handle non-zero delays; skipping";
+    return;
+  }
+
+  std::map<int, int> expected_task_run_counts;
+
+  this->delegate_.StartTaskRunner();
+  scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+  // Post each ith task i+1 times with delays from 0-i.
+  for (int i = 0; i < 20; ++i) {
+    const Closure& ith_task = this->task_tracker_->WrapTask(Closure(), i);
+    for (int j = 0; j < i + 1; ++j) {
+      task_runner->PostDelayedTask(
+          FROM_HERE, ith_task, base::TimeDelta::FromMilliseconds(j));
+      ++expected_task_run_counts[i];
+    }
+  }
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_EQ(expected_task_run_counts,
+            this->task_tracker_->GetTaskRunCounts());
+}
+
+namespace internal {
+
+// Calls RunsTasksOnCurrentThread() on |task_runner| and expects it to
+// equal |expected_value|.
+void ExpectRunsTasksOnCurrentThread(
+    bool expected_value,
+    const scoped_refptr<TaskRunner>& task_runner);
+
+}  // namespace internal
+
+// Post a bunch of tasks to the task runner as well as to a separate
+// thread, each checking the value of RunsTasksOnCurrentThread(),
+// which should return true for the tasks posted on the task runner
+// and false for the tasks posted on the separate thread.
+TYPED_TEST_P(TaskRunnerTest, RunsTasksOnCurrentThread) {
+  std::map<int, int> expected_task_run_counts;
+
+  Thread thread("Non-task-runner thread");
+  ASSERT_TRUE(thread.Start());
+  this->delegate_.StartTaskRunner();
+
+  scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+  // Post each ith task i+1 times on the task runner and i+1 times on
+  // the non-task-runner thread.
+  for (int i = 0; i < 20; ++i) {
+    const Closure& ith_task_runner_task =
+        this->task_tracker_->WrapTask(
+            Bind(&internal::ExpectRunsTasksOnCurrentThread,
+                 true, task_runner),
+            i);
+    const Closure& ith_non_task_runner_task =
+        this->task_tracker_->WrapTask(
+            Bind(&internal::ExpectRunsTasksOnCurrentThread,
+                 false, task_runner),
+            i);
+    for (int j = 0; j < i + 1; ++j) {
+      task_runner->PostTask(FROM_HERE, ith_task_runner_task);
+      thread.message_loop()->PostTask(FROM_HERE, ith_non_task_runner_task);
+      expected_task_run_counts[i] += 2;
+    }
+  }
+
+  this->delegate_.StopTaskRunner();
+  thread.Stop();
+
+  EXPECT_EQ(expected_task_run_counts,
+            this->task_tracker_->GetTaskRunCounts());
+}
+
+REGISTER_TYPED_TEST_CASE_P(
+    TaskRunnerTest, Basic, Delayed, RunsTasksOnCurrentThread);
+
+}  // namespace base
+
+#endif  //#define BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
diff --git a/base/test/test_file_util.h b/base/test/test_file_util.h
new file mode 100644
index 0000000..165af70
--- /dev/null
+++ b/base/test/test_file_util.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_FILE_UTIL_H_
+#define BASE_TEST_TEST_FILE_UTIL_H_
+
+// File utility functions used only by tests.
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/file_path.h"
+
+class FilePath;
+
+namespace file_util {
+
+// Wrapper over file_util::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);
+
+// Like CopyFileNoCache but recursively copies all files and subdirectories
+// in the given input directory to the output directory. Any files in the
+// destination that already exist will be overwritten.
+//
+// Returns true on success. False means there was some error copying, so the
+// state of the destination is unknown.
+bool CopyRecursiveDirNoCache(const FilePath& source_dir,
+                             const FilePath& dest_dir);
+
+#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)
+
+// In general it's not reliable to convert a FilePath to a wstring and we use
+// string16 elsewhere for Unicode strings, but in tests it is frequently
+// convenient to be able to compare paths to literals like L"foobar".
+std::wstring FilePathAsWString(const FilePath& path);
+FilePath WStringAsFilePath(const std::wstring& path);
+
+// 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 PermissionRestorer {
+ public:
+  explicit PermissionRestorer(const FilePath& path);
+  ~PermissionRestorer();
+
+ 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(PermissionRestorer);
+};
+
+}  // namespace file_util
+
+#endif  // BASE_TEST_TEST_FILE_UTIL_H_
diff --git a/base/test/test_file_util_linux.cc b/base/test/test_file_util_linux.cc
new file mode 100644
index 0000000..993750e
--- /dev/null
+++ b/base/test/test_file_util_linux.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/file_path.h"
+
+namespace file_util {
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+  int fd = open(file.value().c_str(), O_RDONLY);
+  if (fd < 0)
+    return false;
+  if (fdatasync(fd) != 0)
+    return false;
+  if (posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED) != 0)
+    return false;
+  close(fd);
+  return true;
+}
+
+}  // namespace file_util
diff --git a/base/test/test_file_util_mac.cc b/base/test/test_file_util_mac.cc
new file mode 100644
index 0000000..7145e51
--- /dev/null
+++ b/base/test/test_file_util_mac.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <sys/mman.h>
+#include <errno.h>
+#include "base/logging.h"
+#include "base/file_util.h"
+
+namespace file_util {
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+  // There aren't any really direct ways to purge a file from the UBC.  From
+  // talking with Amit Singh, the safest is to mmap the file with MAP_FILE (the
+  // default) + MAP_SHARED, then do an msync to invalidate the memory.  The next
+  // open should then have to load the file from disk.
+
+  int64 length;
+  if (!file_util::GetFileSize(file, &length)) {
+    DLOG(ERROR) << "failed to get size of " << file.value();
+    return false;
+  }
+
+  // When a file is empty, we do not need to evict it from cache.
+  // In fact, an attempt to map it to memory will result in error.
+  if (length == 0) {
+    DLOG(WARNING) << "file size is zero, will not attempt to map to memory";
+    return true;
+  }
+
+  file_util::MemoryMappedFile mapped_file;
+  if (!mapped_file.Initialize(file)) {
+    DLOG(WARNING) << "failed to memory map " << file.value();
+    return false;
+  }
+
+  if (msync(const_cast<uint8*>(mapped_file.data()), mapped_file.length(),
+            MS_INVALIDATE) != 0) {
+    DLOG(WARNING) << "failed to invalidate memory map of " << file.value()
+                  << ", errno: " << errno;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace file_util
diff --git a/base/test/test_file_util_posix.cc b/base/test/test_file_util_posix.cc
new file mode 100644
index 0000000..5ebf335
--- /dev/null
+++ b/base/test/test_file_util_posix.cc
@@ -0,0 +1,191 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+
+namespace file_util {
+
+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 file_util::Delete(file, recurse);
+}
+
+// Mostly a verbatim copy of CopyDirectory
+bool CopyRecursiveDirNoCache(const FilePath& source_dir,
+                             const FilePath& dest_dir) {
+  char top_dir[PATH_MAX];
+  if (base::strlcpy(top_dir, source_dir.value().c_str(),
+                    arraysize(top_dir)) >= arraysize(top_dir)) {
+    return false;
+  }
+
+  // This function does not properly handle destinations within the source
+  FilePath real_to_path = dest_dir;
+  if (PathExists(real_to_path)) {
+    if (!AbsolutePath(&real_to_path))
+      return false;
+  } else {
+    real_to_path = real_to_path.DirName();
+    if (!AbsolutePath(&real_to_path))
+      return false;
+  }
+  if (real_to_path.value().compare(0, source_dir.value().size(),
+      source_dir.value()) == 0)
+    return false;
+
+  bool success = true;
+  int traverse_type = FileEnumerator::FILES |
+      FileEnumerator::SHOW_SYM_LINKS | FileEnumerator::DIRECTORIES;
+  FileEnumerator traversal(source_dir, true, traverse_type);
+
+  // dest_dir may not exist yet, start the loop with dest_dir
+  FileEnumerator::FindInfo info;
+  FilePath current = source_dir;
+  if (stat(source_dir.value().c_str(), &info.stat) < 0) {
+    DLOG(ERROR) << "CopyRecursiveDirNoCache() couldn't stat source directory: "
+                << source_dir.value() << " errno = " << errno;
+    success = false;
+  }
+
+  while (success && !current.empty()) {
+    // |current| is the source path, including source_dir, so paste
+    // the suffix after source_dir onto dest_dir to create the target_path.
+    std::string suffix(&current.value().c_str()[source_dir.value().size()]);
+    // Strip the leading '/' (if any).
+    if (!suffix.empty()) {
+      DCHECK_EQ('/', suffix[0]);
+      suffix.erase(0, 1);
+    }
+    const FilePath target_path = dest_dir.Append(suffix);
+
+    if (S_ISDIR(info.stat.st_mode)) {
+      if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 &&
+          errno != EEXIST) {
+        DLOG(ERROR) << "CopyRecursiveDirNoCache() couldn't create directory: "
+                    << target_path.value() << " errno = " << errno;
+        success = false;
+      }
+    } else if (S_ISREG(info.stat.st_mode)) {
+      if (CopyFile(current, target_path)) {
+        success = EvictFileFromSystemCache(target_path);
+        DCHECK(success);
+      } else {
+        DLOG(ERROR) << "CopyRecursiveDirNoCache() couldn't create file: "
+                    << target_path.value();
+        success = false;
+      }
+    } else {
+      DLOG(WARNING) << "CopyRecursiveDirNoCache() skipping non-regular file: "
+                    << current.value();
+    }
+
+    current = traversal.Next();
+    traversal.GetFindInfo(&info);
+  }
+
+  return success;
+}
+
+#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
+
+std::wstring FilePathAsWString(const FilePath& path) {
+  return UTF8ToWide(path.value());
+}
+FilePath WStringAsFilePath(const std::wstring& path) {
+  return FilePath(WideToUTF8(path));
+}
+
+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);
+}
+
+PermissionRestorer::PermissionRestorer(const FilePath& path)
+    : path_(path), info_(NULL), length_(0) {
+  info_ = GetPermissionInfo(path_, &length_);
+  DCHECK(info_ != NULL);
+  DCHECK_NE(0u, length_);
+}
+
+PermissionRestorer::~PermissionRestorer() {
+  if (!RestorePermissionInfo(path_, info_, length_))
+    NOTREACHED();
+}
+
+}  // namespace file_util
diff --git a/base/test/test_file_util_win.cc b/base/test/test_file_util_win.cc
new file mode 100644
index 0000000..41d69ea
--- /dev/null
+++ b/base/test/test_file_util_win.cc
@@ -0,0 +1,343 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <aclapi.h>
+#include <shlwapi.h>
+#include <windows.h>
+
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_split.h"
+#include "base/win/scoped_handle.h"
+#include "base/threading/platform_thread.h"
+
+namespace file_util {
+
+static const ptrdiff_t kOneMB = 1024 * 1024;
+
+namespace {
+
+struct PermissionInfo {
+  PSECURITY_DESCRIPTOR security_descriptor;
+  ACL dacl;
+};
+
+// Deny |permission| on the file |path|, for the current user.
+bool DenyFilePermission(const FilePath& path, DWORD permission) {
+  PACL old_dacl;
+  PSECURITY_DESCRIPTOR security_descriptor;
+  if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                           SE_FILE_OBJECT,
+                           DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl,
+                           NULL, &security_descriptor) != ERROR_SUCCESS) {
+    return false;
+  }
+
+  EXPLICIT_ACCESS change;
+  change.grfAccessPermissions = permission;
+  change.grfAccessMode = DENY_ACCESS;
+  change.grfInheritance = 0;
+  change.Trustee.pMultipleTrustee = NULL;
+  change.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+  change.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
+  change.Trustee.TrusteeType = TRUSTEE_IS_USER;
+  change.Trustee.ptstrName = L"CURRENT_USER";
+
+  PACL new_dacl;
+  if (SetEntriesInAcl(1, &change, old_dacl, &new_dacl) != ERROR_SUCCESS) {
+    LocalFree(security_descriptor);
+    return false;
+  }
+
+  DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                                  SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
+                                  NULL, NULL, new_dacl, NULL);
+  LocalFree(security_descriptor);
+  LocalFree(new_dacl);
+
+  return rc == ERROR_SUCCESS;
+}
+
+// Gets a blob indicating the permission information for |path|.
+// |length| is the length of the blob.  Zero on failure.
+// Returns the blob pointer, or NULL on failure.
+void* GetPermissionInfo(const FilePath& path, size_t* length) {
+  DCHECK(length != NULL);
+  *length = 0;
+  PACL dacl = NULL;
+  PSECURITY_DESCRIPTOR security_descriptor;
+  if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                           SE_FILE_OBJECT,
+                           DACL_SECURITY_INFORMATION, NULL, NULL, &dacl,
+                           NULL, &security_descriptor) != ERROR_SUCCESS) {
+    return NULL;
+  }
+  DCHECK(dacl != NULL);
+
+  *length = sizeof(PSECURITY_DESCRIPTOR) + dacl->AclSize;
+  PermissionInfo* info = reinterpret_cast<PermissionInfo*>(new char[*length]);
+  info->security_descriptor = security_descriptor;
+  memcpy(&info->dacl, dacl, dacl->AclSize);
+
+  return info;
+}
+
+// Restores the permission information for |path|, given the blob retrieved
+// using |GetPermissionInfo()|.
+// |info| is the pointer to the blob.
+// |length| is the length of the blob.
+// Either |info| or |length| may be NULL/0, in which case nothing happens.
+bool RestorePermissionInfo(const FilePath& path, void* info, size_t length) {
+  if (!info || !length)
+    return false;
+
+  PermissionInfo* perm = reinterpret_cast<PermissionInfo*>(info);
+
+  DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                                  SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
+                                  NULL, NULL, &perm->dacl, NULL);
+  LocalFree(perm->security_descriptor);
+
+  char* char_array = reinterpret_cast<char*>(info);
+  delete [] char_array;
+
+  return rc == ERROR_SUCCESS;
+}
+
+}  // namespace
+
+bool DieFileDie(const FilePath& file, bool recurse) {
+  // It turns out that to not induce flakiness a long timeout is needed.
+  const int kIterations = 25;
+  const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(10) /
+                                   kIterations;
+
+  if (!file_util::PathExists(file))
+    return true;
+
+  // Sometimes Delete fails, so try a few more times. Divide the timeout
+  // into short chunks, so that if a try succeeds, we won't delay the test
+  // for too long.
+  for (int i = 0; i < kIterations; ++i) {
+    if (file_util::Delete(file, recurse))
+      return true;
+    base::PlatformThread::Sleep(kTimeout);
+  }
+  return false;
+}
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+  // Request exclusive access to the file and overwrite it with no buffering.
+  base::win::ScopedHandle file_handle(
+      CreateFile(file.value().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                 OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL));
+  if (!file_handle)
+    return false;
+
+  // Get some attributes to restore later.
+  BY_HANDLE_FILE_INFORMATION bhi = {0};
+  CHECK(::GetFileInformationByHandle(file_handle, &bhi));
+
+  // Execute in chunks. It could be optimized. We want to do few of these since
+  // these operations will be slow without the cache.
+
+  // Allocate a buffer for the reads and the writes.
+  char* buffer = reinterpret_cast<char*>(VirtualAlloc(NULL,
+                                                      kOneMB,
+                                                      MEM_COMMIT | MEM_RESERVE,
+                                                      PAGE_READWRITE));
+
+  // If the file size isn't a multiple of kOneMB, we'll need special
+  // processing.
+  bool file_is_aligned = true;
+  int total_bytes = 0;
+  DWORD bytes_read, bytes_written;
+  for (;;) {
+    bytes_read = 0;
+    ::ReadFile(file_handle, buffer, kOneMB, &bytes_read, NULL);
+    if (bytes_read == 0)
+      break;
+
+    if (bytes_read < kOneMB) {
+      // Zero out the remaining part of the buffer.
+      // WriteFile will fail if we provide a buffer size that isn't a
+      // sector multiple, so we'll have to write the entire buffer with
+      // padded zeros and then use SetEndOfFile to truncate the file.
+      ZeroMemory(buffer + bytes_read, kOneMB - bytes_read);
+      file_is_aligned = false;
+    }
+
+    // Move back to the position we just read from.
+    // Note that SetFilePointer will also fail if total_bytes isn't sector
+    // aligned, but that shouldn't happen here.
+    DCHECK((total_bytes % kOneMB) == 0);
+    SetFilePointer(file_handle, total_bytes, NULL, FILE_BEGIN);
+    if (!::WriteFile(file_handle, buffer, kOneMB, &bytes_written, NULL) ||
+        bytes_written != kOneMB) {
+      BOOL freed = VirtualFree(buffer, 0, MEM_RELEASE);
+      DCHECK(freed);
+      NOTREACHED();
+      return false;
+    }
+
+    total_bytes += bytes_read;
+
+    // If this is false, then we just processed the last portion of the file.
+    if (!file_is_aligned)
+      break;
+  }
+
+  BOOL freed = VirtualFree(buffer, 0, MEM_RELEASE);
+  DCHECK(freed);
+
+  if (!file_is_aligned) {
+    // The size of the file isn't a multiple of 1 MB, so we'll have
+    // to open the file again, this time without the FILE_FLAG_NO_BUFFERING
+    // flag and use SetEndOfFile to mark EOF.
+    file_handle.Set(NULL);
+    file_handle.Set(CreateFile(file.value().c_str(), GENERIC_WRITE, 0, NULL,
+                               OPEN_EXISTING, 0, NULL));
+    CHECK_NE(SetFilePointer(file_handle, total_bytes, NULL, FILE_BEGIN),
+             INVALID_SET_FILE_POINTER);
+    CHECK(::SetEndOfFile(file_handle));
+  }
+
+  // Restore the file attributes.
+  CHECK(::SetFileTime(file_handle, &bhi.ftCreationTime, &bhi.ftLastAccessTime,
+                      &bhi.ftLastWriteTime));
+
+  return true;
+}
+
+// Like CopyFileNoCache but recursively copies all files and subdirectories
+// in the given input directory to the output directory.
+bool CopyRecursiveDirNoCache(const FilePath& source_dir,
+                             const FilePath& dest_dir) {
+  // Try to create the directory if it doesn't already exist.
+  if (!CreateDirectory(dest_dir)) {
+    if (GetLastError() != ERROR_ALREADY_EXISTS)
+      return false;
+  }
+
+  std::vector<std::wstring> files_copied;
+
+  FilePath src(source_dir.AppendASCII("*"));
+
+  WIN32_FIND_DATA fd;
+  HANDLE fh = FindFirstFile(src.value().c_str(), &fd);
+  if (fh == INVALID_HANDLE_VALUE)
+    return false;
+
+  do {
+    std::wstring cur_file(fd.cFileName);
+    if (cur_file == L"." || cur_file == L"..")
+      continue;  // Skip these special entries.
+
+    FilePath cur_source_path = source_dir.Append(cur_file);
+    FilePath cur_dest_path = dest_dir.Append(cur_file);
+
+    if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+      // Recursively copy a subdirectory. We stripped "." and ".." already.
+      if (!CopyRecursiveDirNoCache(cur_source_path, cur_dest_path)) {
+        FindClose(fh);
+        return false;
+      }
+    } else {
+      // Copy the file.
+      if (!::CopyFile(cur_source_path.value().c_str(),
+                      cur_dest_path.value().c_str(), false)) {
+        FindClose(fh);
+        return false;
+      }
+
+      // We don't check for errors from this function, often, we are copying
+      // files that are in the repository, and they will have read-only set.
+      // This will prevent us from evicting from the cache, but these don't
+      // matter anyway.
+      EvictFileFromSystemCache(cur_dest_path);
+    }
+  } while (FindNextFile(fh, &fd));
+
+  FindClose(fh);
+  return true;
+}
+
+// Checks if the volume supports Alternate Data Streams. This is required for
+// the Zone Identifier implementation.
+bool VolumeSupportsADS(const FilePath& path) {
+  wchar_t drive[MAX_PATH] = {0};
+  wcscpy_s(drive, MAX_PATH, path.value().c_str());
+
+  if (!PathStripToRootW(drive))
+    return false;
+
+  DWORD fs_flags = 0;
+  if (!GetVolumeInformationW(drive, NULL, 0, 0, NULL, &fs_flags, NULL, 0))
+    return false;
+
+  if (fs_flags & FILE_NAMED_STREAMS)
+    return true;
+
+  return false;
+}
+
+// Return whether the ZoneIdentifier is correctly set to "Internet" (3)
+// Only returns a valid result when called from same process as the
+// one that (was supposed to have) set the zone identifier.
+bool HasInternetZoneIdentifier(const FilePath& full_path) {
+  FilePath zone_path(full_path.value() + L":Zone.Identifier");
+  std::string zone_path_contents;
+  if (!file_util::ReadFileToString(zone_path, &zone_path_contents))
+    return false;
+
+  std::vector<std::string> lines;
+  // This call also trims whitespaces, including carriage-returns (\r).
+  base::SplitString(zone_path_contents, '\n', &lines);
+
+  switch (lines.size()) {
+    case 3:
+      // optional empty line at end of file:
+      if (lines[2] != "")
+        return false;
+      // fall through:
+    case 2:
+      return lines[0] == "[ZoneTransfer]" && lines[1] == "ZoneId=3";
+    default:
+      return false;
+  }
+}
+
+std::wstring FilePathAsWString(const FilePath& path) {
+  return path.value();
+}
+FilePath WStringAsFilePath(const std::wstring& path) {
+  return FilePath(path);
+}
+
+bool MakeFileUnreadable(const FilePath& path) {
+  return DenyFilePermission(path, GENERIC_READ);
+}
+
+bool MakeFileUnwritable(const FilePath& path) {
+  return DenyFilePermission(path, GENERIC_WRITE);
+}
+
+PermissionRestorer::PermissionRestorer(const FilePath& path)
+    : path_(path), info_(NULL), length_(0) {
+  info_ = GetPermissionInfo(path_, &length_);
+  DCHECK(info_ != NULL);
+  DCHECK_NE(0u, length_);
+}
+
+PermissionRestorer::~PermissionRestorer() {
+  if (!RestorePermissionInfo(path_, info_, length_))
+    NOTREACHED();
+}
+
+}  // namespace file_util
diff --git a/base/test/test_listener_ios.h b/base/test/test_listener_ios.h
new file mode 100644
index 0000000..c312250
--- /dev/null
+++ b/base/test/test_listener_ios.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_LISTENER_IOS_H_
+#define BASE_TEST_TEST_LISTENER_IOS_H_
+
+namespace base {
+namespace test_listener_ios {
+
+// Register an IOSRunLoopListener.
+void RegisterTestEndListener();
+
+}  // namespace test_listener_ios
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_LISTENER_IOS_H_
diff --git a/base/test/test_listener_ios.mm b/base/test/test_listener_ios.mm
new file mode 100644
index 0000000..12cf5bb
--- /dev/null
+++ b/base/test/test_listener_ios.mm
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_listener_ios.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// The iOS watchdog timer will kill an app that doesn't spin the main event
+// loop often enough. This uses a Gtest TestEventListener to spin the current
+// loop after each test finishes. However, if any individual test takes too
+// long, it is still possible that the app will get killed.
+
+namespace {
+
+class IOSRunLoopListener : public testing::EmptyTestEventListener {
+ public:
+  virtual void OnTestEnd(const testing::TestInfo& test_info);
+};
+
+void IOSRunLoopListener::OnTestEnd(const testing::TestInfo& test_info) {
+  base::mac::ScopedNSAutoreleasePool scoped_pool;
+
+  // At the end of the test, spin the default loop for a moment.
+  NSDate* stop_date = [NSDate dateWithTimeIntervalSinceNow:0.001];
+  [[NSRunLoop currentRunLoop] runUntilDate:stop_date];
+}
+
+}  // namespace
+
+
+namespace base {
+namespace test_listener_ios {
+
+void RegisterTestEndListener() {
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(new IOSRunLoopListener);
+}
+
+}  // namespace test_listener_ios
+}  // namespace base
diff --git a/base/test/test_reg_util_win.cc b/base/test/test_reg_util_win.cc
new file mode 100644
index 0000000..e23c6e9
--- /dev/null
+++ b/base/test/test_reg_util_win.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.
+
+#include "base/test/test_reg_util_win.h"
+
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace registry_util {
+
+const wchar_t RegistryOverrideManager::kTempTestKeyPath[] =
+    L"Software\\Chromium\\TempTestKeys";
+
+RegistryOverrideManager::ScopedRegistryKeyOverride::ScopedRegistryKeyOverride(
+    HKEY override,
+    const std::wstring& temp_name)
+    : override_(override),
+      temp_name_(temp_name) {
+  DCHECK(!temp_name_.empty());
+  std::wstring key_path(RegistryOverrideManager::kTempTestKeyPath);
+  key_path += L"\\" + temp_name_;
+  EXPECT_EQ(ERROR_SUCCESS,
+      temp_key_.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS));
+  EXPECT_EQ(ERROR_SUCCESS,
+            ::RegOverridePredefKey(override_, temp_key_.Handle()));
+}
+
+RegistryOverrideManager::
+    ScopedRegistryKeyOverride::~ScopedRegistryKeyOverride() {
+  ::RegOverridePredefKey(override_, NULL);
+  // The temp key will be deleted via a call to DeleteAllTempKeys().
+}
+
+RegistryOverrideManager::RegistryOverrideManager() {
+  DeleteAllTempKeys();
+}
+
+RegistryOverrideManager::~RegistryOverrideManager() {
+  RemoveAllOverrides();
+}
+
+void RegistryOverrideManager::OverrideRegistry(HKEY override,
+                                               const std::wstring& temp_name) {
+  overrides_.push_back(new ScopedRegistryKeyOverride(override, temp_name));
+}
+
+void RegistryOverrideManager::RemoveAllOverrides() {
+  while (!overrides_.empty()) {
+    delete overrides_.back();
+    overrides_.pop_back();
+  }
+
+  DeleteAllTempKeys();
+}
+
+// static
+void RegistryOverrideManager::DeleteAllTempKeys() {
+  base::win::RegKey key;
+  if (key.Open(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS) == ERROR_SUCCESS) {
+    key.DeleteKey(kTempTestKeyPath);
+  }
+}
+
+}  // namespace registry_util
diff --git a/base/test/test_reg_util_win.h b/base/test/test_reg_util_win.h
new file mode 100644
index 0000000..b71831f
--- /dev/null
+++ b/base/test/test_reg_util_win.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_REG_UTIL_H_
+#define BASE_TEST_TEST_REG_UTIL_H_
+
+// Registry utility functions used only by tests.
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/win/registry.h"
+
+namespace registry_util {
+
+// Allows a test to easily override registry hives so that it can start from a
+// known good state, or make sure to not leave any side effects once the test
+// completes.
+class RegistryOverrideManager {
+ public:
+  // All overridden hives will be descendents of this registry path under the
+  // main HKCU hive.
+  static const wchar_t kTempTestKeyPath[];
+
+  RegistryOverrideManager();
+  ~RegistryOverrideManager();
+
+  // Override the given registry hive using a temporary key named by temp_name
+  // under the temporary test key path.
+  void OverrideRegistry(HKEY override, const std::wstring& temp_name);
+
+  // Deletes all temporary test keys used by the overrides.
+  static void DeleteAllTempKeys();
+
+  // Removes all overrides and deletes all temporary test keys used by the
+  // overrides.
+  void RemoveAllOverrides();
+
+ private:
+  // Keeps track of one override.
+  class ScopedRegistryKeyOverride {
+   public:
+    ScopedRegistryKeyOverride(HKEY override, const std::wstring& temp_name);
+    ~ScopedRegistryKeyOverride();
+
+   private:
+    HKEY override_;
+    base::win::RegKey temp_key_;
+    std::wstring temp_name_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedRegistryKeyOverride);
+  };
+
+  std::vector<ScopedRegistryKeyOverride*> overrides_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegistryOverrideManager);
+};
+
+}  // namespace registry_util
+
+#endif  // BASE_TEST_TEST_REG_UTIL_H_
diff --git a/base/test/test_shortcut_win.cc b/base/test/test_shortcut_win.cc
new file mode 100644
index 0000000..f84c0d0
--- /dev/null
+++ b/base/test/test_shortcut_win.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_shortcut_win.h"
+
+#include <windows.h>
+#include <shlobj.h>
+#include <propkey.h>
+#include <propvarutil.h>
+
+#include "base/file_path.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// propsys.lib is required for PropvariantTo*().
+#pragma comment(lib, "propsys.lib")
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Validates |actual_path|'s LongPathName case-insensitively matches
+// |expected_path|'s LongPathName.
+void ValidatePathsAreEqual(const FilePath& expected_path,
+                           const FilePath& actual_path) {
+  wchar_t long_expected_path_chars[MAX_PATH] = {0};
+  wchar_t long_actual_path_chars[MAX_PATH] = {0};
+
+  // If |expected_path| is empty confirm immediately that |actual_path| is also
+  // empty.
+  if (expected_path.empty()) {
+    EXPECT_TRUE(actual_path.empty());
+    return;
+  }
+
+  // Proceed with LongPathName matching which will also confirm the paths exist.
+  EXPECT_NE(0U, ::GetLongPathName(
+      expected_path.value().c_str(), long_expected_path_chars, MAX_PATH))
+          << "Failed to get LongPathName of " << expected_path.value();
+  EXPECT_NE(0U, ::GetLongPathName(
+      actual_path.value().c_str(), long_actual_path_chars, MAX_PATH))
+          << "Failed to get LongPathName of " << actual_path.value();
+
+  FilePath long_expected_path(long_expected_path_chars);
+  FilePath long_actual_path(long_actual_path_chars);
+  EXPECT_FALSE(long_expected_path.empty());
+  EXPECT_FALSE(long_actual_path.empty());
+
+  EXPECT_EQ(long_expected_path, long_actual_path);
+}
+
+}  // namespace
+
+void ValidateShortcut(const FilePath& shortcut_path,
+                      const ShortcutProperties& properties) {
+  ScopedComPtr<IShellLink> i_shell_link;
+  ScopedComPtr<IPersistFile> i_persist_file;
+
+  wchar_t read_target[MAX_PATH] = {0};
+  wchar_t read_working_dir[MAX_PATH] = {0};
+  wchar_t read_arguments[MAX_PATH] = {0};
+  wchar_t read_description[MAX_PATH] = {0};
+  wchar_t read_icon[MAX_PATH] = {0};
+  int read_icon_index = 0;
+
+  HRESULT hr;
+
+  // Initialize the shell interfaces.
+  EXPECT_TRUE(SUCCEEDED(hr = i_shell_link.CreateInstance(
+      CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER)));
+  if (FAILED(hr))
+    return;
+
+  EXPECT_TRUE(SUCCEEDED(hr = i_persist_file.QueryFrom(i_shell_link)));
+  if (FAILED(hr))
+    return;
+
+  // Load the shortcut.
+  EXPECT_TRUE(SUCCEEDED(hr = i_persist_file->Load(
+      shortcut_path.value().c_str(), 0))) << "Failed to load shortcut at "
+                                          << shortcut_path.value();
+  if (FAILED(hr))
+    return;
+
+  if (properties.options & ShortcutProperties::PROPERTIES_TARGET) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetPath(read_target, MAX_PATH, NULL, SLGP_SHORTPATH)));
+    ValidatePathsAreEqual(properties.target, FilePath(read_target));
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetWorkingDirectory(read_working_dir, MAX_PATH)));
+    ValidatePathsAreEqual(properties.working_dir, FilePath(read_working_dir));
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetArguments(read_arguments, MAX_PATH)));
+    EXPECT_EQ(properties.arguments, read_arguments);
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetDescription(read_description, MAX_PATH)));
+    EXPECT_EQ(properties.description, read_description);
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_ICON) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetIconLocation(read_icon, MAX_PATH, &read_icon_index)));
+    ValidatePathsAreEqual(properties.icon, FilePath(read_icon));
+    EXPECT_EQ(properties.icon_index, read_icon_index);
+  }
+
+  if (GetVersion() >= VERSION_WIN7) {
+    ScopedComPtr<IPropertyStore> property_store;
+    // Note that, as mentioned on MSDN at http://goo.gl/M8h9g, if a property is
+    // not set, GetValue will return S_OK and the PROPVARIANT will be set to
+    // VT_EMPTY.
+    PROPVARIANT pv_app_id, pv_dual_mode;
+    EXPECT_TRUE(SUCCEEDED(hr = property_store.QueryFrom(i_shell_link)));
+    if (FAILED(hr))
+      return;
+    EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_ID, &pv_app_id));
+    EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_IsDualMode,
+                                             &pv_dual_mode));
+
+    // Note, as mentioned on MSDN at
+    // http://msdn.microsoft.com/library/windows/desktop/bb776559.aspx, if
+    // |pv_app_id| is a VT_EMPTY it is successfully converted to the empty
+    // string as desired.
+    wchar_t read_app_id[MAX_PATH] = {0};
+    PropVariantToString(pv_app_id, read_app_id, MAX_PATH);
+    if (properties.options & ShortcutProperties::PROPERTIES_APP_ID)
+      EXPECT_EQ(properties.app_id, read_app_id);
+
+    // Note, as mentioned on MSDN at
+    // http://msdn.microsoft.com/library/windows/desktop/bb776531.aspx, if
+    // |pv_dual_mode| is a VT_EMPTY it is successfully converted to false as
+    // desired.
+    BOOL read_dual_mode;
+    PropVariantToBoolean(pv_dual_mode, &read_dual_mode);
+    if (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE)
+      EXPECT_EQ(properties.dual_mode, static_cast<bool>(read_dual_mode));
+  }
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/test/test_shortcut_win.h b/base/test/test_shortcut_win.h
new file mode 100644
index 0000000..ef75713
--- /dev/null
+++ b/base/test/test_shortcut_win.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_TEST_TEST_SHORTCUT_WIN_H_
+#define BASE_TEST_TEST_SHORTCUT_WIN_H_
+
+#include "base/file_path.h"
+#include "base/win/shortcut.h"
+
+// Windows shortcut functions used only by tests.
+
+namespace base {
+namespace win {
+
+// Validates that a shortcut exists at |shortcut_path| with the expected
+// |properties|.
+// Logs gtest failures on failed verifications.
+void ValidateShortcut(const FilePath& shortcut_path,
+                      const ShortcutProperties& properties);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SHORTCUT_WIN_H_
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
new file mode 100644
index 0000000..824fbc6
--- /dev/null
+++ b/base/test/test_suite.cc
@@ -0,0 +1,298 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_suite.h"
+
+#include "base/at_exit.h"
+#include "base/base_paths.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/debug/debug_on_start_win.h"
+#include "base/debug/debugger.h"
+#include "base/debug/stack_trace.h"
+#include "base/file_path.h"
+#include "base/i18n/icu_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#if defined(OS_IOS)
+#include "base/test/test_listener_ios.h"
+#else
+#include "base/test/mock_chrome_application_mac.h"
+#endif  // OS_IOS
+#endif  // OS_MACOSX
+
+#if defined(OS_ANDROID)
+#include "base/test/test_support_android.h"
+#endif
+
+#if defined(OS_IOS)
+#include "base/test/test_support_ios.h"
+#endif
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+#endif
+
+namespace {
+
+class MaybeTestDisabler : public testing::EmptyTestEventListener {
+ public:
+  virtual void OnTestStart(const testing::TestInfo& test_info) OVERRIDE {
+    ASSERT_FALSE(TestSuite::IsMarkedMaybe(test_info))
+        << "Probably the OS #ifdefs don't include all of the necessary "
+           "platforms.\nPlease ensure that no tests have the MAYBE_ prefix "
+           "after the code is preprocessed.";
+  }
+};
+
+class TestClientInitializer : public testing::EmptyTestEventListener {
+ public:
+  TestClientInitializer()
+      : old_command_line_(CommandLine::NO_PROGRAM) {
+  }
+
+  virtual void OnTestStart(const testing::TestInfo& test_info) OVERRIDE {
+    old_command_line_ = *CommandLine::ForCurrentProcess();
+  }
+
+  virtual void OnTestEnd(const testing::TestInfo& test_info) OVERRIDE {
+    *CommandLine::ForCurrentProcess() = old_command_line_;
+  }
+
+ private:
+  CommandLine old_command_line_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestClientInitializer);
+};
+
+}  // namespace
+
+const char TestSuite::kStrictFailureHandling[] = "strict_failure_handling";
+
+TestSuite::TestSuite(int argc, char** argv) : initialized_command_line_(false) {
+  PreInitialize(argc, argv, true);
+}
+
+TestSuite::TestSuite(int argc, char** argv, bool create_at_exit_manager)
+    : initialized_command_line_(false) {
+  PreInitialize(argc, argv, create_at_exit_manager);
+}
+
+TestSuite::~TestSuite() {
+  if (initialized_command_line_)
+    CommandLine::Reset();
+}
+
+void TestSuite::PreInitialize(int argc, char** argv,
+                              bool create_at_exit_manager) {
+#if defined(OS_WIN)
+  testing::GTEST_FLAG(catch_exceptions) = false;
+#endif
+  base::EnableTerminationOnHeapCorruption();
+  initialized_command_line_ = CommandLine::Init(argc, argv);
+  testing::InitGoogleTest(&argc, argv);
+#if defined(OS_LINUX) && defined(USE_AURA)
+  // When calling native char conversion functions (e.g wrctomb) we need to
+  // have the locale set. In the absence of such a call the "C" locale is the
+  // default. In the gtk code (below) gtk_init() implicitly sets a locale.
+  setlocale(LC_ALL, "");
+#elif defined(TOOLKIT_GTK)
+  gtk_init_check(&argc, &argv);
+#endif  // defined(TOOLKIT_GTK)
+
+  // On Android, AtExitManager is created in
+  // testing/android/native_test_wrapper.cc before main() is called.
+#if !defined(OS_ANDROID)
+  if (create_at_exit_manager)
+    at_exit_manager_.reset(new base::AtExitManager);
+#endif
+
+  // Don't add additional code to this function.  Instead add it to
+  // Initialize().  See bug 6436.
+}
+
+
+// static
+bool TestSuite::IsMarkedFlaky(const testing::TestInfo& test) {
+  return strncmp(test.name(), "FLAKY_", 6) == 0;
+}
+
+// static
+bool TestSuite::IsMarkedMaybe(const testing::TestInfo& test) {
+  return strncmp(test.name(), "MAYBE_", 6) == 0;
+}
+
+// static
+bool TestSuite::ShouldIgnoreFailure(const testing::TestInfo& test) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(kStrictFailureHandling))
+    return false;
+  return IsMarkedFlaky(test);
+}
+
+// static
+bool TestSuite::NonIgnoredFailures(const testing::TestInfo& test) {
+  return test.should_run() && test.result()->Failed() &&
+      !ShouldIgnoreFailure(test);
+}
+
+int TestSuite::GetTestCount(TestMatch test_match) {
+  testing::UnitTest* instance = testing::UnitTest::GetInstance();
+  int count = 0;
+
+  for (int i = 0; i < instance->total_test_case_count(); ++i) {
+    const testing::TestCase& test_case = *instance->GetTestCase(i);
+    for (int j = 0; j < test_case.total_test_count(); ++j) {
+      if (test_match(*test_case.GetTestInfo(j))) {
+        count++;
+      }
+    }
+  }
+
+  return count;
+}
+
+void TestSuite::CatchMaybeTests() {
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(new MaybeTestDisabler);
+}
+
+void TestSuite::ResetCommandLine() {
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(new TestClientInitializer);
+}
+
+// Don't add additional code to this method.  Instead add it to
+// Initialize().  See bug 6436.
+int TestSuite::Run() {
+#if defined(OS_MACOSX)
+  base::mac::ScopedNSAutoreleasePool scoped_pool;
+#endif
+
+  Initialize();
+  std::string client_func =
+      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kTestChildProcess);
+
+  // Check to see if we are being run as a client process.
+  if (!client_func.empty())
+    return multi_process_function_list::InvokeChildProcessTest(client_func);
+#if defined(OS_IOS)
+  base::test_listener_ios::RegisterTestEndListener();
+#endif
+  int result = RUN_ALL_TESTS();
+
+  // If there are failed tests, see if we should ignore the failures.
+  if (result != 0 && GetTestCount(&TestSuite::NonIgnoredFailures) == 0)
+    result = 0;
+
+  // Display the number of flaky tests.
+  int flaky_count = GetTestCount(&TestSuite::IsMarkedFlaky);
+  if (flaky_count) {
+    printf("  YOU HAVE %d FLAKY %s\n\n", flaky_count,
+           flaky_count == 1 ? "TEST" : "TESTS");
+  }
+
+#if defined(OS_MACOSX)
+  // This MUST happen before Shutdown() since Shutdown() tears down
+  // objects (such as NotificationService::current()) that Cocoa
+  // objects use to remove themselves as observers.
+  scoped_pool.Recycle();
+#endif
+
+  Shutdown();
+
+  return result;
+}
+
+// static
+void TestSuite::UnitTestAssertHandler(const std::string& str) {
+  RAW_LOG(FATAL, str.c_str());
+}
+
+void TestSuite::SuppressErrorDialogs() {
+#if defined(OS_WIN)
+  UINT new_flags = SEM_FAILCRITICALERRORS |
+                   SEM_NOGPFAULTERRORBOX |
+                   SEM_NOOPENFILEERRORBOX;
+
+  // Preserve existing error mode, as discussed at
+  // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
+  UINT existing_flags = SetErrorMode(new_flags);
+  SetErrorMode(existing_flags | new_flags);
+
+#if defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1)
+  // Suppress the "Debug Assertion Failed" dialog.
+  // TODO(hbono): remove this code when gtest has it.
+  // http://groups.google.com/d/topic/googletestframework/OjuwNlXy5ac/discussion
+  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+#endif  // defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1)
+#endif  // defined(OS_WIN)
+}
+
+void TestSuite::Initialize() {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // Some of the app unit tests spin runloops.
+  mock_cr_app::RegisterMockCrApp();
+#endif
+
+#if defined(OS_IOS)
+  InitIOSTestMessageLoop();
+#endif  // OS_IOS
+
+#if defined(OS_ANDROID)
+  InitAndroidTest();
+#else
+  // Initialize logging.
+  FilePath exe;
+  PathService::Get(base::FILE_EXE, &exe);
+  FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
+  logging::InitLogging(
+      log_filename.value().c_str(),
+      logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
+      logging::LOCK_LOG_FILE,
+      logging::DELETE_OLD_LOG_FILE,
+      logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
+  // We want process and thread IDs because we may have multiple processes.
+  // Note: temporarily enabled timestamps in an effort to catch bug 6361.
+  logging::SetLogItems(true, true, true, true);
+#endif  // else defined(OS_ANDROID)
+
+  CHECK(base::debug::EnableInProcessStackDumping());
+#if defined(OS_WIN)
+  // Make sure we run with high resolution timer to minimize differences
+  // between production code and test code.
+  base::Time::EnableHighResolutionTimer(true);
+#endif  // defined(OS_WIN)
+
+  // In some cases, we do not want to see standard error dialogs.
+  if (!base::debug::BeingDebugged() &&
+      !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) {
+    SuppressErrorDialogs();
+    base::debug::SetSuppressDebugUI(true);
+    logging::SetLogAssertHandler(UnitTestAssertHandler);
+  }
+
+  icu_util::Initialize();
+
+  CatchMaybeTests();
+  ResetCommandLine();
+
+  TestTimeouts::Initialize();
+}
+
+void TestSuite::Shutdown() {
+}
diff --git a/base/test/test_suite.h b/base/test/test_suite.h
new file mode 100644
index 0000000..1758f86
--- /dev/null
+++ b/base/test/test_suite.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SUITE_H_
+#define BASE_TEST_TEST_SUITE_H_
+
+// Defines a basic test suite framework for running gtest based tests.  You can
+// instantiate this class in your main function and call its Run method to run
+// any gtest based tests that are linked into your executable.
+
+#include <string>
+
+#include "base/at_exit.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace testing {
+class TestInfo;
+}
+
+namespace base {
+
+class TestSuite {
+ public:
+  // Match function used by the GetTestCount method.
+  typedef bool (*TestMatch)(const testing::TestInfo&);
+
+  TestSuite(int argc, char** argv);
+  virtual ~TestSuite();
+
+  // Returns true if the test is marked as flaky.
+  static bool IsMarkedFlaky(const testing::TestInfo& test);
+
+  // Returns true if the test is marked as failing.
+  static bool IsMarkedFailing(const testing::TestInfo& test);
+
+  // Returns true if the test is marked as "MAYBE_".
+  // When using different prefixes depending on platform, we use MAYBE_ and
+  // preprocessor directives to replace MAYBE_ with the target prefix.
+  static bool IsMarkedMaybe(const testing::TestInfo& test);
+
+  // Returns true if the test failure should be ignored.
+  static bool ShouldIgnoreFailure(const testing::TestInfo& test);
+
+  // Returns true if the test failed and the failure shouldn't be ignored.
+  static bool NonIgnoredFailures(const testing::TestInfo& test);
+
+  // Returns the number of tests where the match function returns true.
+  int GetTestCount(TestMatch test_match);
+
+  void CatchMaybeTests();
+
+  void ResetCommandLine();
+
+  int Run();
+
+  // A command-line flag that makes a test failure always result in a non-zero
+  // process exit code.
+  static const char kStrictFailureHandling[];
+
+ protected:
+  // This constructor is only accessible to specialized test suite
+  // implementations which need to control the creation of an AtExitManager
+  // instance for the duration of the test.
+  TestSuite(int argc, char** argv, bool create_at_exit_manager);
+
+  // By default fatal log messages (e.g. from DCHECKs) result in error dialogs
+  // which gum up buildbots. Use a minimalistic assert handler which just
+  // terminates the process.
+  static void UnitTestAssertHandler(const std::string& str);
+
+  // Disable crash dialogs so that it doesn't gum up the buildbot
+  virtual void SuppressErrorDialogs();
+
+  // Override these for custom initialization and shutdown handling.  Use these
+  // instead of putting complex code in your constructor/destructor.
+
+  virtual void Initialize();
+  virtual void Shutdown();
+
+  // Make sure that we setup an AtExitManager so Singleton objects will be
+  // destroyed.
+  scoped_ptr<base::AtExitManager> at_exit_manager_;
+
+ private:
+  // Basic initialization for the test suite happens here.
+  void PreInitialize(int argc, char** argv, bool create_at_exit_manager);
+
+  bool initialized_command_line_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestSuite);
+};
+
+}  // namespace base
+
+// TODO(brettw) remove this. This is a temporary hack to allow WebKit to compile
+// until we can update it to use "base::" (preventing a two-sided patch).
+using base::TestSuite;
+
+#endif  // BASE_TEST_TEST_SUITE_H_
diff --git a/base/test/test_support_android.cc b/base/test/test_support_android.cc
new file mode 100644
index 0000000..8b512f4
--- /dev/null
+++ b/base/test/test_support_android.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "base/android/path_utils.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/message_loop.h"
+#include "base/message_pump_android.h"
+#include "base/path_service.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace {
+
+struct RunState {
+  RunState(base::MessagePump::Delegate* delegate, int run_depth)
+      : delegate(delegate),
+        run_depth(run_depth),
+        should_quit(false) {
+  }
+
+  base::MessagePump::Delegate* delegate;
+
+  // Used to count how many Run() invocations are on the stack.
+  int run_depth;
+
+  // Used to flag that the current Run() invocation should return ASAP.
+  bool should_quit;
+};
+
+RunState* g_state = NULL;
+
+// A singleton WaitableEvent wrapper so we avoid a busy loop in
+// MessagePumpForUIStub. Other platforms use the native event loop which blocks
+// when there are no pending messages.
+class Waitable {
+ public:
+   static Waitable* GetInstance() {
+     return Singleton<Waitable>::get();
+   }
+
+   // Signals that there are more work to do.
+   void Signal() {
+     waitable_event_.Signal();
+   }
+
+   // Blocks until more work is scheduled.
+   void Block() {
+     waitable_event_.Wait();
+   }
+
+   void Quit() {
+     g_state->should_quit = true;
+     Signal();
+   }
+
+ private:
+  friend struct DefaultSingletonTraits<Waitable>;
+
+  Waitable()
+      : waitable_event_(false, false) {
+  }
+
+  base::WaitableEvent waitable_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(Waitable);
+};
+
+// The MessagePumpForUI implementation for test purpose.
+class MessagePumpForUIStub : public base::MessagePumpForUI {
+  virtual void Start(base::MessagePump::Delegate* delegate) OVERRIDE {
+    NOTREACHED() << "The Start() method shouldn't be called in test, using"
+        " Run() method should be used.";
+  }
+
+  virtual void Run(base::MessagePump::Delegate* delegate) OVERRIDE {
+    // The following was based on message_pump_glib.cc, except we're using a
+    // WaitableEvent since there are no native message loop to use.
+    RunState state(delegate, g_state ? g_state->run_depth + 1 : 1);
+
+    RunState* previous_state = g_state;
+    g_state = &state;
+
+    bool more_work_is_plausible = true;
+
+    for (;;) {
+      if (!more_work_is_plausible) {
+        Waitable::GetInstance()->Block();
+        if (g_state->should_quit)
+          break;
+      }
+
+      more_work_is_plausible = g_state->delegate->DoWork();
+      if (g_state->should_quit)
+        break;
+
+      base::TimeTicks delayed_work_time;
+      more_work_is_plausible |=
+          g_state->delegate->DoDelayedWork(&delayed_work_time);
+      if (g_state->should_quit)
+        break;
+
+      if (more_work_is_plausible)
+        continue;
+
+      more_work_is_plausible = g_state->delegate->DoIdleWork();
+      if (g_state->should_quit)
+        break;
+
+      more_work_is_plausible |= !delayed_work_time.is_null();
+    }
+
+    g_state = previous_state;
+  }
+
+  virtual void Quit() OVERRIDE {
+    Waitable::GetInstance()->Quit();
+  }
+
+  virtual void ScheduleWork() OVERRIDE {
+    Waitable::GetInstance()->Signal();
+  }
+
+  virtual void ScheduleDelayedWork(
+      const base::TimeTicks& delayed_work_time) OVERRIDE {
+    Waitable::GetInstance()->Signal();
+  }
+
+ protected:
+  virtual ~MessagePumpForUIStub() {}
+};
+
+base::MessagePump* CreateMessagePumpForUIStub() {
+  return new MessagePumpForUIStub();
+};
+
+// Provides the test path for DIR_MODULE and DIR_ANDROID_APP_DATA.
+bool GetTestProviderPath(int key, FilePath* result) {
+  switch (key) {
+    case base::DIR_MODULE: {
+      return base::android::GetExternalStorageDirectory(result);
+    }
+    case base::DIR_ANDROID_APP_DATA: {
+      // For tests, app data is put in external storage.
+      return base::android::GetExternalStorageDirectory(result);
+    }
+    default:
+      return false;
+  }
+}
+
+void InitPathProvider(int key) {
+  FilePath path;
+  // If failed to override the key, that means the way has not been registered.
+  if (GetTestProviderPath(key, &path) && !PathService::Override(key, path))
+    PathService::RegisterProvider(&GetTestProviderPath, key, key + 1);
+}
+
+}  // namespace
+
+namespace base {
+
+void InitAndroidTestLogging() {
+  logging::InitLogging(NULL,
+                       logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
+                       logging::DONT_LOCK_LOG_FILE,
+                       logging::DELETE_OLD_LOG_FILE,
+                       logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
+  // To view log output with IDs and timestamps use "adb logcat -v threadtime".
+  logging::SetLogItems(false,    // Process ID
+                       false,    // Thread ID
+                       false,    // Timestamp
+                       false);   // Tick count
+}
+
+void InitAndroidTestPaths() {
+  InitPathProvider(DIR_MODULE);
+  InitPathProvider(DIR_ANDROID_APP_DATA);
+}
+
+void InitAndroidTestMessageLoop() {
+  MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIStub);
+}
+
+void InitAndroidTest() {
+  InitAndroidTestLogging();
+  InitAndroidTestPaths();
+  InitAndroidTestMessageLoop();
+}
+}  // namespace base
diff --git a/base/test/test_support_android.h b/base/test/test_support_android.h
new file mode 100644
index 0000000..062785e
--- /dev/null
+++ b/base/test/test_support_android.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SUPPORT_ANDROID_H_
+#define BASE_TEST_TEST_SUPPORT_ANDROID_H_
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Init logging for tests on Android. Logs will be output into Android's logcat.
+BASE_EXPORT void InitAndroidTestLogging();
+
+// Init path providers for tests on Android.
+BASE_EXPORT void InitAndroidTestPaths();
+
+// Init the message loop for tests on Android.
+BASE_EXPORT void InitAndroidTestMessageLoop();
+
+// Do all of the initializations above.
+BASE_EXPORT void InitAndroidTest();
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SUPPORT_ANDROID_H_
diff --git a/base/test/test_support_ios.h b/base/test/test_support_ios.h
new file mode 100644
index 0000000..35b5b19
--- /dev/null
+++ b/base/test/test_support_ios.h
@@ -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.
+
+#ifndef BASE_TEST_TEST_SUPPORT_IOS_H_
+#define BASE_TEST_TEST_SUPPORT_IOS_H_
+
+namespace base {
+
+// Init the message loop for tests on iOS.
+void InitIOSTestMessageLoop();
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SUPPORT_IOS_H_
diff --git a/base/test/test_support_ios.mm b/base/test/test_support_ios.mm
new file mode 100644
index 0000000..01b5158
--- /dev/null
+++ b/base/test/test_support_ios.mm
@@ -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/message_loop.h"
+#include "base/message_pump_default.h"
+
+namespace {
+
+base::MessagePump* CreateMessagePumpForUIForTests() {
+  // A default MessagePump will do quite nicely in tests.
+  return new base::MessagePumpDefault();
+}
+
+}  // namespace
+
+namespace base {
+
+void InitIOSTestMessageLoop() {
+  MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIForTests);
+}
+
+}  // namespace base
diff --git a/base/test/test_switches.cc b/base/test/test_switches.cc
new file mode 100644
index 0000000..79fbad1
--- /dev/null
+++ b/base/test/test_switches.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 The Chromium Authors. All 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"
+
+// Time (in milliseconds) that the tests should wait before timing out.
+// TODO(phajdan.jr): Clean up the switch names.
+const char switches::kTestLargeTimeout[] = "test-large-timeout";
+const char switches::kTestTinyTimeout[] = "test-tiny-timeout";
+const char switches::kUiTestActionTimeout[] = "ui-test-action-timeout";
+const char switches::kUiTestActionMaxTimeout[] = "ui-test-action-max-timeout";
diff --git a/base/test/test_switches.h b/base/test/test_switches.h
new file mode 100644
index 0000000..a5665d4
--- /dev/null
+++ b/base/test/test_switches.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 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 kTestLargeTimeout[];
+extern const char kTestTinyTimeout[];
+extern const char kUiTestActionTimeout[];
+extern const char kUiTestActionMaxTimeout[];
+
+}  // namespace switches
+
+#endif  // BASE_TEST_TEST_SWITCHES_H_
diff --git a/base/test/test_timeouts.cc b/base/test/test_timeouts.cc
new file mode 100644
index 0000000..dc7f243
--- /dev/null
+++ b/base/test/test_timeouts.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_timeouts.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/test/test_switches.h"
+
+namespace {
+
+#ifdef ADDRESS_SANITIZER
+static const int kTimeoutMultiplier = 2;
+#else
+static const int kTimeoutMultiplier = 1;
+#endif
+
+// 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 (CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
+    std::string string_value(
+        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;
+int TestTimeouts::action_max_timeout_ms_ = 45000;
+int TestTimeouts::large_test_timeout_ms_ = 10 * 60 * 1000;
+
+// static
+void TestTimeouts::Initialize() {
+  if (initialized_) {
+    NOTREACHED();
+    return;
+  }
+  initialized_ = true;
+
+  // 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, tiny_timeout_ms_,
+                    &action_timeout_ms_);
+  InitializeTimeout(switches::kUiTestActionMaxTimeout, action_timeout_ms_,
+                    &action_max_timeout_ms_);
+  InitializeTimeout(switches::kTestLargeTimeout, action_max_timeout_ms_,
+                    &large_test_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_max_timeout_ms_ <= large_test_timeout_ms_);
+}
diff --git a/base/test/test_timeouts.h b/base/test/test_timeouts.h
new file mode 100644
index 0000000..0c4587e
--- /dev/null
+++ b/base/test/test_timeouts.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_TIMEOUTS_H_
+#define BASE_TEST_TEST_TIMEOUTS_H_
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/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 large test that may take a few minutes to run.
+  static base::TimeDelta large_test_timeout() {
+    DCHECK(initialized_);
+    return base::TimeDelta::FromMilliseconds(large_test_timeout_ms_);
+  }
+
+ private:
+  static bool initialized_;
+
+  static int tiny_timeout_ms_;
+  static int action_timeout_ms_;
+  static int action_max_timeout_ms_;
+  static int large_test_timeout_ms_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(TestTimeouts);
+};
+
+#endif  // BASE_TEST_TEST_TIMEOUTS_H_
diff --git a/base/test/thread_test_helper.cc b/base/test/thread_test_helper.cc
new file mode 100644
index 0000000..a91517d
--- /dev/null
+++ b/base/test/thread_test_helper.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/thread_test_helper.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+ThreadTestHelper::ThreadTestHelper(MessageLoopProxy* target_thread)
+    : test_result_(false),
+      target_thread_(target_thread),
+      done_event_(false, false) {
+}
+
+bool ThreadTestHelper::Run() {
+  if (!target_thread_->PostTask(
+          FROM_HERE, base::Bind(&ThreadTestHelper::RunInThread, this))) {
+    return false;
+  }
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  done_event_.Wait();
+  return test_result_;
+}
+
+void ThreadTestHelper::RunTest() { set_test_result(true); }
+
+ThreadTestHelper::~ThreadTestHelper() {}
+
+void ThreadTestHelper::RunInThread() {
+  RunTest();
+  done_event_.Signal();
+}
+
+}  // namespace base
diff --git a/base/test/thread_test_helper.h b/base/test/thread_test_helper.h
new file mode 100644
index 0000000..961982c
--- /dev/null
+++ b/base/test/thread_test_helper.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_THREAD_TEST_HELPER_H_
+#define BASE_TEST_THREAD_TEST_HELPER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop_proxy.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+// Helper class that executes code on a given thread while blocking on the
+// invoking thread. To use, derive from this class and overwrite RunTest. An
+// alternative use of this class is to use it directly.  It will then block
+// until all pending tasks on a given thread have been executed.
+class ThreadTestHelper : public RefCountedThreadSafe<ThreadTestHelper> {
+ public:
+  explicit ThreadTestHelper(MessageLoopProxy* target_thread);
+
+  // True if RunTest() was successfully executed on the target thread.
+  bool Run() WARN_UNUSED_RESULT;
+
+  virtual void RunTest();
+
+ protected:
+  friend class RefCountedThreadSafe<ThreadTestHelper>;
+
+  virtual ~ThreadTestHelper();
+
+  // Use this method to store the result of RunTest().
+  void set_test_result(bool test_result) { test_result_ = test_result; }
+
+ private:
+  void RunInThread();
+
+  bool test_result_;
+  scoped_refptr<MessageLoopProxy> target_thread_;
+  WaitableEvent done_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadTestHelper);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_THREAD_TEST_HELPER_H_
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
new file mode 100644
index 0000000..d4ebb04
--- /dev/null
+++ b/base/test/trace_event_analyzer.cc
@@ -0,0 +1,966 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/trace_event_analyzer.h"
+
+#include <algorithm>
+#include <math.h>
+#include <set>
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+namespace trace_analyzer {
+
+// TraceEvent
+
+TraceEvent::TraceEvent()
+    : thread(0, 0),
+      timestamp(0),
+      phase(TRACE_EVENT_PHASE_BEGIN),
+      other_event(NULL) {
+}
+
+TraceEvent::~TraceEvent() {
+}
+
+bool TraceEvent::SetFromJSON(const base::Value* event_value) {
+  if (event_value->GetType() != base::Value::TYPE_DICTIONARY) {
+    LOG(ERROR) << "Value must be TYPE_DICTIONARY";
+    return false;
+  }
+  const base::DictionaryValue* dictionary =
+      static_cast<const base::DictionaryValue*>(event_value);
+
+  std::string phase_str;
+  const base::DictionaryValue* args = NULL;
+
+  if (!dictionary->GetString("ph", &phase_str)) {
+    LOG(ERROR) << "ph is missing from TraceEvent JSON";
+    return false;
+  }
+
+  phase = *phase_str.data();
+
+  bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA);
+  bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN ||
+                     phase == TRACE_EVENT_PHASE_ASYNC_STEP ||
+                     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 (!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.
+  base::DictionaryValue::key_iterator keyi = args->begin_keys();
+  for (; keyi != args->end_keys(); ++keyi) {
+    std::string str;
+    bool boolean = false;
+    int int_num = 0;
+    double double_num = 0.0;
+    const Value* value = NULL;
+    if (args->GetWithoutPathExpansion(*keyi, &value)) {
+      if (value->GetAsString(&str))
+        arg_strings[*keyi] = str;
+      else if (value->GetAsInteger(&int_num))
+        arg_numbers[*keyi] = static_cast<double>(int_num);
+      else if (value->GetAsBoolean(&boolean))
+        arg_numbers[*keyi] = static_cast<double>(boolean ? 1 : 0);
+      else if (value->GetAsDouble(&double_num))
+        arg_numbers[*keyi] = double_num;
+      else {
+        LOG(ERROR) << "Value type of argument is not supported: " <<
+                      static_cast<int>(value->GetType());
+        return false;  // Invalid trace event JSON format.
+      }
+    }
+  }
+
+  return true;
+}
+
+double TraceEvent::GetAbsTimeToOtherEvent() const {
+  return fabs(other_event->timestamp - timestamp);
+}
+
+bool TraceEvent::GetArgAsString(const std::string& name,
+                                std::string* arg) const {
+  std::map<std::string, std::string>::const_iterator i = arg_strings.find(name);
+  if (i != arg_strings.end()) {
+    *arg = i->second;
+    return true;
+  }
+  return false;
+}
+
+bool TraceEvent::GetArgAsNumber(const std::string& name,
+                                double* arg) const {
+  std::map<std::string, double>::const_iterator i = arg_numbers.find(name);
+  if (i != arg_numbers.end()) {
+    *arg = i->second;
+    return true;
+  }
+  return false;
+}
+
+bool TraceEvent::HasStringArg(const std::string& name) const {
+  return (arg_strings.find(name) != arg_strings.end());
+}
+
+bool TraceEvent::HasNumberArg(const std::string& name) const {
+  return (arg_numbers.find(name) != arg_numbers.end());
+}
+
+std::string TraceEvent::GetKnownArgAsString(const std::string& name) const {
+  std::string arg_string;
+  if (GetArgAsString(name, &arg_string))
+    return arg_string;
+  NOTREACHED();
+  return "";
+}
+
+double TraceEvent::GetKnownArgAsDouble(const std::string& name) const {
+  double arg_double;
+  if (GetArgAsNumber(name, &arg_double))
+    return arg_double;
+  NOTREACHED();
+  return 0;
+}
+
+int TraceEvent::GetKnownArgAsInt(const std::string& name) const {
+  double arg_double;
+  if (GetArgAsNumber(name, &arg_double))
+    return static_cast<int>(arg_double);
+  NOTREACHED();
+  return 0;
+}
+
+bool TraceEvent::GetKnownArgAsBool(const std::string& name) const {
+  double arg_double;
+  if (GetArgAsNumber(name, &arg_double))
+    return (arg_double != 0.0);
+  NOTREACHED();
+  return false;
+}
+
+// QueryNode
+
+QueryNode::QueryNode(const Query& query) : query_(query) {
+}
+
+QueryNode::~QueryNode() {
+}
+
+// Query
+
+Query::Query(TraceEventMember member)
+    : type_(QUERY_EVENT_MEMBER),
+      operator_(OP_INVALID),
+      member_(member),
+      number_(0),
+      is_pattern_(false) {
+}
+
+Query::Query(TraceEventMember member, const std::string& arg_name)
+    : type_(QUERY_EVENT_MEMBER),
+      operator_(OP_INVALID),
+      member_(member),
+      number_(0),
+      string_(arg_name),
+      is_pattern_(false) {
+}
+
+Query::Query(const Query& query)
+    : type_(query.type_),
+      operator_(query.operator_),
+      left_(query.left_),
+      right_(query.right_),
+      member_(query.member_),
+      number_(query.number_),
+      string_(query.string_),
+      is_pattern_(query.is_pattern_) {
+}
+
+Query::~Query() {
+}
+
+Query Query::String(const std::string& str) {
+  return Query(str);
+}
+
+Query Query::Double(double num) {
+  return Query(num);
+}
+
+Query Query::Int(int32 num) {
+  return Query(static_cast<double>(num));
+}
+
+Query Query::Uint(uint32 num) {
+  return Query(static_cast<double>(num));
+}
+
+Query Query::Bool(bool boolean) {
+  return Query(boolean ? 1.0 : 0.0);
+}
+
+Query Query::Phase(char phase) {
+  return Query(static_cast<double>(phase));
+}
+
+Query Query::Pattern(const std::string& pattern) {
+  Query query(pattern);
+  query.is_pattern_ = true;
+  return query;
+}
+
+bool Query::Evaluate(const TraceEvent& event) const {
+  // First check for values that can convert to bool.
+
+  // double is true if != 0:
+  double bool_value = 0.0;
+  bool is_bool = GetAsDouble(event, &bool_value);
+  if (is_bool)
+    return (bool_value != 0.0);
+
+  // string is true if it is non-empty:
+  std::string str_value;
+  bool is_str = GetAsString(event, &str_value);
+  if (is_str)
+    return !str_value.empty();
+
+  DCHECK(type_ == QUERY_BOOLEAN_OPERATOR)
+      << "Invalid query: missing boolean expression";
+  DCHECK(left_.get() && (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;
+    else 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();
+  }
+
+  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;
+  }
+  return true;
+}
+
+bool Query::CompareAsString(const TraceEvent& event, bool* result) const {
+  std::string lhs, rhs;
+  if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs))
+    return false;
+  switch (operator_) {
+    case OP_EQ:
+      if (right().is_pattern_)
+        *result = MatchPattern(lhs, rhs);
+      else if (left().is_pattern_)
+        *result = MatchPattern(rhs, lhs);
+      else
+        *result = (lhs == rhs);
+      return true;
+    case OP_NE:
+      if (right().is_pattern_)
+        *result = !MatchPattern(lhs, rhs);
+      else if (left().is_pattern_)
+        *result = !MatchPattern(rhs, lhs);
+      else
+        *result = (lhs != rhs);
+      return true;
+    case OP_LT:
+      *result = (lhs < rhs);
+      return true;
+    case OP_LE:
+      *result = (lhs <= rhs);
+      return true;
+    case OP_GT:
+      *result = (lhs > rhs);
+      return true;
+    case OP_GE:
+      *result = (lhs >= rhs);
+      return true;
+    default:
+      NOTREACHED();
+      return false;
+  }
+  return true;
+}
+
+bool Query::EvaluateArithmeticOperator(const TraceEvent& event,
+                                       double* num) const {
+  DCHECK(type_ == QUERY_ARITHMETIC_OPERATOR);
+  DCHECK(left_.get() && (right_.get() || is_unary_operator()));
+
+  double lhs = 0, rhs = 0;
+  if (!left().GetAsDouble(event, &lhs))
+    return false;
+  if (!is_unary_operator() && !right().GetAsDouble(event, &rhs))
+    return false;
+
+  switch (operator_) {
+    case OP_ADD:
+      *num = lhs + rhs;
+      return true;
+    case OP_SUB:
+      *num = lhs - rhs;
+      return true;
+    case OP_MUL:
+      *num = lhs * rhs;
+      return true;
+    case OP_DIV:
+      *num = lhs / rhs;
+      return true;
+    case OP_MOD:
+      *num = static_cast<double>(static_cast<int64>(lhs) %
+                                 static_cast<int64>(rhs));
+      return true;
+    case OP_NEGATE:
+      *num = -lhs;
+      return true;
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool Query::GetAsDouble(const TraceEvent& event, double* num) const {
+  switch (type_) {
+    case QUERY_ARITHMETIC_OPERATOR:
+      return EvaluateArithmeticOperator(event, num);
+    case QUERY_EVENT_MEMBER:
+      return GetMemberValueAsDouble(event, num);
+    case QUERY_NUMBER:
+      *num = number_;
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool Query::GetAsString(const TraceEvent& event, std::string* str) const {
+  switch (type_) {
+    case QUERY_EVENT_MEMBER:
+      return GetMemberValueAsString(event, str);
+    case QUERY_STRING:
+      *str = string_;
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool Query::GetMemberValueAsDouble(const TraceEvent& event,
+                                   double* num) const {
+  DCHECK(type_ == QUERY_EVENT_MEMBER);
+
+  // 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()) {
+        *num = the_event->GetAbsTimeToOtherEvent();
+        return true;
+      }
+      return false;
+    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(type_ == QUERY_EVENT_MEMBER);
+
+  // 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) {
+  for (size_t i = 0; i < events.size(); ++i) {
+    if (query.Evaluate(events[i]))
+      output->push_back(&events[i]);
+  }
+  return output->size();
+}
+
+bool ParseEventsFromJson(const std::string& json,
+                         std::vector<TraceEvent>* output) {
+  scoped_ptr<base::Value> root;
+  root.reset(base::JSONReader::Read(json));
+
+  ListValue* root_list = NULL;
+  if (!root.get() || !root->GetAsList(&root_list))
+    return false;
+
+  for (size_t i = 0; i < root_list->GetSize(); ++i) {
+    Value* item = NULL;
+    if (root_list->Get(i, &item)) {
+      TraceEvent event;
+      if (event.SetFromJSON(item))
+        output->push_back(event);
+      else
+        return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace
+
+// TraceAnalyzer
+
+TraceAnalyzer::TraceAnalyzer() : allow_assocation_changes_(true) {
+}
+
+TraceAnalyzer::~TraceAnalyzer() {
+}
+
+// static
+TraceAnalyzer* TraceAnalyzer::Create(const std::string& json_events) {
+  scoped_ptr<TraceAnalyzer> analyzer(new TraceAnalyzer());
+  if (analyzer->SetEvents(json_events))
+    return analyzer.release();
+  return NULL;
+}
+
+bool TraceAnalyzer::SetEvents(const std::string& json_events) {
+  raw_events_.clear();
+  if (!ParseEventsFromJson(json_events, &raw_events_))
+    return false;
+  std::stable_sort(raw_events_.begin(), raw_events_.end());
+  ParseMetadata();
+  return true;
+}
+
+void TraceAnalyzer::AssociateBeginEndEvents() {
+  using trace_analyzer::Query;
+
+  Query begin(Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN));
+  Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_END));
+  Query match(Query::EventName() == Query::OtherName() &&
+              Query::EventCategory() == Query::OtherCategory() &&
+              Query::EventTid() == Query::OtherTid() &&
+              Query::EventPid() == Query::OtherPid());
+
+  AssociateEvents(begin, end, match);
+}
+
+void TraceAnalyzer::AssociateAsyncBeginEndEvents() {
+  using trace_analyzer::Query;
+
+  Query begin(
+      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
+      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP));
+  Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_END) ||
+            Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP));
+  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);
+}
+
+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) {
+  CHECK(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 =
+      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) {
+  CHECK(return_index);
+  for (size_t i = position; i < events.size(); ++i) {
+    if (query.Evaluate(*events.at(i))) {
+      *return_index = i;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool FindLastOf(const TraceEventVector& events,
+                const Query& query,
+                size_t position,
+                size_t* return_index) {
+  CHECK(return_index);
+  if (events.empty())
+    return false;
+  position = (position < events.size()) ? position : events.size() - 1;
+  for (;;) {
+    if (query.Evaluate(*events.at(position))) {
+      *return_index = position;
+      return true;
+    }
+    if (position == 0)
+      return false;
+    --position;
+  }
+  return false;
+}
+
+bool FindClosest(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_closest,
+                 size_t* return_second_closest) {
+  CHECK(return_closest);
+  if (events.empty() || position >= events.size())
+    return false;
+  size_t closest = events.size();
+  size_t second_closest = events.size();
+  for (size_t i = 0; i < events.size(); ++i) {
+    if (!query.Evaluate(*events.at(i)))
+      continue;
+    if (closest == events.size()) {
+      closest = i;
+      continue;
+    }
+    if (fabs(events.at(i)->timestamp - events.at(position)->timestamp) <
+        fabs(events.at(closest)->timestamp - events.at(position)->timestamp)) {
+      second_closest = closest;
+      closest = i;
+    } else if (second_closest == events.size()) {
+      second_closest = i;
+    }
+  }
+
+  if (closest < events.size() &&
+      (!return_second_closest || second_closest < events.size())) {
+    *return_closest = closest;
+    if (return_second_closest)
+      *return_second_closest = second_closest;
+    return true;
+  }
+
+  return false;
+}
+
+size_t CountMatches(const TraceEventVector& events,
+                    const Query& query,
+                    size_t begin_position,
+                    size_t end_position) {
+  if (begin_position >= events.size())
+    return 0u;
+  end_position = (end_position < events.size()) ? end_position : events.size();
+  size_t count = 0u;
+  for (size_t i = begin_position; i < end_position; ++i) {
+    if (query.Evaluate(*events.at(i)))
+      ++count;
+  }
+  return count;
+}
+
+}  // namespace trace_analyzer
diff --git a/base/test/trace_event_analyzer.h b/base/test/trace_event_analyzer.h
new file mode 100644
index 0000000..a472639
--- /dev/null
+++ b/base/test/trace_event_analyzer.h
@@ -0,0 +1,684 @@
+// Copyright (c) 2012 The Chromium 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::debug::TraceLog.
+// - Create TraceAnalyzer with JSON string.
+// - Call TraceAnalyzer::AssociateBeginEndEvents (optional).
+// - Call TraceAnalyzer::AssociateEvents (zero or more times).
+// - Call TraceAnalyzer::FindEvents with queries to find specific events.
+//
+// A Query is a boolean expression tree that evaluates to true or false for a
+// given trace event. Queries can be combined into a tree using boolean,
+// arithmetic and comparison operators that refer to data of an individual trace
+// event.
+//
+// The events are returned as trace_analyzer::TraceEvent objects.
+// TraceEvent contains a single trace event's data, as well as a pointer to
+// a related trace event. The related trace event is typically the matching end
+// of a begin event or the matching begin of an end event.
+//
+// The following examples use this basic setup code to construct TraceAnalyzer
+// with the json trace string retrieved from TraceLog and construct an event
+// vector for retrieving events:
+//
+// TraceAnalyzer analyzer(json_events);
+// TraceEventVector events;
+//
+// EXAMPLE 1: Find events named "my_event".
+//
+// analyzer.FindEvents(Query(EVENT_NAME) == "my_event", &events);
+//
+// EXAMPLE 2: Find begin events named "my_event" with duration > 1 second.
+//
+// Query q = (Query(EVENT_NAME) == Query::String("my_event") &&
+//            Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN) &&
+//            Query(EVENT_DURATION) > Query::Double(1000000.0));
+// analyzer.FindEvents(q, &events);
+//
+// EXAMPLE 3: Associating event pairs across threads.
+//
+// If the test needs to analyze something that starts and ends on different
+// threads, the test needs to use INSTANT events. The typical procedure is to
+// specify the same unique ID as a TRACE_EVENT argument on both the start and
+// finish INSTANT events. Then use the following procedure to associate those
+// events.
+//
+// Step 1: instrument code with custom begin/end trace events.
+//   [Thread 1 tracing code]
+//   TRACE_EVENT_INSTANT1("test_latency", "timing1_begin", "id", 3);
+//   [Thread 2 tracing code]
+//   TRACE_EVENT_INSTANT1("test_latency", "timing1_end", "id", 3);
+//
+// Step 2: associate these custom begin/end pairs.
+//   Query begin(Query(EVENT_NAME) == Query::String("timing1_begin"));
+//   Query end(Query(EVENT_NAME) == Query::String("timing1_end"));
+//   Query match(Query(EVENT_ARG, "id") == Query(OTHER_ARG, "id"));
+//   analyzer.AssociateEvents(begin, end, match);
+//
+// Step 3: search for "timing1_begin" events with existing other event.
+//   Query q = (Query(EVENT_NAME) == Query::String("timing1_begin") &&
+//              Query(EVENT_HAS_OTHER));
+//   analyzer.FindEvents(q, &events);
+//
+// Step 4: analyze events, such as checking durations.
+//   for (size_t i = 0; i < events.size(); ++i) {
+//     double duration;
+//     EXPECT_TRUE(events[i].GetAbsTimeToOtherEvent(&duration));
+//     EXPECT_LT(duration, 1000000.0/60.0); // expect less than 1/60 second.
+//   }
+
+
+#ifndef BASE_TEST_TRACE_EVENT_ANALYZER_H_
+#define BASE_TEST_TRACE_EVENT_ANALYZER_H_
+
+#include <map>
+
+#include "base/debug/trace_event.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+class Value;
+}
+
+namespace trace_analyzer {
+class QueryNode;
+
+// trace_analyzer::TraceEvent is a more convenient form of the
+// base::debug::TraceEvent class to make tracing-based tests easier to write.
+struct TraceEvent {
+  // ProcessThreadID contains a Process ID and Thread ID.
+  struct ProcessThreadID {
+    ProcessThreadID() : process_id(0), thread_id(0) {}
+    ProcessThreadID(int process_id, int thread_id)
+        : process_id(process_id), thread_id(thread_id) {}
+    bool operator< (const ProcessThreadID& rhs) const {
+      if (process_id != rhs.process_id)
+        return process_id < rhs.process_id;
+      return thread_id < rhs.thread_id;
+    }
+    int process_id;
+    int thread_id;
+  };
+
+  TraceEvent();
+  ~TraceEvent();
+
+  bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT;
+
+  bool operator< (const TraceEvent& rhs) const {
+    return timestamp < rhs.timestamp;
+  }
+
+  bool has_other_event() const { return other_event; }
+
+  // Returns absolute duration in microseconds between this event and other
+  // event. Must have already verified that other_event exists by
+  // Query(EVENT_HAS_OTHER) or by calling has_other_event().
+  double GetAbsTimeToOtherEvent() const;
+
+  // Return the argument value if it exists and it is a string.
+  bool GetArgAsString(const std::string& name, std::string* arg) const;
+  // Return the argument value if it exists and it is a number.
+  bool GetArgAsNumber(const std::string& name, double* arg) const;
+
+  // Check if argument exists and is string.
+  bool HasStringArg(const std::string& name) const;
+  // Check if argument exists and is number (double, int or bool).
+  bool HasNumberArg(const std::string& name) const;
+
+  // Get known existing arguments as specific types.
+  // Useful when you have already queried the argument with
+  // Query(HAS_NUMBER_ARG) or Query(HAS_STRING_ARG).
+  std::string GetKnownArgAsString(const std::string& name) const;
+  double GetKnownArgAsDouble(const std::string& name) const;
+  int GetKnownArgAsInt(const std::string& name) const;
+  bool GetKnownArgAsBool(const std::string& name) const;
+
+  // Process ID and Thread ID.
+  ProcessThreadID thread;
+
+  // Time since epoch in microseconds.
+  // Stored as double to match its JSON representation.
+  double timestamp;
+
+  char phase;
+
+  std::string category;
+
+  std::string name;
+
+  std::string id;
+
+  // All numbers and bool values from TraceEvent args are cast to double.
+  // bool becomes 1.0 (true) or 0.0 (false).
+  std::map<std::string, double> arg_numbers;
+
+  std::map<std::string, std::string> arg_strings;
+
+  // The other event associated with this event (or NULL).
+  const TraceEvent* other_event;
+};
+
+typedef std::vector<const TraceEvent*> TraceEventVector;
+
+class Query {
+ public:
+  Query(const Query& query);
+
+  ~Query();
+
+  ////////////////////////////////////////////////////////////////
+  // Query literal values
+
+  // Compare with the given string.
+  static Query String(const std::string& str);
+
+  // Compare with the given number.
+  static Query Double(double num);
+  static Query Int(int32 num);
+  static Query Uint(uint32 num);
+
+  // Compare with the given bool.
+  static Query Bool(bool boolean);
+
+  // Compare with the given phase.
+  static Query Phase(char phase);
+
+  // Compare with the given string pattern. Only works with == and != operators.
+  // Example: Query(EVENT_NAME) == Query::Pattern("MyEvent*")
+  static Query Pattern(const std::string& pattern);
+
+  ////////////////////////////////////////////////////////////////
+  // Query event members
+
+  static Query EventPid() { return Query(EVENT_PID); }
+
+  static Query EventTid() { return Query(EVENT_TID); }
+
+  // Return the timestamp of the event in microseconds since epoch.
+  static Query EventTime() { return Query(EVENT_TIME); }
+
+  // Return the absolute time between event and other event in microseconds.
+  // Only works if Query::EventHasOther() == true.
+  static Query EventDuration() { return Query(EVENT_DURATION); }
+
+  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 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) == name) && MatchBeginWithEnd();
+  }
+
+  // Match given Process ID and Thread ID.
+  static Query MatchThread(const TraceEvent::ProcessThreadID& thread) {
+    return (Query(EVENT_PID) == Query::Int(thread.process_id)) &&
+           (Query(EVENT_TID) == Query::Int(thread.thread_id));
+  }
+
+  // Match event pair that spans multiple threads.
+  static Query MatchCrossThread() {
+    return (Query(EVENT_PID) != Query(OTHER_PID)) ||
+           (Query(EVENT_TID) != Query(OTHER_TID));
+  }
+
+  ////////////////////////////////////////////////////////////////
+  // Operators:
+
+  // Boolean operators:
+  Query operator==(const Query& rhs) const;
+  Query operator!=(const Query& rhs) const;
+  Query operator< (const Query& rhs) const;
+  Query operator<=(const Query& rhs) const;
+  Query operator> (const Query& rhs) const;
+  Query operator>=(const Query& rhs) const;
+  Query operator&&(const Query& rhs) const;
+  Query operator||(const Query& rhs) const;
+  Query operator!() const;
+
+  // Arithmetic operators:
+  // Following operators are applied to double arguments:
+  Query operator+(const Query& rhs) const;
+  Query operator-(const Query& rhs) const;
+  Query operator*(const Query& rhs) const;
+  Query operator/(const Query& rhs) const;
+  Query operator-() const;
+  // Mod operates on int64 args (doubles are casted to int64 beforehand):
+  Query operator%(const Query& rhs) const;
+
+  // Return true if the given event matches this query tree.
+  // This is a recursive method that walks the query tree.
+  bool Evaluate(const TraceEvent& event) const;
+
+ private:
+  enum TraceEventMember {
+    EVENT_INVALID,
+    EVENT_PID,
+    EVENT_TID,
+    EVENT_TIME,
+    EVENT_DURATION,
+    EVENT_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.
+  Query(TraceEventMember member);
+
+  // Compare with the given member argument value.
+  Query(TraceEventMember member, const std::string& arg_name);
+
+  // Compare with the given string.
+  Query(const std::string& str);
+
+  // Compare with the given number.
+  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;
+
+  // 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 allow_assocation_changes_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceAnalyzer);
+};
+
+// Utility functions for TraceEventVector.
+
+struct RateStats {
+  double min_us;
+  double max_us;
+  double mean_us;
+  double standard_deviation_us;
+};
+
+struct RateStatsOptions {
+  RateStatsOptions() : trim_min(0u), trim_max(0u) {}
+  // After the times between events are sorted, the number of specified elements
+  // will be trimmed before calculating the RateStats. This is useful in cases
+  // where extreme outliers are tolerable and should not skew the overall
+  // average.
+  size_t trim_min;  // Trim this many minimum times.
+  size_t trim_max;  // Trim this many maximum times.
+};
+
+// Calculate min/max/mean and standard deviation from the times between
+// adjacent events.
+bool GetRateStats(const TraceEventVector& events,
+                  RateStats* stats,
+                  const RateStatsOptions* options);
+
+// Starting from |position|, find the first event that matches |query|.
+// Returns true if found, false otherwise.
+bool FindFirstOf(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_index);
+
+// Starting from |position|, find the last event that matches |query|.
+// Returns true if found, false otherwise.
+bool FindLastOf(const TraceEventVector& events,
+                const Query& query,
+                size_t position,
+                size_t* return_index);
+
+// Find the closest events to |position| in time that match |query|.
+// return_second_closest may be NULL. Closeness is determined by comparing
+// with the event timestamp.
+// Returns true if found, false otherwise. If both return parameters are
+// requested, both must be found for a successful result.
+bool FindClosest(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_closest,
+                 size_t* return_second_closest);
+
+// Count matches, inclusive of |begin_position|, exclusive of |end_position|.
+size_t CountMatches(const TraceEventVector& events,
+                    const Query& query,
+                    size_t begin_position,
+                    size_t end_position);
+
+// Count all matches.
+static inline size_t CountMatches(const TraceEventVector& events,
+                                  const Query& query) {
+  return CountMatches(events, query, 0u, events.size());
+}
+
+}  // namespace trace_analyzer
+
+#endif  // BASE_TEST_TRACE_EVENT_ANALYZER_H_
diff --git a/base/test/trace_event_analyzer_unittest.cc b/base/test/trace_event_analyzer_unittest.cc
new file mode 100644
index 0000000..eca2b70
--- /dev/null
+++ b/base/test/trace_event_analyzer_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 "base/bind.h"
+#include "base/debug/trace_event_unittest.h"
+#include "base/test/trace_event_analyzer.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(
+      const scoped_refptr<base::RefCountedString>& json_events_str);
+  void BeginTracing();
+  void EndTracing();
+
+  base::debug::TraceResultBuffer::SimpleOutput output_;
+  base::debug::TraceResultBuffer buffer_;
+};
+
+void TraceEventAnalyzerTest::ManualSetUp() {
+  base::debug::TraceLog::Resurrect();
+  ASSERT_TRUE(base::debug::TraceLog::GetInstance());
+  buffer_.SetOutputCallback(output_.GetCallback());
+  output_.json_output.clear();
+}
+
+void TraceEventAnalyzerTest::OnTraceDataCollected(
+    const scoped_refptr<base::RefCountedString>& json_events_str) {
+  buffer_.AddFragment(json_events_str->data());
+}
+
+void TraceEventAnalyzerTest::BeginTracing() {
+  output_.json_output.clear();
+  buffer_.Start();
+  base::debug::TraceLog::GetInstance()->SetEnabled(true);
+}
+
+void TraceEventAnalyzerTest::EndTracing() {
+  base::debug::TraceLog::GetInstance()->SetEnabled(false);
+  base::debug::TraceLog::GetInstance()->Flush(
+      base::Bind(&TraceEventAnalyzerTest::OnTraceDataCollected,
+                 base::Unretained(this)));
+  buffer_.Finish();
+}
+
+}  // namespace
+
+TEST_F(TraceEventAnalyzerTest, NoEvents) {
+  ManualSetUp();
+
+  // Create an empty JSON event string:
+  buffer_.Start();
+  buffer_.Finish();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  // Search for all events and verify that nothing is returned.
+  TraceEventVector found;
+  analyzer->FindEvents(Query::Bool(true), &found);
+  EXPECT_EQ(0u, found.size());
+}
+
+TEST_F(TraceEventAnalyzerTest, TraceEvent) {
+  ManualSetUp();
+
+  int int_num = 2;
+  double double_num = 3.5;
+  const char* str = "the string";
+
+  TraceEvent event;
+  event.arg_numbers["false"] = 0.0;
+  event.arg_numbers["true"] = 1.0;
+  event.arg_numbers["int"] = static_cast<double>(int_num);
+  event.arg_numbers["double"] = double_num;
+  event.arg_strings["string"] = str;
+
+  ASSERT_TRUE(event.HasNumberArg("false"));
+  ASSERT_TRUE(event.HasNumberArg("true"));
+  ASSERT_TRUE(event.HasNumberArg("int"));
+  ASSERT_TRUE(event.HasNumberArg("double"));
+  ASSERT_TRUE(event.HasStringArg("string"));
+  ASSERT_FALSE(event.HasNumberArg("notfound"));
+  ASSERT_FALSE(event.HasStringArg("notfound"));
+
+  EXPECT_FALSE(event.GetKnownArgAsBool("false"));
+  EXPECT_TRUE(event.GetKnownArgAsBool("true"));
+  EXPECT_EQ(int_num, event.GetKnownArgAsInt("int"));
+  EXPECT_EQ(double_num, event.GetKnownArgAsDouble("double"));
+  EXPECT_STREQ(str, event.GetKnownArgAsString("string").c_str());
+}
+
+TEST_F(TraceEventAnalyzerTest, QueryEventMember) {
+  ManualSetUp();
+
+  TraceEvent event;
+  event.thread.process_id = 3;
+  event.thread.thread_id = 4;
+  event.timestamp = 1.5;
+  event.phase = TRACE_EVENT_PHASE_BEGIN;
+  event.category = "category";
+  event.name = "name";
+  event.id = "1";
+  event.arg_numbers["num"] = 7.0;
+  event.arg_strings["str"] = "the string";
+
+  // Other event with all different members:
+  TraceEvent other;
+  other.thread.process_id = 5;
+  other.thread.thread_id = 6;
+  other.timestamp = 2.5;
+  other.phase = TRACE_EVENT_PHASE_END;
+  other.category = "category2";
+  other.name = "name2";
+  other.id = "2";
+  other.arg_numbers["num2"] = 8.0;
+  other.arg_strings["str2"] = "the string 2";
+
+  event.other_event = &other;
+  ASSERT_TRUE(event.has_other_event());
+  double duration = event.GetAbsTimeToOtherEvent();
+
+  Query event_pid = Query::EventPidIs(event.thread.process_id);
+  Query event_tid = Query::EventTidIs(event.thread.thread_id);
+  Query event_time = Query::EventTimeIs(event.timestamp);
+  Query event_duration = Query::EventDurationIs(duration);
+  Query event_phase = Query::EventPhaseIs(event.phase);
+  Query event_category = Query::EventCategoryIs(event.category);
+  Query event_name = Query::EventNameIs(event.name);
+  Query event_id = Query::EventIdIs(event.id);
+  Query event_has_arg1 = Query::EventHasNumberArg("num");
+  Query event_has_arg2 = Query::EventHasStringArg("str");
+  Query event_arg1 =
+      (Query::EventArg("num") == Query::Double(event.arg_numbers["num"]));
+  Query event_arg2 =
+      (Query::EventArg("str") == Query::String(event.arg_strings["str"]));
+  Query event_has_other = Query::EventHasOther();
+  Query other_pid = Query::OtherPidIs(other.thread.process_id);
+  Query other_tid = Query::OtherTidIs(other.thread.thread_id);
+  Query other_time = Query::OtherTimeIs(other.timestamp);
+  Query other_phase = Query::OtherPhaseIs(other.phase);
+  Query other_category = Query::OtherCategoryIs(other.category);
+  Query other_name = Query::OtherNameIs(other.name);
+  Query other_id = Query::OtherIdIs(other.id);
+  Query other_has_arg1 = Query::OtherHasNumberArg("num2");
+  Query other_has_arg2 = Query::OtherHasStringArg("str2");
+  Query other_arg1 =
+      (Query::OtherArg("num2") == Query::Double(other.arg_numbers["num2"]));
+  Query other_arg2 =
+      (Query::OtherArg("str2") == Query::String(other.arg_strings["str2"]));
+
+  EXPECT_TRUE(event_pid.Evaluate(event));
+  EXPECT_TRUE(event_tid.Evaluate(event));
+  EXPECT_TRUE(event_time.Evaluate(event));
+  EXPECT_TRUE(event_duration.Evaluate(event));
+  EXPECT_TRUE(event_phase.Evaluate(event));
+  EXPECT_TRUE(event_category.Evaluate(event));
+  EXPECT_TRUE(event_name.Evaluate(event));
+  EXPECT_TRUE(event_id.Evaluate(event));
+  EXPECT_TRUE(event_has_arg1.Evaluate(event));
+  EXPECT_TRUE(event_has_arg2.Evaluate(event));
+  EXPECT_TRUE(event_arg1.Evaluate(event));
+  EXPECT_TRUE(event_arg2.Evaluate(event));
+  EXPECT_TRUE(event_has_other.Evaluate(event));
+  EXPECT_TRUE(other_pid.Evaluate(event));
+  EXPECT_TRUE(other_tid.Evaluate(event));
+  EXPECT_TRUE(other_time.Evaluate(event));
+  EXPECT_TRUE(other_phase.Evaluate(event));
+  EXPECT_TRUE(other_category.Evaluate(event));
+  EXPECT_TRUE(other_name.Evaluate(event));
+  EXPECT_TRUE(other_id.Evaluate(event));
+  EXPECT_TRUE(other_has_arg1.Evaluate(event));
+  EXPECT_TRUE(other_has_arg2.Evaluate(event));
+  EXPECT_TRUE(other_arg1.Evaluate(event));
+  EXPECT_TRUE(other_arg2.Evaluate(event));
+
+  // Evaluate event queries against other to verify the queries fail when the
+  // event members are wrong.
+  EXPECT_FALSE(event_pid.Evaluate(other));
+  EXPECT_FALSE(event_tid.Evaluate(other));
+  EXPECT_FALSE(event_time.Evaluate(other));
+  EXPECT_FALSE(event_duration.Evaluate(other));
+  EXPECT_FALSE(event_phase.Evaluate(other));
+  EXPECT_FALSE(event_category.Evaluate(other));
+  EXPECT_FALSE(event_name.Evaluate(other));
+  EXPECT_FALSE(event_id.Evaluate(other));
+  EXPECT_FALSE(event_has_arg1.Evaluate(other));
+  EXPECT_FALSE(event_has_arg2.Evaluate(other));
+  EXPECT_FALSE(event_arg1.Evaluate(other));
+  EXPECT_FALSE(event_arg2.Evaluate(other));
+  EXPECT_FALSE(event_has_other.Evaluate(other));
+}
+
+TEST_F(TraceEventAnalyzerTest, BooleanOperators) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_INSTANT1("cat1", "name1", "num", 1);
+    TRACE_EVENT_INSTANT1("cat1", "name2", "num", 2);
+    TRACE_EVENT_INSTANT1("cat2", "name3", "num", 3);
+    TRACE_EVENT_INSTANT1("cat2", "name4", "num", 4);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(!!analyzer.get());
+
+  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", "a", 10, "b", 5);
+    TRACE_EVENT_INSTANT2("cat1", "math2", "a", 10, "b", 10);
+    // Extra events that never match, for noise:
+    TRACE_EVENT_INSTANT2("noise", "math3", "a", 1,  "b", 3);
+    TRACE_EVENT_INSTANT2("noise", "math4", "c", 10, "d", 5);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  TraceEventVector found;
+
+  // Verify that arithmetic operators function:
+
+  // +
+  analyzer->FindEvents(Query::EventArg("a") + Query::EventArg("b") ==
+                       Query::Int(20), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math2", found.front()->name.c_str());
+
+  // -
+  analyzer->FindEvents(Query::EventArg("a") - Query::EventArg("b") ==
+                       Query::Int(5), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math1", found.front()->name.c_str());
+
+  // *
+  analyzer->FindEvents(Query::EventArg("a") * Query::EventArg("b") ==
+                       Query::Int(50), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math1", found.front()->name.c_str());
+
+  // /
+  analyzer->FindEvents(Query::EventArg("a") / Query::EventArg("b") ==
+                       Query::Int(2), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math1", found.front()->name.c_str());
+
+  // %
+  analyzer->FindEvents(Query::EventArg("a") % Query::EventArg("b") ==
+                       Query::Int(0), &found);
+  EXPECT_EQ(2u, found.size());
+
+  // - (negate)
+  analyzer->FindEvents(-Query::EventArg("b") == Query::Int(-10), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math2", found.front()->name.c_str());
+}
+
+TEST_F(TraceEventAnalyzerTest, StringPattern) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_INSTANT0("cat1", "name1");
+    TRACE_EVENT_INSTANT0("cat1", "name2");
+    TRACE_EVENT_INSTANT0("cat1", "no match");
+    TRACE_EVENT_INSTANT0("cat1", "name3x");
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  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, Duration) {
+  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.
+  int 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
+      TRACE_EVENT_INSTANT0("noise", "name4"); // not searched for, just noise
+      base::debug::HighResSleepForTraceTest(kSleepTime);
+      TRACE_EVENT0("cat2", "name5"); // not found (duration too short)
+    }
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(
+      Query::MatchBeginWithEnd() &&
+      Query::EventDuration() > Query::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_EVENT0("cat1", "name2");
+    TRACE_EVENT_INSTANT0("cat1", "name3");
+    TRACE_EVENT_BEGIN0("cat1", "name1");
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchBeginWithEnd(), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name2", found[0]->name.c_str());
+}
+
+// Test MergeAssociatedEventArgs
+TEST_F(TraceEventAnalyzerTest, MergeAssociatedEventArgs) {
+  ManualSetUp();
+
+  const char* arg_string = "arg_string";
+  BeginTracing();
+  {
+    TRACE_EVENT_BEGIN0("cat1", "name1");
+    TRACE_EVENT_END1("cat1", "name1", "arg", arg_string);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchBeginName("name1"), &found);
+  ASSERT_EQ(1u, found.size());
+  std::string arg_actual;
+  EXPECT_FALSE(found[0]->GetArgAsString("arg", &arg_actual));
+
+  analyzer->MergeAssociatedEventArgs();
+  EXPECT_TRUE(found[0]->GetArgAsString("arg", &arg_actual));
+  EXPECT_STREQ(arg_string, arg_actual.c_str());
+}
+
+// Test AssociateAsyncBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, AsyncBeginEndAssocations) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xA); // no match / out of order
+    TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xB);
+    TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xC);
+    TRACE_EVENT_INSTANT0("cat1", "name1"); // noise
+    TRACE_EVENT0("cat1", "name1"); // noise
+    TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xB);
+    TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xC);
+    TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xA); // no match / out of order
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateAsyncBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchAsyncBeginWithNext(), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STRCASEEQ("B", found[0]->id.c_str());
+  EXPECT_STRCASEEQ("C", found[1]->id.c_str());
+}
+
+// Test AssociateAsyncBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, AsyncBeginEndAssocationsWithSteps) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_ASYNC_STEP0("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_STEP0("c", "n", 0xB, "s1");
+    TRACE_EVENT_ASYNC_STEP0("c", "n", 0xC, "s1");
+    TRACE_EVENT_ASYNC_STEP1("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_STEP0("c", "n", 0xA, "s2");
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateAsyncBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchAsyncBeginWithNext(), &found);
+  ASSERT_EQ(3u, found.size());
+
+  EXPECT_STRCASEEQ("B", found[0]->id.c_str());
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP, 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("C", found[1]->id.c_str());
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP, found[1]->other_event->phase);
+  EXPECT_TRUE(found[1]->other_event->other_event);
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP,
+            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("A", found[2]->id.c_str());
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP, 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();
+  {
+    TRACE_EVENT_INSTANT1("cat1", "end", "id", 1);   // no begin match
+    TRACE_EVENT_INSTANT1("cat2", "begin", "id", 2); // end is cat4
+    TRACE_EVENT_INSTANT1("cat3", "begin", "id", 3); // end is cat5
+    TRACE_EVENT_INSTANT1("cat4", "end", "id", 2);
+    TRACE_EVENT_INSTANT1("cat5", "end", "id", 3);
+    TRACE_EVENT_INSTANT1("cat6", "begin", "id", 1); // no end match
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  // begin, end, and match queries to find proper begin/end pairs.
+  Query begin(Query::EventName() == Query::String("begin"));
+  Query end(Query::EventName() == Query::String("end"));
+  Query match(Query::EventArg("id") == Query::OtherArg("id"));
+  analyzer->AssociateEvents(begin, end, match);
+
+  TraceEventVector found;
+
+  // cat1 has no other_event.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat1") &&
+                       Query::EventHasOther(), &found);
+  EXPECT_EQ(0u, found.size());
+
+  // cat1 has no other_event.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat1") &&
+                       !Query::EventHasOther(), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat6 has no other_event.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat6") &&
+                       !Query::EventHasOther(), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat2 and cat4 are associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat2") &&
+                       Query::OtherCategory() == Query::String("cat4"), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat4 and cat2 are not associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat4") &&
+                       Query::OtherCategory() == Query::String("cat2"), &found);
+  EXPECT_EQ(0u, found.size());
+
+  // cat3 and cat5 are associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat3") &&
+                       Query::OtherCategory() == Query::String("cat5"), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat5 and cat3 are not associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat5") &&
+                       Query::OtherCategory() == Query::String("cat3"), &found);
+  EXPECT_EQ(0u, found.size());
+}
+
+// Verify that Query literals and types are properly casted.
+TEST_F(TraceEventAnalyzerTest, Literals) {
+  ManualSetUp();
+
+  // Since these queries don't refer to the event data, the dummy event below
+  // will never be accessed.
+  TraceEvent dummy;
+  char char_num = 5;
+  short short_num = -5;
+  EXPECT_TRUE((Query::Double(5.0) == Query::Int(char_num)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(-5.0) == Query::Int(short_num)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(1.0) == Query::Uint(1u)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(1.0) == Query::Int(1)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(-1.0) == Query::Int(-1)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(1.0) == Query::Double(1.0f)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(true) == Query::Int(1)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(false) == Query::Int(0)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(true) == Query::Double(1.0f)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(false) == Query::Double(0.0f)).Evaluate(dummy));
+}
+
+// Test GetRateStats.
+TEST_F(TraceEventAnalyzerTest, RateStats) {
+  std::vector<TraceEvent> events;
+  events.reserve(100);
+  TraceEventVector event_ptrs;
+  TraceEvent event;
+  event.timestamp = 0.0;
+  double little_delta = 1.0;
+  double big_delta = 10.0;
+  double tiny_delta = 0.1;
+  RateStats stats;
+  RateStatsOptions options;
+
+  // Insert 10 events, each apart by little_delta.
+  for (int i = 0; i < 10; ++i) {
+    event.timestamp += little_delta;
+    events.push_back(event);
+    event_ptrs.push_back(&events.back());
+  }
+
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, NULL));
+  EXPECT_EQ(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(little_delta, stats.max_us);
+  EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+  // Add an event apart by big_delta.
+  event.timestamp += big_delta;
+  events.push_back(event);
+  event_ptrs.push_back(&events.back());
+
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, NULL));
+  EXPECT_LT(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(big_delta, stats.max_us);
+  EXPECT_LT(0.0, stats.standard_deviation_us);
+
+  // Trim off the biggest delta and verify stats.
+  options.trim_min = 0;
+  options.trim_max = 1;
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, &options));
+  EXPECT_EQ(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(little_delta, stats.max_us);
+  EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+  // Add an event apart by tiny_delta.
+  event.timestamp += tiny_delta;
+  events.push_back(event);
+  event_ptrs.push_back(&events.back());
+
+  // Trim off both the biggest and tiniest delta and verify stats.
+  options.trim_min = 1;
+  options.trim_max = 1;
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, &options));
+  EXPECT_EQ(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(little_delta, stats.max_us);
+  EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+  // Verify smallest allowed number of events.
+  TraceEventVector few_event_ptrs;
+  few_event_ptrs.push_back(&event);
+  few_event_ptrs.push_back(&event);
+  ASSERT_FALSE(GetRateStats(few_event_ptrs, &stats, NULL));
+  few_event_ptrs.push_back(&event);
+  ASSERT_TRUE(GetRateStats(few_event_ptrs, &stats, NULL));
+
+  // Trim off more than allowed and verify failure.
+  options.trim_min = 0;
+  options.trim_max = 1;
+  ASSERT_FALSE(GetRateStats(few_event_ptrs, &stats, &options));
+}
+
+// Test FindFirstOf and FindLastOf.
+TEST_F(TraceEventAnalyzerTest, FindOf) {
+  size_t num_events = 100;
+  size_t index = 0;
+  TraceEventVector event_ptrs;
+  EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(true), 0, &index));
+  EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(true), 10, &index));
+  EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(true), 0, &index));
+  EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(true), 10, &index));
+
+  std::vector<TraceEvent> events;
+  events.resize(num_events);
+  for (size_t i = 0; i < events.size(); ++i)
+    event_ptrs.push_back(&events[i]);
+  size_t bam_index = num_events/2;
+  events[bam_index].name = "bam";
+  Query query_bam = Query::EventName() == Query::String(events[bam_index].name);
+
+  // FindFirstOf
+  EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(false), 0, &index));
+  EXPECT_TRUE(FindFirstOf(event_ptrs, Query::Bool(true), 0, &index));
+  EXPECT_EQ(0u, index);
+  EXPECT_TRUE(FindFirstOf(event_ptrs, Query::Bool(true), 5, &index));
+  EXPECT_EQ(5u, index);
+
+  EXPECT_FALSE(FindFirstOf(event_ptrs, query_bam, bam_index + 1, &index));
+  EXPECT_TRUE(FindFirstOf(event_ptrs, query_bam, 0, &index));
+  EXPECT_EQ(bam_index, index);
+  EXPECT_TRUE(FindFirstOf(event_ptrs, query_bam, bam_index, &index));
+  EXPECT_EQ(bam_index, index);
+
+  // FindLastOf
+  EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(false), 1000, &index));
+  EXPECT_TRUE(FindLastOf(event_ptrs, Query::Bool(true), 1000, &index));
+  EXPECT_EQ(num_events - 1, index);
+  EXPECT_TRUE(FindLastOf(event_ptrs, Query::Bool(true), num_events - 5,
+                         &index));
+  EXPECT_EQ(num_events - 5, index);
+
+  EXPECT_FALSE(FindLastOf(event_ptrs, query_bam, bam_index - 1, &index));
+  EXPECT_TRUE(FindLastOf(event_ptrs, query_bam, num_events, &index));
+  EXPECT_EQ(bam_index, index);
+  EXPECT_TRUE(FindLastOf(event_ptrs, query_bam, bam_index, &index));
+  EXPECT_EQ(bam_index, index);
+}
+
+// Test FindClosest.
+TEST_F(TraceEventAnalyzerTest, FindClosest) {
+  size_t index_1 = 0;
+  size_t index_2 = 0;
+  TraceEventVector event_ptrs;
+  EXPECT_FALSE(FindClosest(event_ptrs, Query::Bool(true), 0,
+                           &index_1, &index_2));
+
+  size_t num_events = 5;
+  std::vector<TraceEvent> events;
+  events.resize(num_events);
+  for (size_t i = 0; i < events.size(); ++i) {
+    // timestamps go up exponentially so the lower index is always closer in
+    // time than the higher index.
+    events[i].timestamp = static_cast<double>(i) * static_cast<double>(i);
+    event_ptrs.push_back(&events[i]);
+  }
+  events[0].name = "one";
+  events[2].name = "two";
+  events[4].name = "three";
+  Query query_named = Query::EventName() != Query::String("");
+  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("");
+  Query query_one = Query::EventName() == Query::String("one");
+
+  EXPECT_EQ(0u, CountMatches(event_ptrs, Query::Bool(false)));
+  EXPECT_EQ(num_events, CountMatches(event_ptrs, Query::Bool(true)));
+  EXPECT_EQ(num_events - 1, CountMatches(event_ptrs, Query::Bool(true),
+                                         1, num_events));
+  EXPECT_EQ(1u, CountMatches(event_ptrs, query_one));
+  EXPECT_EQ(num_events - 1, CountMatches(event_ptrs, !query_one));
+  EXPECT_EQ(num_named, CountMatches(event_ptrs, query_named));
+}
+
+
+}  // namespace trace_analyzer
diff --git a/base/test/values_test_util.cc b/base/test/values_test_util.cc
new file mode 100644
index 0000000..a5667f1
--- /dev/null
+++ b/base/test/values_test_util.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/memory/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "base/test/values_test_util.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+void ExpectDictBooleanValue(bool expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key) {
+  bool boolean_value = false;
+  EXPECT_TRUE(value.GetBoolean(key, &boolean_value)) << key;
+  EXPECT_EQ(expected_value, boolean_value) << key;
+}
+
+void ExpectDictDictionaryValue(const DictionaryValue& expected_value,
+                               const DictionaryValue& value,
+                               const std::string& key) {
+  const DictionaryValue* dict_value = NULL;
+  EXPECT_TRUE(value.GetDictionary(key, &dict_value)) << key;
+  EXPECT_TRUE(Value::Equals(dict_value, &expected_value)) << key;
+}
+
+void ExpectDictIntegerValue(int expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key) {
+  int integer_value = 0;
+  EXPECT_TRUE(value.GetInteger(key, &integer_value)) << key;
+  EXPECT_EQ(expected_value, integer_value) << key;
+}
+
+void ExpectDictListValue(const ListValue& expected_value,
+                         const DictionaryValue& value,
+                         const std::string& key) {
+  const ListValue* list_value = NULL;
+  EXPECT_TRUE(value.GetList(key, &list_value)) << key;
+  EXPECT_TRUE(Value::Equals(list_value, &expected_value)) << key;
+}
+
+void ExpectDictStringValue(const std::string& expected_value,
+                           const DictionaryValue& value,
+                           const std::string& key) {
+  std::string string_value;
+  EXPECT_TRUE(value.GetString(key, &string_value)) << key;
+  EXPECT_EQ(expected_value, string_value) << key;
+}
+
+void ExpectStringValue(const std::string& expected_str,
+                       StringValue* actual) {
+  scoped_ptr<StringValue> scoped_actual(actual);
+  std::string actual_str;
+  EXPECT_TRUE(scoped_actual->GetAsString(&actual_str));
+  EXPECT_EQ(expected_str, actual_str);
+}
+
+}  // namespace base
diff --git a/base/test/values_test_util.h b/base/test/values_test_util.h
new file mode 100644
index 0000000..f2b5abd
--- /dev/null
+++ b/base/test/values_test_util.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_VALUES_TEST_UTIL_H_
+#define BASE_TEST_VALUES_TEST_UTIL_H_
+
+#include <string>
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class StringValue;
+
+// All the functions below expect that the value for the given key in
+// the given dictionary equals the given expected value.
+
+void ExpectDictBooleanValue(bool expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key);
+
+void ExpectDictDictionaryValue(const DictionaryValue& expected_value,
+                               const DictionaryValue& value,
+                               const std::string& key);
+
+void ExpectDictIntegerValue(int expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key);
+
+void ExpectDictListValue(const ListValue& expected_value,
+                         const DictionaryValue& value,
+                         const std::string& key);
+
+void ExpectDictStringValue(const std::string& expected_value,
+                           const DictionaryValue& value,
+                           const std::string& key);
+
+// Takes ownership of |actual|.
+void ExpectStringValue(const std::string& expected_str,
+                       StringValue* actual);
+
+}  // namespace base
+
+#endif  // BASE_TEST_VALUES_TEST_UTIL_H_
diff --git a/base/third_party/dmg_fp/LICENSE b/base/third_party/dmg_fp/LICENSE
new file mode 100644
index 0000000..716f1ef
--- /dev/null
+++ b/base/third_party/dmg_fp/LICENSE
@@ -0,0 +1,18 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
diff --git a/base/third_party/dmg_fp/README.chromium b/base/third_party/dmg_fp/README.chromium
new file mode 100644
index 0000000..10db408
--- /dev/null
+++ b/base/third_party/dmg_fp/README.chromium
@@ -0,0 +1,22 @@
+Name: David M. Gay's floating point routines
+URL: http://www.netlib.org/fp/
+License: MIT-like
+
+Original dtoa.c file can be found at <http://www.netlib.org/fp/dtoa.c>.
+Original g_fmt.c file can be found at <http://www.netlib.org/fp/g_fmt.c>.
+
+List of changes made to original code:
+  - wrapped functions in dmg_fp namespace
+  - renamed .c files to .cc
+  - added dmg_fp.h header
+  - added #define IEEE_8087 to dtoa.cc
+  - added #define NO_HEX_FP to dtoa.cc
+  - made some minor changes to allow clean compilation under g++ -Wall, see
+    gcc_warnings.patch.
+  - made some minor changes to build on 64-bit, see gcc_64_bit.patch.
+  - made minor changes for -Wextra for Mac build, see mac_wextra.patch
+  - crash fix for running with reduced CPU float precision, see
+    float_precision_crash.patch and crbug.com/123157
+  - Fix for 'warning C4703: potentially uninitialized local pointer variable'
+    in VS2012.
+
diff --git a/base/third_party/dmg_fp/dmg_fp.h b/base/third_party/dmg_fp/dmg_fp.h
new file mode 100644
index 0000000..4795397
--- /dev/null
+++ b/base/third_party/dmg_fp/dmg_fp.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_DMG_FP_H_
+#define THIRD_PARTY_DMG_FP_H_
+
+namespace dmg_fp {
+
+// Return a nearest machine number to the input decimal
+// string (or set errno to ERANGE). With IEEE arithmetic, ties are
+// broken by the IEEE round-even rule.  Otherwise ties are broken by
+// biased rounding (add half and chop).
+double strtod(const char* s00, char** se);
+
+// Convert double to ASCII string. For meaning of parameters
+// see dtoa.cc file.
+char* dtoa(double d, int mode, int ndigits,
+           int* decpt, int* sign, char** rve);
+
+// Must be used to free values returned by dtoa.
+void freedtoa(char* s);
+
+// Store the closest decimal approximation to x in b (null terminated).
+// Returns a pointer to b.  It is sufficient for |b| to be 32 characters.
+char* g_fmt(char* b, double x);
+
+}  // namespace dmg_fp
+
+#endif  // THIRD_PARTY_DMG_FP_H_
diff --git a/base/third_party/dmg_fp/dtoa.cc b/base/third_party/dmg_fp/dtoa.cc
new file mode 100644
index 0000000..4eb9f0e
--- /dev/null
+++ b/base/third_party/dmg_fp/dtoa.cc
@@ -0,0 +1,4209 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa.
+ * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ *	and strtod and dtoa should round accordingly.  Unless Trust_FLT_ROUNDS
+ *	is also #defined, fegetround() will be queried for the rounding mode.
+ *	Note that both FLT_ROUNDS and fegetround() are specified by the C99
+ *	standard (and are specified to be consistent, with fesetround()
+ *	affecting the value of FLT_ROUNDS), but that some (Linux) systems
+ *	do not work correctly in this regard, so using fegetround() is more
+ *	portable than using FLT_FOUNDS directly.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ *	and Honor_FLT_ROUNDS is not #defined.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a dtoa call after a dtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  The longest string dtoa can return is about 751 bytes
+ *	long.  For conversions by strtod of strings of 800 digits and
+ *	all dtoa conversions in single-threaded executions with 8-byte
+ *	pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
+ *	pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ *	#defined automatically on IEEE systems.  On such systems,
+ *	when INFNAN_CHECK is #defined, strtod checks
+ *	for Infinity and NaN (case insensitively).  On some systems
+ *	(e.g., some HP systems), it may be necessary to #define NAN_WORD0
+ *	appropriately -- to the most significant word of a quiet NaN.
+ *	(On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtod also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits and spaces;
+ *	if there is only one string of hexadecimal digits, it is taken
+ *	for the 52 fraction bits of the resulting NaN; if there are two
+ *	or more strings of hex digits, the first is for the high 20 bits,
+ *	the second and subsequent for the low 32 bits, with intervening
+ *	white space ignored; but if this results in none of the 52
+ *	fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
+ *	and NAN_WORD1 are used instead.
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
+ *	avoids underflows on inputs whose result does not underflow.
+ *	If you #define NO_IEEE_Scale on a machine that uses IEEE-format
+ *	floating-point numbers and flushes underflows to zero rather
+ *	than implementing gradual underflow, then you must also #define
+ *	Sudden_Underflow.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ * #define SET_INEXACT if IEEE arithmetic is being used and extra
+ *	computation should be done to set the inexact flag when the
+ *	result is inexact and avoid setting inexact when the result
+ *	is exact.  In this case, dtoa.c must be compiled in
+ *	an environment, perhaps provided by #include "dtoa.c" in a
+ *	suitable wrapper, that defines two functions,
+ *		int get_inexact(void);
+ *		void clear_inexact(void);
+ *	such that get_inexact() returns a nonzero value if the
+ *	inexact bit is already set, and clear_inexact() sets the
+ *	inexact bit to 0.  When SET_INEXACT is #defined, strtod
+ *	also does extra computations to set the underflow and overflow
+ *	flags when appropriate (i.e., when the result is tiny and
+ *	inexact or when it is a numeric value rounded to +-infinity).
+ * #define NO_ERRNO if strtod should not assign errno = ERANGE when
+ *	the result overflows to +-Infinity or underflows to 0.
+ * #define NO_HEX_FP to omit recognition of hexadecimal floating-point
+ *	values by strtod.
+ * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now)
+ *	to disable logic for "fast" testing of very long input strings
+ *	to strtod.  This testing proceeds by initially truncating the
+ *	input string, then if necessary comparing the whole string with
+ *	a decimal expansion to decide close cases. This logic is only
+ *	used for input more than STRTOD_DIGLIM digits long (default 40).
+ */
+
+#define IEEE_8087
+#define NO_HEX_FP
+
+#ifndef Long
+#if __LP64__
+#define Long int
+#else
+#define Long long
+#endif
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+
+#ifdef DEBUG
+#include "stdio.h"
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef USE_LOCALE
+#include "locale.h"
+#endif
+
+#ifdef Honor_FLT_ROUNDS
+#ifndef Trust_FLT_ROUNDS
+#include <fenv.h>
+#endif
+#endif
+
+#ifdef MALLOC
+#ifdef KR_headers
+extern char *MALLOC();
+#else
+extern void *MALLOC(size_t);
+#endif
+#else
+#define MALLOC malloc
+#endif
+
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((unsigned)((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#ifdef IEEE_Arith
+#ifndef NO_INFNAN_CHECK
+#undef INFNAN_CHECK
+#define INFNAN_CHECK
+#endif
+#else
+#undef INFNAN_CHECK
+#define NO_STRTOD_BIGCOMP
+#endif
+
+#include "errno.h"
+
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#endif /*IEEE_Arith*/
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+#endif /* Bad_float_h */
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+namespace dmg_fp {
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef IEEE_8087
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#else
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#endif
+#define dval(x) (x)->d
+
+#ifndef STRTOD_DIGLIM
+#define STRTOD_DIGLIM 40
+#endif
+
+#ifdef DIGLIM_DEBUG
+extern int strtod_diglim;
+#else
+#define strtod_diglim STRTOD_DIGLIM
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift  20
+#define Exp_shift1 20
+#define Exp_msk1    0x100000
+#define Exp_msk11   0x100000
+#define Exp_mask  0x7ff00000
+#define P 53
+#define Nbits 53
+#define Bias 1023
+#define Emax 1023
+#define Emin (-1022)
+#define Exp_1  0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask  0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask  0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#ifndef NO_IEEE_Scale
+#define Avoid_Underflow
+#ifdef Flush_Denorm	/* debugging option */
+#undef Sudden_Underflow
+#endif
+#endif
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+#else /* ifndef IEEE_Arith */
+#undef Check_FLT_ROUNDS
+#undef Honor_FLT_ROUNDS
+#undef SET_INEXACT
+#undef  Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift  24
+#define Exp_shift1 24
+#define Exp_msk1   0x1000000
+#define Exp_msk11  0x1000000
+#define Exp_mask  0x7f000000
+#define P 14
+#define Nbits 56
+#define Bias 65
+#define Emax 248
+#define Emin (-260)
+#define Exp_1  0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8	/* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask  0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask  0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift  23
+#define Exp_shift1 7
+#define Exp_msk1    0x80
+#define Exp_msk11   0x800000
+#define Exp_mask  0x7f80
+#define P 56
+#define Nbits 56
+#define Bias 129
+#define Emax 126
+#define Emin (-129)
+#define Exp_1  0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask  0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask  0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+#ifdef KR_headers
+extern double rnd_prod(), rnd_quot();
+#else
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#endif
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+typedef struct BCinfo BCinfo;
+ struct
+BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; };
+
+#ifdef KR_headers
+#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff)
+#else
+#define FFFFFFFF 0xffffffffUL
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower.  Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else	/* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
+#define FREE_DTOA_LOCK(n)	/*nothing*/
+#endif
+
+#define Kmax 7
+
+double strtod(const char *s00, char **se);
+char *dtoa(double d, int mode, int ndigits,
+			int *decpt, int *sign, char **rve);
+
+ struct
+Bigint {
+	struct Bigint *next;
+	int k, maxwds, sign, wds;
+	ULong x[1];
+	};
+
+ typedef struct Bigint Bigint;
+
+ static Bigint *freelist[Kmax+1];
+
+ static Bigint *
+Balloc
+#ifdef KR_headers
+	(k) int k;
+#else
+	(int k)
+#endif
+{
+	int x;
+	Bigint *rv;
+#ifndef Omit_Private_Memory
+	unsigned int len;
+#endif
+
+	ACQUIRE_DTOA_LOCK(0);
+	/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+	/* but this case seems very unlikely. */
+	if (k <= Kmax && (rv = freelist[k]))
+		freelist[k] = rv->next;
+	else {
+		x = 1 << k;
+#ifdef Omit_Private_Memory
+		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+#else
+		len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+			/sizeof(double);
+		if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+			rv = (Bigint*)pmem_next;
+			pmem_next += len;
+			}
+		else
+			rv = (Bigint*)MALLOC(len*sizeof(double));
+#endif
+		rv->k = k;
+		rv->maxwds = x;
+		}
+	FREE_DTOA_LOCK(0);
+	rv->sign = rv->wds = 0;
+	return rv;
+	}
+
+ static void
+Bfree
+#ifdef KR_headers
+	(v) Bigint *v;
+#else
+	(Bigint *v)
+#endif
+{
+	if (v) {
+		if (v->k > Kmax)
+#ifdef FREE
+			FREE((void*)v);
+#else
+			free((void*)v);
+#endif
+		else {
+			ACQUIRE_DTOA_LOCK(0);
+			v->next = freelist[v->k];
+			freelist[v->k] = v;
+			FREE_DTOA_LOCK(0);
+			}
+		}
+	}
+
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+y->wds*sizeof(Long) + 2*sizeof(int))
+
+ static Bigint *
+multadd
+#ifdef KR_headers
+	(b, m, a) Bigint *b; int m, a;
+#else
+	(Bigint *b, int m, int a)	/* multiply by m and add a */
+#endif
+{
+	int i, wds;
+#ifdef ULLong
+	ULong *x;
+	ULLong carry, y;
+#else
+	ULong carry, *x, y;
+#ifdef Pack_32
+	ULong xi, z;
+#endif
+#endif
+	Bigint *b1;
+
+	wds = b->wds;
+	x = b->x;
+	i = 0;
+	carry = a;
+	do {
+#ifdef ULLong
+		y = *x * (ULLong)m + carry;
+		carry = y >> 32;
+		*x++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+		xi = *x;
+		y = (xi & 0xffff) * m + carry;
+		z = (xi >> 16) * m + (y >> 16);
+		carry = z >> 16;
+		*x++ = (z << 16) + (y & 0xffff);
+#else
+		y = *x * m + carry;
+		carry = y >> 16;
+		*x++ = y & 0xffff;
+#endif
+#endif
+		}
+		while(++i < wds);
+	if (carry) {
+		if (wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			Bcopy(b1, b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[wds++] = carry;
+		b->wds = wds;
+		}
+	return b;
+	}
+
+ static Bigint *
+s2b
+#ifdef KR_headers
+	(s, nd0, nd, y9, dplen) CONST char *s; int nd0, nd, dplen; ULong y9;
+#else
+	(CONST char *s, int nd0, int nd, ULong y9, int dplen)
+#endif
+{
+	Bigint *b;
+	int i, k;
+	Long x, y;
+
+	x = (nd + 8) / 9;
+	for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+	b = Balloc(k);
+	b->x[0] = y9;
+	b->wds = 1;
+#else
+	b = Balloc(k+1);
+	b->x[0] = y9 & 0xffff;
+	b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+	i = 9;
+	if (9 < nd0) {
+		s += 9;
+		do b = multadd(b, 10, *s++ - '0');
+			while(++i < nd0);
+		s += dplen;
+		}
+	else
+		s += dplen + 9;
+	for(; i < nd; i++)
+		b = multadd(b, 10, *s++ - '0');
+	return b;
+	}
+
+ static int
+hi0bits
+#ifdef KR_headers
+	(x) ULong x;
+#else
+	(ULong x)
+#endif
+{
+	int k = 0;
+
+	if (!(x & 0xffff0000)) {
+		k = 16;
+		x <<= 16;
+		}
+	if (!(x & 0xff000000)) {
+		k += 8;
+		x <<= 8;
+		}
+	if (!(x & 0xf0000000)) {
+		k += 4;
+		x <<= 4;
+		}
+	if (!(x & 0xc0000000)) {
+		k += 2;
+		x <<= 2;
+		}
+	if (!(x & 0x80000000)) {
+		k++;
+		if (!(x & 0x40000000))
+			return 32;
+		}
+	return k;
+	}
+
+ static int
+lo0bits
+#ifdef KR_headers
+	(y) ULong *y;
+#else
+	(ULong *y)
+#endif
+{
+	int k;
+	ULong x = *y;
+
+	if (x & 7) {
+		if (x & 1)
+			return 0;
+		if (x & 2) {
+			*y = x >> 1;
+			return 1;
+			}
+		*y = x >> 2;
+		return 2;
+		}
+	k = 0;
+	if (!(x & 0xffff)) {
+		k = 16;
+		x >>= 16;
+		}
+	if (!(x & 0xff)) {
+		k += 8;
+		x >>= 8;
+		}
+	if (!(x & 0xf)) {
+		k += 4;
+		x >>= 4;
+		}
+	if (!(x & 0x3)) {
+		k += 2;
+		x >>= 2;
+		}
+	if (!(x & 1)) {
+		k++;
+		x >>= 1;
+		if (!x)
+			return 32;
+		}
+	*y = x;
+	return k;
+	}
+
+ static Bigint *
+i2b
+#ifdef KR_headers
+	(i) int i;
+#else
+	(int i)
+#endif
+{
+	Bigint *b;
+
+	b = Balloc(1);
+	b->x[0] = i;
+	b->wds = 1;
+	return b;
+	}
+
+ static Bigint *
+mult
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int k, wa, wb, wc;
+	ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+	ULong y;
+#ifdef ULLong
+	ULLong carry, z;
+#else
+	ULong carry, z;
+#ifdef Pack_32
+	ULong z2;
+#endif
+#endif
+
+	if (a->wds < b->wds) {
+		c = a;
+		a = b;
+		b = c;
+		}
+	k = a->k;
+	wa = a->wds;
+	wb = b->wds;
+	wc = wa + wb;
+	if (wc > a->maxwds)
+		k++;
+	c = Balloc(k);
+	for(x = c->x, xa = x + wc; x < xa; x++)
+		*x = 0;
+	xa = a->x;
+	xae = xa + wa;
+	xb = b->x;
+	xbe = xb + wb;
+	xc0 = c->x;
+#ifdef ULLong
+	for(; xb < xbe; xc0++) {
+		if ((y = *xb++)) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * (ULLong)y + *xc + carry;
+				carry = z >> 32;
+				*xc++ = z & FFFFFFFF;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#else
+#ifdef Pack_32
+	for(; xb < xbe; xb++, xc0++) {
+		if (y = *xb & 0xffff) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+				carry = z >> 16;
+				z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+				carry = z2 >> 16;
+				Storeinc(xc, z2, z);
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		if (y = *xb >> 16) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			z2 = *xc;
+			do {
+				z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+				carry = z >> 16;
+				Storeinc(xc, z, z2);
+				z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+				carry = z2 >> 16;
+				}
+				while(x < xae);
+			*xc = z2;
+			}
+		}
+#else
+	for(; xb < xbe; xc0++) {
+		if (y = *xb++) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * y + *xc + carry;
+				carry = z >> 16;
+				*xc++ = z & 0xffff;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#endif
+#endif
+	for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+	c->wds = wc;
+	return c;
+	}
+
+ static Bigint *p5s;
+
+ static Bigint *
+pow5mult
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	Bigint *b1, *p5, *p51;
+	int i;
+	static int p05[3] = { 5, 25, 125 };
+
+	if ((i = k & 3))
+		b = multadd(b, p05[i-1], 0);
+
+	if (!(k >>= 2))
+		return b;
+	if (!(p5 = p5s)) {
+		/* first time */
+#ifdef MULTIPLE_THREADS
+		ACQUIRE_DTOA_LOCK(1);
+		if (!(p5 = p5s)) {
+			p5 = p5s = i2b(625);
+			p5->next = 0;
+			}
+		FREE_DTOA_LOCK(1);
+#else
+		p5 = p5s = i2b(625);
+		p5->next = 0;
+#endif
+		}
+	for(;;) {
+		if (k & 1) {
+			b1 = mult(b, p5);
+			Bfree(b);
+			b = b1;
+			}
+		if (!(k >>= 1))
+			break;
+		if (!(p51 = p5->next)) {
+#ifdef MULTIPLE_THREADS
+			ACQUIRE_DTOA_LOCK(1);
+			if (!(p51 = p5->next)) {
+				p51 = p5->next = mult(p5,p5);
+				p51->next = 0;
+				}
+			FREE_DTOA_LOCK(1);
+#else
+			p51 = p5->next = mult(p5,p5);
+			p51->next = 0;
+#endif
+			}
+		p5 = p51;
+		}
+	return b;
+	}
+
+ static Bigint *
+lshift
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	int i, k1, n, n1;
+	Bigint *b1;
+	ULong *x, *x1, *xe, z;
+
+#ifdef Pack_32
+	n = k >> 5;
+#else
+	n = k >> 4;
+#endif
+	k1 = b->k;
+	n1 = n + b->wds + 1;
+	for(i = b->maxwds; n1 > i; i <<= 1)
+		k1++;
+	b1 = Balloc(k1);
+	x1 = b1->x;
+	for(i = 0; i < n; i++)
+		*x1++ = 0;
+	x = b->x;
+	xe = x + b->wds;
+#ifdef Pack_32
+	if (k &= 0x1f) {
+		k1 = 32 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if ((*x1 = z))
+			++n1;
+		}
+#else
+	if (k &= 0xf) {
+		k1 = 16 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k  & 0xffff | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if (*x1 = z)
+			++n1;
+		}
+#endif
+	else do
+		*x1++ = *x++;
+		while(x < xe);
+	b1->wds = n1 - 1;
+	Bfree(b);
+	return b1;
+	}
+
+ static int
+cmp
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	ULong *xa, *xa0, *xb, *xb0;
+	int i, j;
+
+	i = a->wds;
+	j = b->wds;
+#ifdef DEBUG
+	if (i > 1 && !a->x[i-1])
+		Bug("cmp called with a->x[a->wds-1] == 0");
+	if (j > 1 && !b->x[j-1])
+		Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+	if (i -= j)
+		return i;
+	xa0 = a->x;
+	xa = xa0 + j;
+	xb0 = b->x;
+	xb = xb0 + j;
+	for(;;) {
+		if (*--xa != *--xb)
+			return *xa < *xb ? -1 : 1;
+		if (xa <= xa0)
+			break;
+		}
+	return 0;
+	}
+
+ static Bigint *
+diff
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int i, wa, wb;
+	ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+	ULLong borrow, y;
+#else
+	ULong borrow, y;
+#ifdef Pack_32
+	ULong z;
+#endif
+#endif
+
+	i = cmp(a,b);
+	if (!i) {
+		c = Balloc(0);
+		c->wds = 1;
+		c->x[0] = 0;
+		return c;
+		}
+	if (i < 0) {
+		c = a;
+		a = b;
+		b = c;
+		i = 1;
+		}
+	else
+		i = 0;
+	c = Balloc(a->k);
+	c->sign = i;
+	wa = a->wds;
+	xa = a->x;
+	xae = xa + wa;
+	wb = b->wds;
+	xb = b->x;
+	xbe = xb + wb;
+	xc = c->x;
+	borrow = 0;
+#ifdef ULLong
+	do {
+		y = (ULLong)*xa++ - *xb++ - borrow;
+		borrow = y >> 32 & (ULong)1;
+		*xc++ = y & FFFFFFFF;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = y >> 32 & (ULong)1;
+		*xc++ = y & FFFFFFFF;
+		}
+#else
+#ifdef Pack_32
+	do {
+		y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = (*xa & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+#else
+	do {
+		y = *xa++ - *xb++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+#endif
+#endif
+	while(!*--xc)
+		wa--;
+	c->wds = wa;
+	return c;
+	}
+
+ static double
+ulp
+#ifdef KR_headers
+	(x) U *x;
+#else
+	(U *x)
+#endif
+{
+	Long L;
+	U u;
+
+	L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+	if (L > 0) {
+#endif
+#endif
+#ifdef IBM
+		L |= Exp_msk1 >> 4;
+#endif
+		word0(&u) = L;
+		word1(&u) = 0;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+		}
+	else {
+		L = -L >> Exp_shift;
+		if (L < Exp_shift) {
+			word0(&u) = 0x80000 >> L;
+			word1(&u) = 0;
+			}
+		else {
+			word0(&u) = 0;
+			L -= Exp_shift;
+			word1(&u) = L >= 31 ? 1 : 1 << 31 - L;
+			}
+		}
+#endif
+#endif
+	return dval(&u);
+	}
+
+ static double
+b2d
+#ifdef KR_headers
+	(a, e) Bigint *a; int *e;
+#else
+	(Bigint *a, int *e)
+#endif
+{
+	ULong *xa, *xa0, w, y, z;
+	int k;
+	U d;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+
+	xa0 = a->x;
+	xa = xa0 + a->wds;
+	y = *--xa;
+#ifdef DEBUG
+	if (!y) Bug("zero y in b2d");
+#endif
+	k = hi0bits(y);
+	*e = 32 - k;
+#ifdef Pack_32
+	if (k < Ebits) {
+		d0 = Exp_1 | y >> (Ebits - k);
+		w = xa > xa0 ? *--xa : 0;
+		d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	if (k -= Ebits) {
+		d0 = Exp_1 | y << k | z >> (32 - k);
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k | y >> (32 - k);
+		}
+	else {
+		d0 = Exp_1 | y;
+		d1 = z;
+		}
+#else
+	if (k < Ebits + 16) {
+		z = xa > xa0 ? *--xa : 0;
+		d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+		w = xa > xa0 ? *--xa : 0;
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	w = xa > xa0 ? *--xa : 0;
+	k -= Ebits + 16;
+	d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+	y = xa > xa0 ? *--xa : 0;
+	d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+	word0(&d) = d0 >> 16 | d0 << 16;
+	word1(&d) = d1 >> 16 | d1 << 16;
+#else
+#undef d0
+#undef d1
+#endif
+	return dval(&d);
+	}
+
+ static Bigint *
+d2b
+#ifdef KR_headers
+	(d, e, bits) U *d; int *e, *bits;
+#else
+	(U *d, int *e, int *bits)
+#endif
+{
+	Bigint *b;
+	int de, k;
+	ULong *x, y, z;
+#ifndef Sudden_Underflow
+	int i;
+#endif
+#ifdef VAX
+	ULong d0, d1;
+	d0 = word0(d) >> 16 | word0(d) << 16;
+	d1 = word1(d) >> 16 | word1(d) << 16;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+#ifdef Pack_32
+	b = Balloc(1);
+#else
+	b = Balloc(2);
+#endif
+	x = b->x;
+
+	z = d0 & Frac_mask;
+	d0 &= 0x7fffffff;	/* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+	de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+	z |= Exp_msk11;
+#endif
+#else
+	if ((de = (int)(d0 >> Exp_shift)))
+		z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+	if ((y = d1)) {
+		if ((k = lo0bits(&y))) {
+			x[0] = y | z << (32 - k);
+			z >>= k;
+			}
+		else
+			x[0] = y;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		    b->wds = (x[1] = z) ? 2 : 1;
+		}
+	else {
+		k = lo0bits(&z);
+		x[0] = z;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		    b->wds = 1;
+		k += 32;
+		}
+#else
+	if (y = d1) {
+		if (k = lo0bits(&y))
+			if (k >= 16) {
+				x[0] = y | z << 32 - k & 0xffff;
+				x[1] = z >> k - 16 & 0xffff;
+				x[2] = z >> k;
+				i = 2;
+				}
+			else {
+				x[0] = y & 0xffff;
+				x[1] = y >> 16 | z << 16 - k & 0xffff;
+				x[2] = z >> k & 0xffff;
+				x[3] = z >> k+16;
+				i = 3;
+				}
+		else {
+			x[0] = y & 0xffff;
+			x[1] = y >> 16;
+			x[2] = z & 0xffff;
+			x[3] = z >> 16;
+			i = 3;
+			}
+		}
+	else {
+#ifdef DEBUG
+		if (!z)
+			Bug("Zero passed to d2b");
+#endif
+		k = lo0bits(&z);
+		if (k >= 16) {
+			x[0] = z;
+			i = 0;
+			}
+		else {
+			x[0] = z & 0xffff;
+			x[1] = z >> 16;
+			i = 1;
+			}
+		k += 32;
+		}
+	while(!x[i])
+		--i;
+	b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+	if (de) {
+#endif
+#ifdef IBM
+		*e = (de - Bias - (P-1) << 2) + k;
+		*bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask);
+#else
+		*e = de - Bias - (P-1) + k;
+		*bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+		}
+	else {
+		*e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+		*bits = 32*i - hi0bits(x[i-1]);
+#else
+		*bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+		}
+#endif
+	return b;
+	}
+#undef d0
+#undef d1
+
+ static double
+ratio
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	U da, db;
+	int k, ka, kb;
+
+	dval(&da) = b2d(a, &ka);
+	dval(&db) = b2d(b, &kb);
+#ifdef Pack_32
+	k = ka - kb + 32*(a->wds - b->wds);
+#else
+	k = ka - kb + 16*(a->wds - b->wds);
+#endif
+#ifdef IBM
+	if (k > 0) {
+		word0(&da) += (k >> 2)*Exp_msk1;
+		if (k &= 3)
+			dval(&da) *= 1 << k;
+		}
+	else {
+		k = -k;
+		word0(&db) += (k >> 2)*Exp_msk1;
+		if (k &= 3)
+			dval(&db) *= 1 << k;
+		}
+#else
+	if (k > 0)
+		word0(&da) += k*Exp_msk1;
+	else {
+		k = -k;
+		word0(&db) += k*Exp_msk1;
+		}
+#endif
+	return dval(&da) / dval(&db);
+	}
+
+ static CONST double
+tens[] = {
+		1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+		1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+		1e20, 1e21, 1e22
+#ifdef VAX
+		, 1e23, 1e24
+#endif
+		};
+
+ static CONST double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+#ifdef Avoid_Underflow
+		9007199254740992.*9007199254740992.e-256
+		/* = 2^106 * 1e-256 */
+#else
+		1e-256
+#endif
+		};
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily.  It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#define n_bigtens 3
+#else
+bigtens[] = { 1e16, 1e32 };
+static CONST double tinytens[] = { 1e-16, 1e-32 };
+#define n_bigtens 2
+#endif
+#endif
+
+#undef Need_Hexdig
+#ifdef INFNAN_CHECK
+#ifndef No_Hex_NaN
+#define Need_Hexdig
+#endif
+#endif
+
+#ifndef Need_Hexdig
+#ifndef NO_HEX_FP
+#define Need_Hexdig
+#endif
+#endif
+
+#ifdef Need_Hexdig /*{*/
+static unsigned char hexdig[256];
+
+ static void
+#ifdef KR_headers
+htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc;
+#else
+htinit(unsigned char *h, unsigned char *s, int inc)
+#endif
+{
+	int i, j;
+	for(i = 0; (j = s[i]) !=0; i++)
+		h[j] = i + inc;
+	}
+
+ static void
+#ifdef KR_headers
+hexdig_init()
+#else
+hexdig_init(void)
+#endif
+{
+#define USC (unsigned char *)
+	htinit(hexdig, USC "0123456789", 0x10);
+	htinit(hexdig, USC "abcdef", 0x10 + 10);
+	htinit(hexdig, USC "ABCDEF", 0x10 + 10);
+	}
+#endif /* } Need_Hexdig */
+
+#ifdef INFNAN_CHECK
+
+#ifndef NAN_WORD0
+#define NAN_WORD0 0x7ff80000
+#endif
+
+#ifndef NAN_WORD1
+#define NAN_WORD1 0
+#endif
+
+ static int
+match
+#ifdef KR_headers
+	(sp, t) char **sp, *t;
+#else
+	(CONST char **sp, CONST char *t)
+#endif
+{
+	int c, d;
+	CONST char *s = *sp;
+
+	while((d = *t++)) {
+		if ((c = *++s) >= 'A' && c <= 'Z')
+			c += 'a' - 'A';
+		if (c != d)
+			return 0;
+		}
+	*sp = s + 1;
+	return 1;
+	}
+
+#ifndef No_Hex_NaN
+ static void
+hexnan
+#ifdef KR_headers
+	(rvp, sp) U *rvp; CONST char **sp;
+#else
+	(U *rvp, CONST char **sp)
+#endif
+{
+	ULong c, x[2];
+	CONST char *s;
+	int c1, havedig, udx0, xshift;
+
+	if (!hexdig['0'])
+		hexdig_init();
+	x[0] = x[1] = 0;
+	havedig = xshift = 0;
+	udx0 = 1;
+	s = *sp;
+	/* allow optional initial 0x or 0X */
+	while((c = *(CONST unsigned char*)(s+1)) && c <= ' ')
+		++s;
+	if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X'))
+		s += 2;
+	while((c = *(CONST unsigned char*)++s)) {
+		if ((c1 = hexdig[c]))
+			c  = c1 & 0xf;
+		else if (c <= ' ') {
+			if (udx0 && havedig) {
+				udx0 = 0;
+				xshift = 1;
+				}
+			continue;
+			}
+#ifdef GDTOA_NON_PEDANTIC_NANCHECK
+		else if (/*(*/ c == ')' && havedig) {
+			*sp = s + 1;
+			break;
+			}
+		else
+			return;	/* invalid form: don't change *sp */
+#else
+		else {
+			do {
+				if (/*(*/ c == ')') {
+					*sp = s + 1;
+					break;
+					}
+				} while((c = *++s));
+			break;
+			}
+#endif
+		havedig = 1;
+		if (xshift) {
+			xshift = 0;
+			x[0] = x[1];
+			x[1] = 0;
+			}
+		if (udx0)
+			x[0] = (x[0] << 4) | (x[1] >> 28);
+		x[1] = (x[1] << 4) | c;
+		}
+	if ((x[0] &= 0xfffff) || x[1]) {
+		word0(rvp) = Exp_mask | x[0];
+		word1(rvp) = x[1];
+		}
+	}
+#endif /*No_Hex_NaN*/
+#endif /* INFNAN_CHECK */
+
+#ifdef Pack_32
+#define ULbits 32
+#define kshift 5
+#define kmask 31
+#else
+#define ULbits 16
+#define kshift 4
+#define kmask 15
+#endif
+#ifndef NO_HEX_FP /*{*/
+
+ static void
+#ifdef KR_headers
+rshift(b, k) Bigint *b; int k;
+#else
+rshift(Bigint *b, int k)
+#endif
+{
+	ULong *x, *x1, *xe, y;
+	int n;
+
+	x = x1 = b->x;
+	n = k >> kshift;
+	if (n < b->wds) {
+		xe = x + b->wds;
+		x += n;
+		if (k &= kmask) {
+			n = 32 - k;
+			y = *x++ >> k;
+			while(x < xe) {
+				*x1++ = (y | (*x << n)) & 0xffffffff;
+				y = *x++ >> k;
+				}
+			if ((*x1 = y) !=0)
+				x1++;
+			}
+		else
+			while(x < xe)
+				*x1++ = *x++;
+		}
+	if ((b->wds = x1 - b->x) == 0)
+		b->x[0] = 0;
+	}
+
+ static ULong
+#ifdef KR_headers
+any_on(b, k) Bigint *b; int k;
+#else
+any_on(Bigint *b, int k)
+#endif
+{
+	int n, nwds;
+	ULong *x, *x0, x1, x2;
+
+	x = b->x;
+	nwds = b->wds;
+	n = k >> kshift;
+	if (n > nwds)
+		n = nwds;
+	else if (n < nwds && (k &= kmask)) {
+		x1 = x2 = x[n];
+		x1 >>= k;
+		x1 <<= k;
+		if (x1 != x2)
+			return 1;
+		}
+	x0 = x;
+	x += n;
+	while(x > x0)
+		if (*--x)
+			return 1;
+	return 0;
+	}
+
+enum {	/* rounding values: same as FLT_ROUNDS */
+	Round_zero = 0,
+	Round_near = 1,
+	Round_up = 2,
+	Round_down = 3
+	};
+
+ static Bigint *
+#ifdef KR_headers
+increment(b) Bigint *b;
+#else
+increment(Bigint *b)
+#endif
+{
+	ULong *x, *xe;
+	Bigint *b1;
+
+	x = b->x;
+	xe = x + b->wds;
+	do {
+		if (*x < (ULong)0xffffffffL) {
+			++*x;
+			return b;
+			}
+		*x++ = 0;
+		} while(x < xe);
+	{
+		if (b->wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			Bcopy(b1,b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[b->wds++] = 1;
+		}
+	return b;
+	}
+
+ void
+#ifdef KR_headers
+gethex(sp, rvp, rounding, sign)
+	CONST char **sp; U *rvp; int rounding, sign;
+#else
+gethex( CONST char **sp, U *rvp, int rounding, int sign)
+#endif
+{
+	Bigint *b;
+	CONST unsigned char *decpt, *s0, *s, *s1;
+	Long e, e1;
+	ULong L, lostbits, *x;
+	int big, denorm, esign, havedig, k, n, nbits, up, zret;
+#ifdef IBM
+	int j;
+#endif
+	enum {
+#ifdef IEEE_Arith /*{{*/
+		emax = 0x7fe - Bias - P + 1,
+		emin = Emin - P + 1
+#else /*}{*/
+		emin = Emin - P,
+#ifdef VAX
+		emax = 0x7ff - Bias - P + 1
+#endif
+#ifdef IBM
+		emax = 0x7f - Bias - P
+#endif
+#endif /*}}*/
+		};
+#ifdef USE_LOCALE
+	int i;
+#ifdef NO_LOCALE_CACHE
+	const unsigned char *decimalpoint = (unsigned char*)
+		localeconv()->decimal_point;
+#else
+	const unsigned char *decimalpoint;
+	static unsigned char *decimalpoint_cache;
+	if (!(s0 = decimalpoint_cache)) {
+		s0 = (unsigned char*)localeconv()->decimal_point;
+		if ((decimalpoint_cache = (unsigned char*)
+				MALLOC(strlen((CONST char*)s0) + 1))) {
+			strcpy((char*)decimalpoint_cache, (CONST char*)s0);
+			s0 = decimalpoint_cache;
+			}
+		}
+	decimalpoint = s0;
+#endif
+#endif
+
+	if (!hexdig['0'])
+		hexdig_init();
+	havedig = 0;
+	s0 = *(CONST unsigned char **)sp + 2;
+	while(s0[havedig] == '0')
+		havedig++;
+	s0 += havedig;
+	s = s0;
+	decpt = 0;
+	zret = 0;
+	e = 0;
+	if (hexdig[*s])
+		havedig++;
+	else {
+		zret = 1;
+#ifdef USE_LOCALE
+		for(i = 0; decimalpoint[i]; ++i) {
+			if (s[i] != decimalpoint[i])
+				goto pcheck;
+			}
+		decpt = s += i;
+#else
+		if (*s != '.')
+			goto pcheck;
+		decpt = ++s;
+#endif
+		if (!hexdig[*s])
+			goto pcheck;
+		while(*s == '0')
+			s++;
+		if (hexdig[*s])
+			zret = 0;
+		havedig = 1;
+		s0 = s;
+		}
+	while(hexdig[*s])
+		s++;
+#ifdef USE_LOCALE
+	if (*s == *decimalpoint && !decpt) {
+		for(i = 1; decimalpoint[i]; ++i) {
+			if (s[i] != decimalpoint[i])
+				goto pcheck;
+			}
+		decpt = s += i;
+#else
+	if (*s == '.' && !decpt) {
+		decpt = ++s;
+#endif
+		while(hexdig[*s])
+			s++;
+		}/*}*/
+	if (decpt)
+		e = -(((Long)(s-decpt)) << 2);
+ pcheck:
+	s1 = s;
+	big = esign = 0;
+	switch(*s) {
+	  case 'p':
+	  case 'P':
+		switch(*++s) {
+		  case '-':
+			esign = 1;
+			/* no break */
+		  case '+':
+			s++;
+		  }
+		if ((n = hexdig[*s]) == 0 || n > 0x19) {
+			s = s1;
+			break;
+			}
+		e1 = n - 0x10;
+		while((n = hexdig[*++s]) !=0 && n <= 0x19) {
+			if (e1 & 0xf8000000)
+				big = 1;
+			e1 = 10*e1 + n - 0x10;
+			}
+		if (esign)
+			e1 = -e1;
+		e += e1;
+	  }
+	*sp = (char*)s;
+	if (!havedig)
+		*sp = (char*)s0 - 1;
+	if (zret)
+		goto retz1;
+	if (big) {
+		if (esign) {
+#ifdef IEEE_Arith
+			switch(rounding) {
+			  case Round_up:
+				if (sign)
+					break;
+				goto ret_tiny;
+			  case Round_down:
+				if (!sign)
+					break;
+				goto ret_tiny;
+			  }
+#endif
+			goto retz;
+#ifdef IEEE_Arith
+ ret_tiny:
+#ifndef NO_ERRNO
+			errno = ERANGE;
+#endif
+			word0(rvp) = 0;
+			word1(rvp) = 1;
+			return;
+#endif /* IEEE_Arith */
+			}
+		switch(rounding) {
+		  case Round_near:
+			goto ovfl1;
+		  case Round_up:
+			if (!sign)
+				goto ovfl1;
+			goto ret_big;
+		  case Round_down:
+			if (sign)
+				goto ovfl1;
+			goto ret_big;
+		  }
+ ret_big:
+		word0(rvp) = Big0;
+		word1(rvp) = Big1;
+		return;
+		}
+	n = s1 - s0 - 1;
+	for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
+		k++;
+	b = Balloc(k);
+	x = b->x;
+	n = 0;
+	L = 0;
+#ifdef USE_LOCALE
+	for(i = 0; decimalpoint[i+1]; ++i);
+#endif
+	while(s1 > s0) {
+#ifdef USE_LOCALE
+		if (*--s1 == decimalpoint[i]) {
+			s1 -= i;
+			continue;
+			}
+#else
+		if (*--s1 == '.')
+			continue;
+#endif
+		if (n == ULbits) {
+			*x++ = L;
+			L = 0;
+			n = 0;
+			}
+		L |= (hexdig[*s1] & 0x0f) << n;
+		n += 4;
+		}
+	*x++ = L;
+	b->wds = n = x - b->x;
+	n = ULbits*n - hi0bits(L);
+	nbits = Nbits;
+	lostbits = 0;
+	x = b->x;
+	if (n > nbits) {
+		n -= nbits;
+		if (any_on(b,n)) {
+			lostbits = 1;
+			k = n - 1;
+			if (x[k>>kshift] & 1 << (k & kmask)) {
+				lostbits = 2;
+				if (k > 0 && any_on(b,k))
+					lostbits = 3;
+				}
+			}
+		rshift(b, n);
+		e += n;
+		}
+	else if (n < nbits) {
+		n = nbits - n;
+		b = lshift(b, n);
+		e -= n;
+		x = b->x;
+		}
+	if (e > Emax) {
+ ovfl:
+		Bfree(b);
+ ovfl1:
+#ifndef NO_ERRNO
+		errno = ERANGE;
+#endif
+		word0(rvp) = Exp_mask;
+		word1(rvp) = 0;
+		return;
+		}
+	denorm = 0;
+	if (e < emin) {
+		denorm = 1;
+		n = emin - e;
+		if (n >= nbits) {
+#ifdef IEEE_Arith /*{*/
+			switch (rounding) {
+			  case Round_near:
+				if (n == nbits && (n < 2 || any_on(b,n-1)))
+					goto ret_tiny;
+				break;
+			  case Round_up:
+				if (!sign)
+					goto ret_tiny;
+				break;
+			  case Round_down:
+				if (sign)
+					goto ret_tiny;
+			  }
+#endif /* } IEEE_Arith */
+			Bfree(b);
+ retz:
+#ifndef NO_ERRNO
+			errno = ERANGE;
+#endif
+ retz1:
+			rvp->d = 0.;
+			return;
+			}
+		k = n - 1;
+		if (lostbits)
+			lostbits = 1;
+		else if (k > 0)
+			lostbits = any_on(b,k);
+		if (x[k>>kshift] & 1 << (k & kmask))
+			lostbits |= 2;
+		nbits -= n;
+		rshift(b,n);
+		e = emin;
+		}
+	if (lostbits) {
+		up = 0;
+		switch(rounding) {
+		  case Round_zero:
+			break;
+		  case Round_near:
+			if (lostbits & 2
+			 && (lostbits & 1) | (x[0] & 1))
+				up = 1;
+			break;
+		  case Round_up:
+			up = 1 - sign;
+			break;
+		  case Round_down:
+			up = sign;
+		  }
+		if (up) {
+			k = b->wds;
+			b = increment(b);
+			x = b->x;
+			if (denorm) {
+#if 0
+				if (nbits == Nbits - 1
+				 && x[nbits >> kshift] & 1 << (nbits & kmask))
+					denorm = 0; /* not currently used */
+#endif
+				}
+			else if (b->wds > k
+			 || ((n = nbits & kmask) !=0
+			     && hi0bits(x[k-1]) < 32-n)) {
+				rshift(b,1);
+				if (++e > Emax)
+					goto ovfl;
+				}
+			}
+		}
+#ifdef IEEE_Arith
+	if (denorm)
+		word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0;
+	else
+		word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20);
+	word1(rvp) = b->x[0];
+#endif
+#ifdef IBM
+	if ((j = e & 3)) {
+		k = b->x[0] & ((1 << j) - 1);
+		rshift(b,j);
+		if (k) {
+			switch(rounding) {
+			  case Round_up:
+				if (!sign)
+					increment(b);
+				break;
+			  case Round_down:
+				if (sign)
+					increment(b);
+				break;
+			  case Round_near:
+				j = 1 << (j-1);
+				if (k & j && ((k & (j-1)) | lostbits))
+					increment(b);
+			  }
+			}
+		}
+	e >>= 2;
+	word0(rvp) = b->x[1] | ((e + 65 + 13) << 24);
+	word1(rvp) = b->x[0];
+#endif
+#ifdef VAX
+	/* The next two lines ignore swap of low- and high-order 2 bytes. */
+	/* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */
+	/* word1(rvp) = b->x[0]; */
+	word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16);
+	word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16);
+#endif
+	Bfree(b);
+	}
+#endif /*}!NO_HEX_FP*/
+
+ static int
+#ifdef KR_headers
+dshift(b, p2) Bigint *b; int p2;
+#else
+dshift(Bigint *b, int p2)
+#endif
+{
+	int rv = hi0bits(b->x[b->wds-1]) - 4;
+	if (p2 > 0)
+		rv -= p2;
+	return rv & kmask;
+	}
+
+ static int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->wds;
+#ifdef DEBUG
+	/*debug*/ if (b->wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->wds < n)
+		return 0;
+	sx = S->x;
+	sxe = sx + --n;
+	bx = b->x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & FFFFFFFF) - borrow;
+			borrow = y >> 32 & (ULong)1;
+			*bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->x;
+		sx = S->x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & FFFFFFFF) - borrow;
+			borrow = y >> 32 & (ULong)1;
+			*bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	return q;
+	}
+
+#ifndef NO_STRTOD_BIGCOMP
+
+ static void
+bigcomp
+#ifdef KR_headers
+	(rv, s0, bc)
+	U *rv; CONST char *s0; BCinfo *bc;
+#else
+	(U *rv, CONST char *s0, BCinfo *bc)
+#endif
+{
+	Bigint *b, *d;
+	int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase;
+
+	dsign = bc->dsign;
+	nd = bc->nd;
+	nd0 = bc->nd0;
+	p5 = nd + bc->e0 - 1;
+	dd = speccase = 0;
+#ifndef Sudden_Underflow
+	if (rv->d == 0.) {	/* special case: value near underflow-to-zero */
+				/* threshold was rounded to zero */
+		b = i2b(1);
+		p2 = Emin - P + 1;
+		bbits = 1;
+#ifdef Avoid_Underflow
+		word0(rv) = (P+2) << Exp_shift;
+#else
+		word1(rv) = 1;
+#endif
+		i = 0;
+#ifdef Honor_FLT_ROUNDS
+		if (bc->rounding == 1)
+#endif
+			{
+			speccase = 1;
+			--p2;
+			dsign = 0;
+			goto have_i;
+			}
+		}
+	else
+#endif
+		b = d2b(rv, &p2, &bbits);
+#ifdef Avoid_Underflow
+	p2 -= bc->scale;
+#endif
+	/* floor(log2(rv)) == bbits - 1 + p2 */
+	/* Check for denormal case. */
+	i = P - bbits;
+	if (i > (j = P - Emin - 1 + p2)) {
+#ifdef Sudden_Underflow
+		Bfree(b);
+		b = i2b(1);
+		p2 = Emin;
+		i = P - 1;
+#ifdef Avoid_Underflow
+		word0(rv) = (1 + bc->scale) << Exp_shift;
+#else
+		word0(rv) = Exp_msk1;
+#endif
+		word1(rv) = 0;
+#else
+		i = j;
+#endif
+		}
+#ifdef Honor_FLT_ROUNDS
+	if (bc->rounding != 1) {
+		if (i > 0)
+			b = lshift(b, i);
+		if (dsign)
+			b = increment(b);
+		}
+	else
+#endif
+		{
+		b = lshift(b, ++i);
+		b->x[0] |= 1;
+		}
+#ifndef Sudden_Underflow
+ have_i:
+#endif
+	p2 -= p5 + i;
+	d = i2b(1);
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 */
+	if (p5 > 0)
+		d = pow5mult(d, p5);
+	else if (p5 < 0)
+		b = pow5mult(b, -p5);
+	if (p2 > 0) {
+		b2 = p2;
+		d2 = 0;
+		}
+	else {
+		b2 = 0;
+		d2 = -p2;
+		}
+	i = dshift(d, d2);
+	if ((b2 += i) > 0)
+		b = lshift(b, b2);
+	if ((d2 += i) > 0)
+		d = lshift(d, d2);
+
+	/* Now b/d = exactly half-way between the two floating-point values */
+	/* on either side of the input string.  Compute first digit of b/d. */
+
+	if (!(dig = quorem(b,d))) {
+		b = multadd(b, 10, 0);	/* very unlikely */
+		dig = quorem(b,d);
+		}
+
+	/* Compare b/d with s0 */
+
+	for(i = 0; i < nd0; ) {
+		if ((dd = s0[i++] - '0' - dig))
+			goto ret;
+		if (!b->x[0] && b->wds == 1) {
+			if (i < nd)
+				dd = 1;
+			goto ret;
+			}
+		b = multadd(b, 10, 0);
+		dig = quorem(b,d);
+		}
+	for(j = bc->dp1; i++ < nd;) {
+		if ((dd = s0[j++] - '0' - dig))
+			goto ret;
+		if (!b->x[0] && b->wds == 1) {
+			if (i < nd)
+				dd = 1;
+			goto ret;
+			}
+		b = multadd(b, 10, 0);
+		dig = quorem(b,d);
+		}
+	if (b->x[0] || b->wds > 1)
+		dd = -1;
+ ret:
+	Bfree(b);
+	Bfree(d);
+#ifdef Honor_FLT_ROUNDS
+	if (bc->rounding != 1) {
+		if (dd < 0) {
+			if (bc->rounding == 0) {
+				if (!dsign)
+					goto retlow1;
+				}
+			else if (dsign)
+				goto rethi1;
+			}
+		else if (dd > 0) {
+			if (bc->rounding == 0) {
+				if (dsign)
+					goto rethi1;
+				goto ret1;
+				}
+			if (!dsign)
+				goto rethi1;
+			dval(rv) += 2.*ulp(rv);
+			}
+		else {
+			bc->inexact = 0;
+			if (dsign)
+				goto rethi1;
+			}
+		}
+	else
+#endif
+	if (speccase) {
+		if (dd <= 0)
+			rv->d = 0.;
+		}
+	else if (dd < 0) {
+		if (!dsign)	/* does not happen for round-near */
+retlow1:
+			dval(rv) -= ulp(rv);
+		}
+	else if (dd > 0) {
+		if (dsign) {
+ rethi1:
+			dval(rv) += ulp(rv);
+			}
+		}
+	else {
+		/* Exact half-way case:  apply round-even rule. */
+		if (word1(rv) & 1) {
+			if (dsign)
+				goto rethi1;
+			goto retlow1;
+			}
+		}
+
+#ifdef Honor_FLT_ROUNDS
+ ret1:
+#endif
+	return;
+	}
+#endif /* NO_STRTOD_BIGCOMP */
+
+ double
+strtod
+#ifdef KR_headers
+	(s00, se) CONST char *s00; char **se;
+#else
+	(CONST char *s00, char **se)
+#endif
+{
+	int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1;
+	int esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+	CONST char *s, *s0, *s1;
+	double aadj, aadj1;
+	Long L;
+	U aadj2, adj, rv, rv0;
+	ULong y, z;
+	BCinfo bc;
+	Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+#ifdef SET_INEXACT
+	int oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	bc.rounding = Flt_Rounds;
+#else /*}{*/
+	bc.rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	bc.rounding = 0; break;
+	  case FE_UPWARD:	bc.rounding = 2; break;
+	  case FE_DOWNWARD:	bc.rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+#ifdef USE_LOCALE
+	CONST char *s2;
+#endif
+
+	sign = nz0 = nz = bc.dplen = bc.uflchk = 0;
+	dval(&rv) = 0.;
+	for(s = s00;;s++) switch(*s) {
+		case '-':
+			sign = 1;
+			/* no break */
+		case '+':
+			if (*++s)
+				goto break2;
+			/* no break */
+		case 0:
+			goto ret0;
+		case '\t':
+		case '\n':
+		case '\v':
+		case '\f':
+		case '\r':
+		case ' ':
+			continue;
+		default:
+			goto break2;
+		}
+ break2:
+	if (*s == '0') {
+#ifndef NO_HEX_FP /*{*/
+		switch(s[1]) {
+		  case 'x':
+		  case 'X':
+#ifdef Honor_FLT_ROUNDS
+			gethex(&s, &rv, bc.rounding, sign);
+#else
+			gethex(&s, &rv, 1, sign);
+#endif
+			goto ret;
+		  }
+#endif /*}*/
+		nz0 = 1;
+		while(*++s == '0') ;
+		if (!*s)
+			goto ret;
+		}
+	s0 = s;
+	y = z = 0;
+	for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+		if (nd < 9)
+			y = 10*y + c - '0';
+		else if (nd < 16)
+			z = 10*z + c - '0';
+	nd0 = nd;
+	bc.dp0 = bc.dp1 = s - s0;
+#ifdef USE_LOCALE
+	s1 = localeconv()->decimal_point;
+	if (c == *s1) {
+		c = '.';
+		if (*++s1) {
+			s2 = s;
+			for(;;) {
+				if (*++s2 != *s1) {
+					c = 0;
+					break;
+					}
+				if (!*++s1) {
+					s = s2;
+					break;
+					}
+				}
+			}
+		}
+#endif
+	if (c == '.') {
+		c = *++s;
+		bc.dp1 = s - s0;
+		bc.dplen = bc.dp1 - bc.dp0;
+		if (!nd) {
+			for(; c == '0'; c = *++s)
+				nz++;
+			if (c > '0' && c <= '9') {
+				s0 = s;
+				nf += nz;
+				nz = 0;
+				goto have_dig;
+				}
+			goto dig_done;
+			}
+		for(; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+			nz++;
+			if (c -= '0') {
+				nf += nz;
+				for(i = 1; i < nz; i++)
+					if (nd++ < 9)
+						y *= 10;
+					else if (nd <= DBL_DIG + 1)
+						z *= 10;
+				if (nd++ < 9)
+					y = 10*y + c;
+				else if (nd <= DBL_DIG + 1)
+					z = 10*z + c;
+				nz = 0;
+				}
+			}
+		}
+ dig_done:
+	e = 0;
+	if (c == 'e' || c == 'E') {
+		if (!nd && !nz && !nz0) {
+			goto ret0;
+			}
+		s00 = s;
+		esign = 0;
+		switch(c = *++s) {
+			case '-':
+				esign = 1;
+			case '+':
+				c = *++s;
+			}
+		if (c >= '0' && c <= '9') {
+			while(c == '0')
+				c = *++s;
+			if (c > '0' && c <= '9') {
+				L = c - '0';
+				s1 = s;
+				while((c = *++s) >= '0' && c <= '9')
+					L = 10*L + c - '0';
+				if (s - s1 > 8 || L > 19999)
+					/* Avoid confusion from exponents
+					 * so large that e might overflow.
+					 */
+					e = 19999; /* safe for 16 bit ints */
+				else
+					e = (int)L;
+				if (esign)
+					e = -e;
+				}
+			else
+				e = 0;
+			}
+		else
+			s = s00;
+		}
+	if (!nd) {
+		if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+			/* Check for Nan and Infinity */
+			if (!bc.dplen)
+			 switch(c) {
+			  case 'i':
+			  case 'I':
+				if (match(&s,"nf")) {
+					--s;
+					if (!match(&s,"inity"))
+						++s;
+					word0(&rv) = 0x7ff00000;
+					word1(&rv) = 0;
+					goto ret;
+					}
+				break;
+			  case 'n':
+			  case 'N':
+				if (match(&s, "an")) {
+					word0(&rv) = NAN_WORD0;
+					word1(&rv) = NAN_WORD1;
+#ifndef No_Hex_NaN
+					if (*s == '(') /*)*/
+						hexnan(&rv, &s);
+#endif
+					goto ret;
+					}
+			  }
+#endif /* INFNAN_CHECK */
+ ret0:
+			s = s00;
+			sign = 0;
+			}
+		goto ret;
+		}
+	bc.e0 = e1 = e -= nf;
+
+	/* Now we have nd0 digits, starting at s0, followed by a
+	 * decimal point, followed by nd-nd0 digits.  The number we're
+	 * after is the integer represented by those digits times
+	 * 10**e */
+
+	if (!nd0)
+		nd0 = nd;
+	k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+	dval(&rv) = y;
+	if (k > 9) {
+#ifdef SET_INEXACT
+		if (k > DBL_DIG)
+			oldinexact = get_inexact();
+#endif
+		dval(&rv) = tens[k - 9] * dval(&rv) + z;
+		}
+	bd0 = 0;
+	if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+#ifndef Honor_FLT_ROUNDS
+		&& Flt_Rounds == 1
+#endif
+#endif
+			) {
+		if (!e)
+			goto ret;
+		if (e > 0) {
+			if (e <= Ten_pmax) {
+#ifdef VAX
+				goto vax_ovfl_check;
+#else
+#ifdef Honor_FLT_ROUNDS
+				/* round correctly FLT_ROUNDS = 2 or 3 */
+				if (sign) {
+					rv.d = -rv.d;
+					sign = 0;
+					}
+#endif
+				/* rv = */ rounded_product(dval(&rv), tens[e]);
+				goto ret;
+#endif
+				}
+			i = DBL_DIG - nd;
+			if (e <= Ten_pmax + i) {
+				/* A fancier test would sometimes let us do
+				 * this for larger i values.
+				 */
+#ifdef Honor_FLT_ROUNDS
+				/* round correctly FLT_ROUNDS = 2 or 3 */
+				if (sign) {
+					rv.d = -rv.d;
+					sign = 0;
+					}
+#endif
+				e -= i;
+				dval(&rv) *= tens[i];
+#ifdef VAX
+				/* VAX exponent range is so narrow we must
+				 * worry about overflow here...
+				 */
+ vax_ovfl_check:
+				word0(&rv) -= P*Exp_msk1;
+				/* rv = */ rounded_product(dval(&rv), tens[e]);
+				if ((word0(&rv) & Exp_mask)
+				 > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+					goto ovfl;
+				word0(&rv) += P*Exp_msk1;
+#else
+				/* rv = */ rounded_product(dval(&rv), tens[e]);
+#endif
+				goto ret;
+				}
+			}
+#ifndef Inaccurate_Divide
+		else if (e >= -Ten_pmax) {
+#ifdef Honor_FLT_ROUNDS
+			/* round correctly FLT_ROUNDS = 2 or 3 */
+			if (sign) {
+				rv.d = -rv.d;
+				sign = 0;
+				}
+#endif
+			/* rv = */ rounded_quotient(dval(&rv), tens[-e]);
+			goto ret;
+			}
+#endif
+		}
+	e1 += nd - k;
+
+#ifdef IEEE_Arith
+#ifdef SET_INEXACT
+	bc.inexact = 1;
+	if (k <= DBL_DIG)
+		oldinexact = get_inexact();
+#endif
+#ifdef Avoid_Underflow
+	bc.scale = 0;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (bc.rounding >= 2) {
+		if (sign)
+			bc.rounding = bc.rounding == 2 ? 0 : 2;
+		else
+			if (bc.rounding != 2)
+				bc.rounding = 0;
+		}
+#endif
+#endif /*IEEE_Arith*/
+
+	/* Get starting approximation = rv * 10**e1 */
+
+	if (e1 > 0) {
+		if ((i = e1 & 15))
+			dval(&rv) *= tens[i];
+		if (e1 &= ~15) {
+			if (e1 > DBL_MAX_10_EXP) {
+ ovfl:
+#ifndef NO_ERRNO
+				errno = ERANGE;
+#endif
+				/* Can't trust HUGE_VAL */
+#ifdef IEEE_Arith
+#ifdef Honor_FLT_ROUNDS
+				switch(bc.rounding) {
+				  case 0: /* toward 0 */
+				  case 3: /* toward -infinity */
+					word0(&rv) = Big0;
+					word1(&rv) = Big1;
+					break;
+				  default:
+					word0(&rv) = Exp_mask;
+					word1(&rv) = 0;
+				  }
+#else /*Honor_FLT_ROUNDS*/
+				word0(&rv) = Exp_mask;
+				word1(&rv) = 0;
+#endif /*Honor_FLT_ROUNDS*/
+#ifdef SET_INEXACT
+				/* set overflow bit */
+				dval(&rv0) = 1e300;
+				dval(&rv0) *= dval(&rv0);
+#endif
+#else /*IEEE_Arith*/
+				word0(&rv) = Big0;
+				word1(&rv) = Big1;
+#endif /*IEEE_Arith*/
+				goto ret;
+				}
+			e1 >>= 4;
+			for(j = 0; e1 > 1; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(&rv) *= bigtens[j];
+		/* The last multiplication could overflow. */
+			word0(&rv) -= P*Exp_msk1;
+			dval(&rv) *= bigtens[j];
+			if ((z = word0(&rv) & Exp_mask)
+			 > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+				goto ovfl;
+			if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+				/* set to largest number */
+				/* (Can't trust DBL_MAX) */
+				word0(&rv) = Big0;
+				word1(&rv) = Big1;
+				}
+			else
+				word0(&rv) += P*Exp_msk1;
+			}
+		}
+	else if (e1 < 0) {
+		e1 = -e1;
+		if ((i = e1 & 15))
+			dval(&rv) /= tens[i];
+		if (e1 >>= 4) {
+			if (e1 >= 1 << n_bigtens)
+				goto undfl;
+#ifdef Avoid_Underflow
+			if (e1 & Scale_Bit)
+				bc.scale = 2*P;
+			for(j = 0; e1 > 0; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(&rv) *= tinytens[j];
+			if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask)
+						>> Exp_shift)) > 0) {
+				/* scaled rv is denormal; clear j low bits */
+				if (j >= 32) {
+					word1(&rv) = 0;
+					if (j >= 53)
+					 word0(&rv) = (P+2)*Exp_msk1;
+					else
+					 word0(&rv) &= 0xffffffff << (j-32);
+					}
+				else
+					word1(&rv) &= 0xffffffff << j;
+				}
+#else
+			for(j = 0; e1 > 1; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(&rv) *= tinytens[j];
+			/* The last multiplication could underflow. */
+			dval(&rv0) = dval(&rv);
+			dval(&rv) *= tinytens[j];
+			if (!dval(&rv)) {
+				dval(&rv) = 2.*dval(&rv0);
+				dval(&rv) *= tinytens[j];
+#endif
+				if (!dval(&rv)) {
+ undfl:
+					dval(&rv) = 0.;
+#ifndef NO_ERRNO
+					errno = ERANGE;
+#endif
+					goto ret;
+					}
+#ifndef Avoid_Underflow
+				word0(&rv) = Tiny0;
+				word1(&rv) = Tiny1;
+				/* The refinement below will clean
+				 * this approximation up.
+				 */
+				}
+#endif
+			}
+		}
+
+	/* Now the hard part -- adjusting rv to the correct value.*/
+
+	/* Put digits into bd: true value = bd * 10^e */
+
+	bc.nd = nd;
+#ifndef NO_STRTOD_BIGCOMP
+	bc.nd0 = nd0;	/* Only needed if nd > strtod_diglim, but done here */
+			/* to silence an erroneous warning about bc.nd0 */
+			/* possibly not being initialized. */
+	if (nd > strtod_diglim) {
+		/* ASSERT(strtod_diglim >= 18); 18 == one more than the */
+		/* minimum number of decimal digits to distinguish double values */
+		/* in IEEE arithmetic. */
+		i = j = 18;
+		if (i > nd0)
+			j += bc.dplen;
+		for(;;) {
+			if (--j <= bc.dp1 && j >= bc.dp0)
+				j = bc.dp0 - 1;
+			if (s0[j] != '0')
+				break;
+			--i;
+			}
+		e += nd - i;
+		nd = i;
+		if (nd0 > nd)
+			nd0 = nd;
+		if (nd < 9) { /* must recompute y */
+			y = 0;
+			for(i = 0; i < nd0; ++i)
+				y = 10*y + s0[i] - '0';
+			for(j = bc.dp1; i < nd; ++i)
+				y = 10*y + s0[j++] - '0';
+			}
+		}
+#endif
+	bd0 = s2b(s0, nd0, nd, y, bc.dplen);
+
+	for(;;) {
+		bd = Balloc(bd0->k);
+		Bcopy(bd, bd0);
+		bb = d2b(&rv, &bbe, &bbbits);	/* rv = bb * 2^bbe */
+		bs = i2b(1);
+
+		if (e >= 0) {
+			bb2 = bb5 = 0;
+			bd2 = bd5 = e;
+			}
+		else {
+			bb2 = bb5 = -e;
+			bd2 = bd5 = 0;
+			}
+		if (bbe >= 0)
+			bb2 += bbe;
+		else
+			bd2 -= bbe;
+		bs2 = bb2;
+#ifdef Honor_FLT_ROUNDS
+		if (bc.rounding != 1)
+			bs2++;
+#endif
+#ifdef Avoid_Underflow
+		j = bbe - bc.scale;
+		i = j + bbbits - 1;	/* logb(rv) */
+		if (i < Emin)	/* denormal */
+			j += P - Emin;
+		else
+			j = P + 1 - bbbits;
+#else /*Avoid_Underflow*/
+#ifdef Sudden_Underflow
+#ifdef IBM
+		j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
+#else
+		j = P + 1 - bbbits;
+#endif
+#else /*Sudden_Underflow*/
+		j = bbe;
+		i = j + bbbits - 1;	/* logb(rv) */
+		if (i < Emin)	/* denormal */
+			j += P - Emin;
+		else
+			j = P + 1 - bbbits;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+		bb2 += j;
+		bd2 += j;
+#ifdef Avoid_Underflow
+		bd2 += bc.scale;
+#endif
+		i = bb2 < bd2 ? bb2 : bd2;
+		if (i > bs2)
+			i = bs2;
+		if (i > 0) {
+			bb2 -= i;
+			bd2 -= i;
+			bs2 -= i;
+			}
+		if (bb5 > 0) {
+			bs = pow5mult(bs, bb5);
+			bb1 = mult(bs, bb);
+			Bfree(bb);
+			bb = bb1;
+			}
+		if (bb2 > 0)
+			bb = lshift(bb, bb2);
+		if (bd5 > 0)
+			bd = pow5mult(bd, bd5);
+		if (bd2 > 0)
+			bd = lshift(bd, bd2);
+		if (bs2 > 0)
+			bs = lshift(bs, bs2);
+		delta = diff(bb, bd);
+		bc.dsign = delta->sign;
+		delta->sign = 0;
+		i = cmp(delta, bs);
+#ifndef NO_STRTOD_BIGCOMP
+		if (bc.nd > nd && i <= 0) {
+			if (bc.dsign)
+				break;	/* Must use bigcomp(). */
+#ifdef Honor_FLT_ROUNDS
+			if (bc.rounding != 1) {
+				if (i < 0)
+					break;
+				}
+			else
+#endif
+				{
+				bc.nd = nd;
+				i = -1;	/* Discarded digits make delta smaller. */
+				}
+			}
+#endif
+#ifdef Honor_FLT_ROUNDS
+		if (bc.rounding != 1) {
+			if (i < 0) {
+				/* Error is less than an ulp */
+				if (!delta->x[0] && delta->wds <= 1) {
+					/* exact */
+#ifdef SET_INEXACT
+					bc.inexact = 0;
+#endif
+					break;
+					}
+				if (bc.rounding) {
+					if (bc.dsign) {
+						adj.d = 1.;
+						goto apply_adj;
+						}
+					}
+				else if (!bc.dsign) {
+					adj.d = -1.;
+					if (!word1(&rv)
+					 && !(word0(&rv) & Frac_mask)) {
+						y = word0(&rv) & Exp_mask;
+#ifdef Avoid_Underflow
+						if (!bc.scale || y > 2*P*Exp_msk1)
+#else
+						if (y)
+#endif
+						  {
+						  delta = lshift(delta,Log2P);
+						  if (cmp(delta, bs) <= 0)
+							adj.d = -0.5;
+						  }
+						}
+ apply_adj:
+#ifdef Avoid_Underflow
+					if (bc.scale && (y = word0(&rv) & Exp_mask)
+						<= 2*P*Exp_msk1)
+					  word0(&adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+					if ((word0(&rv) & Exp_mask) <=
+							P*Exp_msk1) {
+						word0(&rv) += P*Exp_msk1;
+						dval(&rv) += adj.d*ulp(dval(&rv));
+						word0(&rv) -= P*Exp_msk1;
+						}
+					else
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+					dval(&rv) += adj.d*ulp(&rv);
+					}
+				break;
+				}
+			adj.d = ratio(delta, bs);
+			if (adj.d < 1.)
+				adj.d = 1.;
+			if (adj.d <= 0x7ffffffe) {
+				/* adj = rounding ? ceil(adj) : floor(adj); */
+				y = adj.d;
+				if (y != adj.d) {
+					if (!((bc.rounding>>1) ^ bc.dsign))
+						y++;
+					adj.d = y;
+					}
+				}
+#ifdef Avoid_Underflow
+			if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)
+				word0(&adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+			if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {
+				word0(&rv) += P*Exp_msk1;
+				adj.d *= ulp(dval(&rv));
+				if (bc.dsign)
+					dval(&rv) += adj.d;
+				else
+					dval(&rv) -= adj.d;
+				word0(&rv) -= P*Exp_msk1;
+				goto cont;
+				}
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+			adj.d *= ulp(&rv);
+			if (bc.dsign) {
+				if (word0(&rv) == Big0 && word1(&rv) == Big1)
+					goto ovfl;
+				dval(&rv) += adj.d;
+				}
+			else
+				dval(&rv) -= adj.d;
+			goto cont;
+			}
+#endif /*Honor_FLT_ROUNDS*/
+
+		if (i < 0) {
+			/* Error is less than half an ulp -- check for
+			 * special case of mantissa a power of two.
+			 */
+			if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask
+#ifdef IEEE_Arith
+#ifdef Avoid_Underflow
+			 || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1
+#else
+			 || (word0(&rv) & Exp_mask) <= Exp_msk1
+#endif
+#endif
+				) {
+#ifdef SET_INEXACT
+				if (!delta->x[0] && delta->wds <= 1)
+					bc.inexact = 0;
+#endif
+				break;
+				}
+			if (!delta->x[0] && delta->wds <= 1) {
+				/* exact result */
+#ifdef SET_INEXACT
+				bc.inexact = 0;
+#endif
+				break;
+				}
+			delta = lshift(delta,Log2P);
+			if (cmp(delta, bs) > 0)
+				goto drop_down;
+			break;
+			}
+		if (i == 0) {
+			/* exactly half-way between */
+			if (bc.dsign) {
+				if ((word0(&rv) & Bndry_mask1) == Bndry_mask1
+				 &&  word1(&rv) == (
+#ifdef Avoid_Underflow
+			(bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)
+		? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
+#endif
+						   0xffffffff)) {
+					/*boundary case -- increment exponent*/
+					word0(&rv) = (word0(&rv) & Exp_mask)
+						+ Exp_msk1
+#ifdef IBM
+						| Exp_msk1 >> 4
+#endif
+						;
+					word1(&rv) = 0;
+#ifdef Avoid_Underflow
+					bc.dsign = 0;
+#endif
+					break;
+					}
+				}
+			else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) {
+ drop_down:
+				/* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow /*{{*/
+				L = word0(&rv) & Exp_mask;
+#ifdef IBM
+				if (L <  Exp_msk1)
+#else
+#ifdef Avoid_Underflow
+				if (L <= (bc.scale ? (2*P+1)*Exp_msk1 : Exp_msk1))
+#else
+				if (L <= Exp_msk1)
+#endif /*Avoid_Underflow*/
+#endif /*IBM*/
+					{
+					if (bc.nd >nd) {
+						bc.uflchk = 1;
+						break;
+						}
+					goto undfl;
+					}
+				L -= Exp_msk1;
+#else /*Sudden_Underflow}{*/
+#ifdef Avoid_Underflow
+				if (bc.scale) {
+					L = word0(&rv) & Exp_mask;
+					if (L <= (2*P+1)*Exp_msk1) {
+						if (L > (P+2)*Exp_msk1)
+							/* round even ==> */
+							/* accept rv */
+							break;
+						/* rv = smallest denormal */
+						if (bc.nd >nd) {
+							bc.uflchk = 1;
+							break;
+							}
+						goto undfl;
+						}
+					}
+#endif /*Avoid_Underflow*/
+				L = (word0(&rv) & Exp_mask) - Exp_msk1;
+#endif /*Sudden_Underflow}}*/
+				word0(&rv) = L | Bndry_mask1;
+				word1(&rv) = 0xffffffff;
+#ifdef IBM
+				goto cont;
+#else
+				break;
+#endif
+				}
+#ifndef ROUND_BIASED
+			if (!(word1(&rv) & LSB))
+				break;
+#endif
+			if (bc.dsign)
+				dval(&rv) += ulp(&rv);
+#ifndef ROUND_BIASED
+			else {
+				dval(&rv) -= ulp(&rv);
+#ifndef Sudden_Underflow
+				if (!dval(&rv)) {
+					if (bc.nd >nd) {
+						bc.uflchk = 1;
+						break;
+						}
+					goto undfl;
+					}
+#endif
+				}
+#ifdef Avoid_Underflow
+			bc.dsign = 1 - bc.dsign;
+#endif
+#endif
+			break;
+			}
+		if ((aadj = ratio(delta, bs)) <= 2.) {
+			if (bc.dsign)
+				aadj = aadj1 = 1.;
+			else if (word1(&rv) || word0(&rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+				if (word1(&rv) == Tiny1 && !word0(&rv)) {
+					if (bc.nd >nd) {
+						bc.uflchk = 1;
+						break;
+						}
+					goto undfl;
+					}
+#endif
+				aadj = 1.;
+				aadj1 = -1.;
+				}
+			else {
+				/* special case -- power of FLT_RADIX to be */
+				/* rounded down... */
+
+				if (aadj < 2./FLT_RADIX)
+					aadj = 1./FLT_RADIX;
+				else
+					aadj *= 0.5;
+				aadj1 = -aadj;
+				}
+			}
+		else {
+			aadj *= 0.5;
+			aadj1 = bc.dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+			switch(bc.rounding) {
+				case 2: /* towards +infinity */
+					aadj1 -= 0.5;
+					break;
+				case 0: /* towards 0 */
+				case 3: /* towards -infinity */
+					aadj1 += 0.5;
+				}
+#else
+			if (Flt_Rounds == 0)
+				aadj1 += 0.5;
+#endif /*Check_FLT_ROUNDS*/
+			}
+		y = word0(&rv) & Exp_mask;
+
+		/* Check for overflow */
+
+		if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+			dval(&rv0) = dval(&rv);
+			word0(&rv) -= P*Exp_msk1;
+			adj.d = aadj1 * ulp(&rv);
+			dval(&rv) += adj.d;
+			if ((word0(&rv) & Exp_mask) >=
+					Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+				if (word0(&rv0) == Big0 && word1(&rv0) == Big1)
+					goto ovfl;
+				word0(&rv) = Big0;
+				word1(&rv) = Big1;
+				goto cont;
+				}
+			else
+				word0(&rv) += P*Exp_msk1;
+			}
+		else {
+#ifdef Avoid_Underflow
+			if (bc.scale && y <= 2*P*Exp_msk1) {
+				if (aadj <= 0x7fffffff) {
+					if ((z = aadj) <= 0)
+						z = 1;
+					aadj = z;
+					aadj1 = bc.dsign ? aadj : -aadj;
+					}
+				dval(&aadj2) = aadj1;
+				word0(&aadj2) += (2*P+1)*Exp_msk1 - y;
+				aadj1 = dval(&aadj2);
+				}
+			adj.d = aadj1 * ulp(&rv);
+			dval(&rv) += adj.d;
+#else
+#ifdef Sudden_Underflow
+			if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {
+				dval(&rv0) = dval(&rv);
+				word0(&rv) += P*Exp_msk1;
+				adj.d = aadj1 * ulp(&rv);
+				dval(&rv) += adj.d;
+#ifdef IBM
+				if ((word0(&rv) & Exp_mask) <  P*Exp_msk1)
+#else
+				if ((word0(&rv) & Exp_mask) <= P*Exp_msk1)
+#endif
+					{
+					if (word0(&rv0) == Tiny0
+					 && word1(&rv0) == Tiny1) {
+						if (bc.nd >nd) {
+							bc.uflchk = 1;
+							break;
+							}
+						goto undfl;
+						}
+					word0(&rv) = Tiny0;
+					word1(&rv) = Tiny1;
+					goto cont;
+					}
+				else
+					word0(&rv) -= P*Exp_msk1;
+				}
+			else {
+				adj.d = aadj1 * ulp(&rv);
+				dval(&rv) += adj.d;
+				}
+#else /*Sudden_Underflow*/
+			/* Compute adj so that the IEEE rounding rules will
+			 * correctly round rv + adj in some half-way cases.
+			 * If rv * ulp(rv) is denormalized (i.e.,
+			 * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+			 * trouble from bits lost to denormalization;
+			 * example: 1.2e-307 .
+			 */
+			if (y <= (P-1)*Exp_msk1 && aadj > 1.) {
+				aadj1 = (double)(int)(aadj + 0.5);
+				if (!bc.dsign)
+					aadj1 = -aadj1;
+				}
+			adj.d = aadj1 * ulp(&rv);
+			dval(&rv) += adj.d;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+			}
+		z = word0(&rv) & Exp_mask;
+#ifndef SET_INEXACT
+		if (bc.nd == nd) {
+#ifdef Avoid_Underflow
+		if (!bc.scale)
+#endif
+		if (y == z) {
+			/* Can we stop now? */
+			L = (Long)aadj;
+			aadj -= L;
+			/* The tolerances below are conservative. */
+			if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) {
+				if (aadj < .4999999 || aadj > .5000001)
+					break;
+				}
+			else if (aadj < .4999999/FLT_RADIX)
+				break;
+			}
+		}
+#endif
+ cont:
+		Bfree(bb);
+		Bfree(bd);
+		Bfree(bs);
+		Bfree(delta);
+		}
+	Bfree(bb);
+	Bfree(bd);
+	Bfree(bs);
+	Bfree(bd0);
+	Bfree(delta);
+#ifndef NO_STRTOD_BIGCOMP
+	if (bc.nd > nd)
+		bigcomp(&rv, s0, &bc);
+#endif
+#ifdef SET_INEXACT
+	if (bc.inexact) {
+		if (!oldinexact) {
+			word0(&rv0) = Exp_1 + (70 << Exp_shift);
+			word1(&rv0) = 0;
+			dval(&rv0) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+#ifdef Avoid_Underflow
+	if (bc.scale) {
+		word0(&rv0) = Exp_1 - 2*P*Exp_msk1;
+		word1(&rv0) = 0;
+		dval(&rv) *= dval(&rv0);
+#ifndef NO_ERRNO
+		/* try to avoid the bug of testing an 8087 register value */
+#ifdef IEEE_Arith
+		if (!(word0(&rv) & Exp_mask))
+#else
+		if (word0(&rv) == 0 && word1(&rv) == 0)
+#endif
+			errno = ERANGE;
+#endif
+		}
+#endif /* Avoid_Underflow */
+#ifdef SET_INEXACT
+	if (bc.inexact && !(word0(&rv) & Exp_mask)) {
+		/* set underflow bit */
+		dval(&rv0) = 1e-300;
+		dval(&rv0) *= dval(&rv0);
+		}
+#endif
+ ret:
+	if (se)
+		*se = (char *)s;
+	return sign ? -dval(&rv) : dval(&rv);
+	}
+
+#ifndef MULTIPLE_THREADS
+ static char *dtoa_result;
+#endif
+
+ static char *
+#ifdef KR_headers
+rv_alloc(i) int i;
+#else
+rv_alloc(int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (size_t)i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(k);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ static char *
+#ifdef KR_headers
+nrv_alloc(s, rve, n) char *s, **rve; int n;
+#else
+nrv_alloc(CONST char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(n);
+	while((*t = *s++)) t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(s) char *s;
+#else
+freedtoa(char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->maxwds = 1 << (b->k = *(int*)b);
+	Bfree(b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ char *
+dtoa
+#ifdef KR_headers
+	(dd, mode, ndigits, decpt, sign, rve)
+	double dd; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+	(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4,5 ==> similar to 2 and 3, respectively, but (in
+			round-nearest mode) with the tests of mode 0 to
+			possibly return a shorter string that rounds to d.
+			With IEEE arithmetic and compilation with
+			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+			as modes 2 and 3 when FLT_ROUNDS != 1.
+		6-9 ==> Debugging modes similar to mode - 4:  don't try
+			fast floating-point estimate (if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+		j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+		spec_case, try_quick;
+	Long L;
+#ifndef Sudden_Underflow
+	int denorm;
+	ULong x;
+#endif
+	Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S;
+	U d2, eps, u;
+	double ds;
+	char *s, *s0;
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+	int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	Rounding = Flt_Rounds;
+#else /*}{*/
+	Rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	Rounding = 0; break;
+	  case FE_UPWARD:	Rounding = 2; break;
+	  case FE_DOWNWARD:	Rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+
+	u.d = dd;
+	if (word0(&u) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(&u) &= ~Sign_bit;	/* clear sign bit */
+		}
+	else
+		*sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+	if ((word0(&u) & Exp_mask) == Exp_mask)
+#else
+	if (word0(&u)  == 0x8000)
+#endif
+		{
+		/* Infinity or NaN */
+		*decpt = 9999;
+#ifdef IEEE_Arith
+		if (!word1(&u) && !(word0(&u) & 0xfffff))
+			return nrv_alloc("Infinity", rve, 8);
+#endif
+		return nrv_alloc("NaN", rve, 3);
+		}
+#endif
+#ifdef IBM
+	dval(&u) += 0; /* normalize */
+#endif
+	if (!dval(&u)) {
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+#ifdef SET_INEXACT
+	try_quick = oldinexact = get_inexact();
+	inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (Rounding >= 2) {
+		if (*sign)
+			Rounding = Rounding == 2 ? 0 : 2;
+		else
+			if (Rounding != 2)
+				Rounding = 0;
+		}
+#endif
+
+	b = d2b(&u, &be, &bbits);
+#ifdef Sudden_Underflow
+	i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+	if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) {
+#endif
+		dval(&d2) = dval(&u);
+		word0(&d2) &= Frac_mask1;
+		word0(&d2) |= Exp_11;
+#ifdef IBM
+		if (j = 11 - hi0bits(word0(&d2) & Frac_mask))
+			dval(&d2) /= 1 << j;
+#endif
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+		 *
+		 * This suggests computing an approximation k to log10(d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifdef IBM
+		i <<= 2;
+		i += j;
+#endif
+#ifndef Sudden_Underflow
+		denorm = 0;
+		}
+	else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P-1) - 1);
+		x = i > 32  ? word0(&u) << (64 - i) | word1(&u) >> (i - 32)
+			    : word1(&u) << (32 - i);
+		dval(&d2) = x;
+		word0(&d2) -= 31*Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P-1) - 1) + 1;
+		denorm = 1;
+		}
+#endif
+	ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&u) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+	try_quick = Rounding == 1;
+#else
+	try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = 18;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+
+#ifdef Honor_FLT_ROUNDS
+	if (mode > 1 && Rounding != 1)
+		leftright = 0;
+#endif
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		dval(&d2) = dval(&u);
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&u) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			dval(&u) /= ds;
+			}
+		else if ((j1 = -k)) {
+			dval(&u) *= tens[j1 & 0xf];
+			for(j = j1 >> 4; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					dval(&u) *= bigtens[i];
+					}
+			}
+		if (k_check && dval(&u) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&u) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&u) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&u) -= 5.;
+			if (dval(&u) > dval(&eps))
+				goto one_digit;
+			if (dval(&u) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = dval(&u);
+				dval(&u) -= L;
+				*s++ = '0' + (int)L;
+				if (dval(&u) < dval(&eps))
+					goto ret1;
+				if (1. - dval(&u) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&u) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&u) *= 10.) {
+				L = (Long)(dval(&u));
+				if (!(dval(&u) -= L))
+					ilim = i;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					if (dval(&u) > 0.5 + dval(&eps))
+						goto bump_up;
+					else if (dval(&u) < 0.5 - dval(&eps)) {
+						while(*--s == '0') {}
+						s++;
+						goto ret1;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&u) = dval(&d2);
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&u) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1; i <= k + 1; i++, dval(&u) *= 10.) {
+			L = (Long)(dval(&u) / ds);
+			dval(&u) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&u) < 0) {
+				L--;
+				dval(&u) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (!dval(&u)) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				switch(Rounding) {
+				  case 0: goto ret1;
+				  case 2: goto bump_up;
+				  }
+#endif
+				dval(&u) += dval(&u);
+				if (dval(&u) > ds || (dval(&u) == ds && L & 1)) {
+ bump_up:
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i =
+#ifndef Sudden_Underflow
+			denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+			1 + P - bbits;
+#endif
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				b1 = mult(mhi, b);
+				Bfree(b);
+				b = b1;
+				}
+			if ((j = b5 - m5))
+				b = pow5mult(b, j);
+			}
+		else
+			b = pow5mult(b, b5);
+		}
+	S = i2b(1);
+	if (s5 > 0)
+		S = pow5mult(S, s5);
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+			&& Rounding == 1
+#endif
+				) {
+		if (!word1(&u) && !(word0(&u) & Bndry_mask)
+#ifndef Sudden_Underflow
+		 && word0(&u) & (Exp_mask & ~Exp_msk1)
+#endif
+				) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+#ifdef Pack_32
+	if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f))
+		i = 32 - i;
+#define iInc 28
+#else
+	if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
+		i = 16 - i;
+#define iInc 12
+#endif
+	i = dshift(S, s2);
+	b2 += i;
+	m2 += i;
+	s2 += i;
+	if (b2 > 0)
+		b = lshift(b, b2);
+	if (s2 > 0)
+		S = lshift(S, s2);
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (leftright)
+				mhi = multadd(mhi, 10, 0);
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+		if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			goto ret;
+			}
+ one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0)
+			mhi = lshift(mhi, m2);
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, Log2P);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && mode != 1 && !(word1(&u) & 1)
+#ifdef Honor_FLT_ROUNDS
+				&& Rounding >= 1
+#endif
+								   ) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+#ifdef SET_INEXACT
+				else if (!b->x[0] && b->wds <= 1)
+					inexact = 0;
+#endif
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+							&& !(word1(&u) & 1)
+#endif
+					)) {
+				if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					goto accept_dig;
+					}
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				 switch(Rounding) {
+				  case 0: goto accept_dig;
+				  case 2: goto keep_dig;
+				  }
+#endif /*Honor_FLT_ROUNDS*/
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					j1 = cmp(b, S);
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+					&& dig++ == '9')
+						goto round_9_up;
+					}
+ accept_dig:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+				if (!Rounding)
+					goto accept_dig;
+#endif
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					goto roundoff;
+					}
+				*s++ = dig + 1;
+				goto ret;
+				}
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (mlo == mhi)
+				mlo = mhi = multadd(mhi, 10, 0);
+			else {
+				mlo = multadd(mlo, 10, 0);
+				mhi = multadd(mhi, 10, 0);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				goto ret;
+				}
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			}
+
+	/* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+	switch(Rounding) {
+	  case 0: goto trimzeros;
+	  case 2: goto roundoff;
+	  }
+#endif
+	b = lshift(b, 1);
+	j = cmp(b, S);
+	if (j > 0 || (j == 0 && dig & 1)) {
+ roundoff:
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+		while(*--s == '0') {}
+		s++;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(&u) = Exp_1 + (70 << Exp_shift);
+			word1(&u) = 0;
+			dval(&u) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+	}
+
+}  // namespace dmg_fp
diff --git a/base/third_party/dmg_fp/dtoa_wrapper.cc b/base/third_party/dmg_fp/dtoa_wrapper.cc
new file mode 100644
index 0000000..c314c59
--- /dev/null
+++ b/base/third_party/dmg_fp/dtoa_wrapper.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The purpose of this file is to supply the macro definintions necessary
+// to make third_party/dmg_fp/dtoa.cc threadsafe.
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+
+// We need two locks because they're sometimes grabbed at the same time.
+// A single lock would lead to an attempted recursive grab.
+static base::LazyInstance<base::Lock>::Leaky
+    dtoa_lock_0 = LAZY_INSTANCE_INITIALIZER;
+static base::LazyInstance<base::Lock>::Leaky
+    dtoa_lock_1 = LAZY_INSTANCE_INITIALIZER;
+
+/*
+ * This define and the code below is to trigger thread-safe behavior
+ * in dtoa.cc, per this comment from the file:
+ *
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ */
+#define MULTIPLE_THREADS
+
+inline static void ACQUIRE_DTOA_LOCK(size_t n) {
+  DCHECK(n < 2);
+  base::Lock* lock = n == 0 ? dtoa_lock_0.Pointer() : dtoa_lock_1.Pointer();
+  lock->Acquire();
+}
+
+inline static void FREE_DTOA_LOCK(size_t n) {
+  DCHECK(n < 2);
+  base::Lock* lock = n == 0 ? dtoa_lock_0.Pointer() : dtoa_lock_1.Pointer();
+  lock->Release();
+}
+
+#include "base/third_party/dmg_fp/dtoa.cc"
diff --git a/base/third_party/dmg_fp/float_precision_crash.patch b/base/third_party/dmg_fp/float_precision_crash.patch
new file mode 100644
index 0000000..df64e7e
--- /dev/null
+++ b/base/third_party/dmg_fp/float_precision_crash.patch
@@ -0,0 +1,13 @@
+diff --git a/base/third_party/dmg_fp/dtoa.cc b/base/third_party/dmg_fp/dtoa.cc
+index 3f7e794..3312fa4 100644
+--- dtoa.cc
++++ dtoa.cc
+@@ -3891,7 +3891,7 @@ dtoa
+ 				goto no_digits;
+ 			goto one_digit;
+ 			}
+-		for(i = 1;; i++, dval(&u) *= 10.) {
++		for(i = 1; i <= k + 1; i++, dval(&u) *= 10.) {
+ 			L = (Long)(dval(&u) / ds);
+ 			dval(&u) -= L*ds;
+ #ifdef Check_FLT_ROUNDS
diff --git a/base/third_party/dmg_fp/g_fmt.cc b/base/third_party/dmg_fp/g_fmt.cc
new file mode 100644
index 0000000..d864eb7
--- /dev/null
+++ b/base/third_party/dmg_fp/g_fmt.cc
@@ -0,0 +1,102 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 1996 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
+ * it suffices to declare buf
+ *	char buf[32];
+ */
+
+#include "dmg_fp.h"
+
+namespace dmg_fp {
+
+ char *
+g_fmt(register char *b, double x)
+{
+	register int i, k;
+	register char *s;
+	int decpt, j, sign;
+	char *b0, *s0, *se;
+
+	b0 = b;
+#ifdef IGNORE_ZERO_SIGN
+	if (!x) {
+		*b++ = '0';
+		*b = 0;
+		goto done;
+		}
+#endif
+	s = s0 = dtoa(x, 0, 0, &decpt, &sign, &se);
+	if (sign)
+		*b++ = '-';
+	if (decpt == 9999) /* Infinity or Nan */ {
+		while((*b++ = *s++)) {}
+		goto done0;
+		}
+	if (decpt <= -4 || decpt > se - s + 5) {
+		*b++ = *s++;
+		if (*s) {
+			*b++ = '.';
+			while((*b = *s++))
+				b++;
+			}
+		*b++ = 'e';
+		/* sprintf(b, "%+.2d", decpt - 1); */
+		if (--decpt < 0) {
+			*b++ = '-';
+			decpt = -decpt;
+			}
+		else
+			*b++ = '+';
+		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10) {}
+		for(;;) {
+			i = decpt / k;
+			*b++ = i + '0';
+			if (--j <= 0)
+				break;
+			decpt -= i*k;
+			decpt *= 10;
+			}
+		*b = 0;
+		}
+	else if (decpt <= 0) {
+		*b++ = '.';
+		for(; decpt < 0; decpt++)
+			*b++ = '0';
+		while((*b++ = *s++)) {}
+		}
+	else {
+		while((*b = *s++)) {
+			b++;
+			if (--decpt == 0 && *s)
+				*b++ = '.';
+			}
+		for(; decpt > 0; decpt--)
+			*b++ = '0';
+		*b = 0;
+		}
+ done0:
+	freedtoa(s0);
+#ifdef IGNORE_ZERO_SIGN
+ done:
+#endif
+	return b0;
+	}
+
+}  // namespace dmg_fp
diff --git a/base/third_party/dmg_fp/gcc_64_bit.patch b/base/third_party/dmg_fp/gcc_64_bit.patch
new file mode 100644
index 0000000..ab943c0
--- /dev/null
+++ b/base/third_party/dmg_fp/gcc_64_bit.patch
@@ -0,0 +1,25 @@
+Index: dtoa.cc
+--- dtoa.cc    (old copy)
++++ dtoa.cc    (working copy)
+@@ -183,8 +183,12 @@
+ #define NO_HEX_FP
+ 
+ #ifndef Long
++#if __LP64__
++#define Long int
++#else
+ #define Long long
+ #endif
++#endif
+ #ifndef ULong
+ typedef unsigned Long ULong;
+ #endif
+@@ -221,7 +225,7 @@ extern void *MALLOC(size_t);
+ #ifndef PRIVATE_MEM
+ #define PRIVATE_MEM 2304
+ #endif
+-#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
++#define PRIVATE_mem ((unsigned)((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)))
+ static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+ #endif
+ 
diff --git a/base/third_party/dmg_fp/gcc_warnings.patch b/base/third_party/dmg_fp/gcc_warnings.patch
new file mode 100644
index 0000000..4262237
--- /dev/null
+++ b/base/third_party/dmg_fp/gcc_warnings.patch
@@ -0,0 +1,126 @@
+Index: dtoa.cc
+--- dtoa.cc    (old copy)
++++ dtoa.cc    (working copy)
+@@ -179,6 +179,9 @@
+  *	used for input more than STRTOD_DIGLIM digits long (default 40).
+  */
+ 
++#define IEEE_8087
++#define NO_HEX_FP
++
+ #ifndef Long
+ #define Long long
+ #endif
+@@ -280,9 +283,7 @@
+ #include "math.h"
+ #endif
+ 
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
++namespace dmg_fp {
+ 
+ #ifndef CONST
+ #ifdef KR_headers
+@@ -511,11 +512,9 @@
+ 
+ #define Kmax 7
+ 
+-#ifdef __cplusplus
+-extern "C" double strtod(const char *s00, char **se);
+-extern "C" char *dtoa(double d, int mode, int ndigits,
++double strtod(const char *s00, char **se);
++char *dtoa(double d, int mode, int ndigits,
+ 			int *decpt, int *sign, char **rve);
+-#endif
+ 
+  struct
+ Bigint {
+@@ -1527,7 +1526,7 @@
+ #ifdef KR_headers
+ 	(sp, t) char **sp, *t;
+ #else
+-	(CONST char **sp, char *t)
++	(CONST char **sp, CONST char *t)
+ #endif
+ {
+ 	int c, d;
+@@ -2234,7 +2234,7 @@ bigcomp
+ 	nd = bc->nd;
+ 	nd0 = bc->nd0;
+ 	p5 = nd + bc->e0 - 1;
+-	speccase = 0;
++	dd = speccase = 0;
+ #ifndef Sudden_Underflow
+ 	if (rv->d == 0.) {	/* special case: value near underflow-to-zero */
+ 				/* threshold was rounded to zero */
+@@ -3431,7 +3430,7 @@
+ 
+ 	j = sizeof(ULong);
+ 	for(k = 0;
+-		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
++		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (size_t)i;
+ 		j <<= 1)
+ 			k++;
+ 	r = (int*)Balloc(k);
+@@ -3447,7 +3446,7 @@
+ #ifdef KR_headers
+ nrv_alloc(s, rve, n) char *s, **rve; int n;
+ #else
+-nrv_alloc(char *s, char **rve, int n)
++nrv_alloc(CONST char *s, char **rve, int n)
+ #endif
+ {
+ 	char *rv, *t;
+@@ -4202,6 +4201,5 @@
+ 		*rve = s;
+ 	return s0;
+ 	}
+-#ifdef __cplusplus
+-}
+-#endif
++
++}  // namespace dmg_fp
+Index: g_fmt.cc
+--- g_fmt.cc   (old copy)
++++ g_fmt.cc   (new copy)
+@@ -46,14 +46,14 @@ g_fmt(register char *b, double x)
+ 	if (sign)
+ 		*b++ = '-';
+ 	if (decpt == 9999) /* Infinity or Nan */ {
+-		while(*b++ = *s++);
++		while((*b++ = *s++));
+ 		goto done0;
+ 		}
+ 	if (decpt <= -4 || decpt > se - s + 5) {
+ 		*b++ = *s++;
+ 		if (*s) {
+ 			*b++ = '.';
+-			while(*b = *s++)
++			while((*b = *s++))
+ 				b++;
+ 			}
+ 		*b++ = 'e';
+@@ -79,10 +79,10 @@ g_fmt(register char *b, double x)
+ 		*b++ = '.';
+ 		for(; decpt < 0; decpt++)
+ 			*b++ = '0';
+-		while(*b++ = *s++);
++		while((*b++ = *s++));
+ 		}
+ 	else {
+-		while(*b = *s++) {
++		while((*b = *s++)) {
+ 			b++;
+ 			if (--decpt == 0 && *s)
+ 				*b++ = '.';
+@@ -93,7 +93,9 @@ g_fmt(register char *b, double x)
+ 		}
+  done0:
+ 	freedtoa(s0);
++#ifdef IGNORE_ZERO_SIGN
+  done:
++#endif
+ 	return b0;
+ 	}
+ 
diff --git a/base/third_party/dmg_fp/mac_wextra.patch b/base/third_party/dmg_fp/mac_wextra.patch
new file mode 100644
index 0000000..15340f2
--- /dev/null
+++ b/base/third_party/dmg_fp/mac_wextra.patch
@@ -0,0 +1,53 @@
+Index: g_fmt.cc
+===================================================================
+--- g_fmt.cc	(revision 49784)
++++ g_fmt.cc	(working copy)
+@@ -46,7 +46,7 @@
+ 	if (sign)
+ 		*b++ = '-';
+ 	if (decpt == 9999) /* Infinity or Nan */ {
+-		while((*b++ = *s++));
++		while((*b++ = *s++)) {}
+ 		goto done0;
+ 		}
+ 	if (decpt <= -4 || decpt > se - s + 5) {
+@@ -64,7 +64,7 @@
+ 			}
+ 		else
+ 			*b++ = '+';
+-		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
++		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10) {}
+ 		for(;;) {
+ 			i = decpt / k;
+ 			*b++ = i + '0';
+@@ -79,7 +79,7 @@
+ 		*b++ = '.';
+ 		for(; decpt < 0; decpt++)
+ 			*b++ = '0';
+-		while((*b++ = *s++));
++		while((*b++ = *s++)) {}
+ 		}
+ 	else {
+ 		while((*b = *s++)) {
+Index: dtoa.cc
+===================================================================
+--- dtoa.cc	(revision 49784)
++++ dtoa.cc	(working copy)
+@@ -3863,7 +3863,7 @@
+ 					if (dval(&u) > 0.5 + dval(&eps))
+ 						goto bump_up;
+ 					else if (dval(&u) < 0.5 - dval(&eps)) {
+-						while(*--s == '0');
++						while(*--s == '0') {}
+ 						s++;
+ 						goto ret1;
+ 						}
+@@ -4176,7 +4176,7 @@
+ #ifdef Honor_FLT_ROUNDS
+  trimzeros:
+ #endif
+-		while(*--s == '0');
++		while(*--s == '0') {}
+ 		s++;
+ 		}
+  ret:
diff --git a/base/third_party/dmg_fp/win_vs2012.patch b/base/third_party/dmg_fp/win_vs2012.patch
new file mode 100644
index 0000000..f3f599c
--- /dev/null
+++ b/base/third_party/dmg_fp/win_vs2012.patch
@@ -0,0 +1,13 @@
+Index: dtoa.cc
+===================================================================
+--- dtoa.cc	(revision 161424)
++++ dtoa.cc	(working copy)
+@@ -3569,7 +3569,7 @@
+ 	int denorm;
+ 	ULong x;
+ #endif
+-	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
++	Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S;
+ 	U d2, eps, u;
+ 	double ds;
+ 	char *s, *s0;
diff --git a/base/third_party/dynamic_annotations/LICENSE b/base/third_party/dynamic_annotations/LICENSE
new file mode 100644
index 0000000..5c581a9
--- /dev/null
+++ b/base/third_party/dynamic_annotations/LICENSE
@@ -0,0 +1,28 @@
+/* Copyright (c) 2008-2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ---
+ * Author: Kostya Serebryany
+ */
diff --git a/base/third_party/dynamic_annotations/README.chromium b/base/third_party/dynamic_annotations/README.chromium
new file mode 100644
index 0000000..dc8bdef
--- /dev/null
+++ b/base/third_party/dynamic_annotations/README.chromium
@@ -0,0 +1,13 @@
+Name: dynamic annotations
+URL: http://code.google.com/p/data-race-test/wiki/DynamicAnnotations
+Version: 4384
+License: BSD
+
+One header and one source file (dynamic_annotations.h and dynamic_annotations.c)
+in this directory define runtime macros useful for annotating synchronization
+utilities and benign data races so data race detectors can handle Chromium code
+with better precision.
+
+These files were taken from
+http://code.google.com/p/data-race-test/source/browse/?#svn/trunk/dynamic_annotations
+The files are covered under BSD license as described within the files.
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.c b/base/third_party/dynamic_annotations/dynamic_annotations.c
new file mode 100644
index 0000000..f57cb12
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.c
@@ -0,0 +1,269 @@
+/* Copyright (c) 2011, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef _MSC_VER
+# include <windows.h>
+#endif
+
+#ifdef __cplusplus
+# error "This file should be built as pure C to avoid name mangling"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+
+#ifdef __GNUC__
+/* valgrind.h uses gcc extensions so it won't build with other compilers */
+# include "base/third_party/valgrind/valgrind.h"
+#endif
+
+/* Compiler-based ThreadSanitizer defines
+   DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
+   and provides its own definitions of the functions. */
+
+#ifndef DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
+# define DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0
+#endif
+
+/* Each function is empty and called (via a macro) only in debug mode.
+   The arguments are captured by dynamic tools at runtime. */
+
+#if DYNAMIC_ANNOTATIONS_ENABLED == 1 \
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0
+
+/* Identical code folding(-Wl,--icf=all) countermeasures.
+   This makes all Annotate* functions different, which prevents the linker from
+   folding them. */
+#ifdef __COUNTER__
+#define DYNAMIC_ANNOTATIONS_IMPL \
+  volatile short lineno = (__LINE__ << 8) + __COUNTER__; (void)lineno;
+#else
+#define DYNAMIC_ANNOTATIONS_IMPL \
+  volatile short lineno = (__LINE__ << 8); (void)lineno;
+#endif
+
+/* WARNING: always add new annotations to the end of the list.
+   Otherwise, lineno (see above) numbers for different Annotate* functions may
+   conflict. */
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+    const char *file, int line, const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+    const char *file, int line, const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+    const char *file, int line, const volatile void *lock, long is_w)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+    const char *file, int line, const volatile void *lock, long is_w)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+    const char *file, int line, const volatile void *barrier, long count,
+    long reinitialization_allowed)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+    const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+    const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+    const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+    const char *file, int line, const volatile void *cv,
+    const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+    const char *file, int line, const volatile void *cv)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+    const char *file, int line, const volatile void *cv)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(
+    const char *file, int line, const volatile void *obj)
+{DYNAMIC_ANNOTATIONS_IMPL};
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(
+    const char *file, int line, const volatile void *obj)
+{DYNAMIC_ANNOTATIONS_IMPL};
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+    const char *file, int line, const volatile void *address, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+    const char *file, int line, const volatile void *address, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+    const char *file, int line, const volatile void *mem, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+    const char *file, int line, const volatile void *mem, long size,
+    const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+    const char *file, int line, const volatile void *mu)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+    const char *file, int line, const volatile void *mu)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+    const char *file, int line, const volatile void *arg)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+    const char *file, int line, const char *name)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+    const char *file, int line, int enable)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+    const char *file, int line, const volatile void *arg)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+#endif  /* DYNAMIC_ANNOTATIONS_ENABLED == 1
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
+
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 \
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0
+static int GetRunningOnValgrind(void) {
+#ifdef RUNNING_ON_VALGRIND
+  if (RUNNING_ON_VALGRIND) return 1;
+#endif
+
+#ifndef _MSC_VER
+  char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
+  if (running_on_valgrind_str) {
+    return strcmp(running_on_valgrind_str, "0") != 0;
+  }
+#else
+  /* Visual Studio issues warnings if we use getenv,
+   * so we use GetEnvironmentVariableA instead.
+   */
+  char value[100] = "1";
+  int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND",
+                                    value, sizeof(value));
+  /* value will remain "1" if res == 0 or res >= sizeof(value). The latter
+   * can happen only if the given value is long, in this case it can't be "0".
+   */
+  if (res > 0 && strcmp(value, "0") != 0)
+    return 1;
+#endif
+  return 0;
+}
+
+/* See the comments in dynamic_annotations.h */
+int RunningOnValgrind(void) {
+  static volatile int running_on_valgrind = -1;
+  /* C doesn't have thread-safe initialization of statics, and we
+     don't want to depend on pthread_once here, so hack it. */
+  int local_running_on_valgrind = running_on_valgrind;
+  if (local_running_on_valgrind == -1)
+    running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind();
+  return local_running_on_valgrind;
+}
+
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.gyp b/base/third_party/dynamic_annotations/dynamic_annotations.gyp
new file mode 100644
index 0000000..1f1dc49
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.gyp
@@ -0,0 +1,47 @@
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'dynamic_annotations',
+      'type': 'static_library',
+      'toolsets': ['host', 'target'],
+      'include_dirs': [
+        '../../../',
+      ],
+      'sources': [
+        'dynamic_annotations.c',
+        'dynamic_annotations.h',
+        '../valgrind/valgrind.h',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS == "win"', {
+      'targets': [
+        {
+          'target_name': 'dynamic_annotations_win64',
+          'type': 'static_library',
+          # We can't use dynamic_annotations target for win64 build since it is
+          # a 32-bit library.
+          # TODO(gregoryd): merge with dynamic_annotations when
+          # the win32/64 targets are merged.
+          'include_dirs': [
+              '../../../',
+          ],
+          'sources': [
+            'dynamic_annotations.c',
+            'dynamic_annotations.h',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.h b/base/third_party/dynamic_annotations/dynamic_annotations.h
new file mode 100644
index 0000000..8d7f052
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.h
@@ -0,0 +1,595 @@
+/* Copyright (c) 2011, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This file defines dynamic annotations for use with dynamic analysis
+   tool such as valgrind, PIN, etc.
+
+   Dynamic annotation is a source code annotation that affects
+   the generated code (that is, the annotation is not a comment).
+   Each such annotation is attached to a particular
+   instruction and/or to a particular object (address) in the program.
+
+   The annotations that should be used by users are macros in all upper-case
+   (e.g., ANNOTATE_NEW_MEMORY).
+
+   Actual implementation of these macros may differ depending on the
+   dynamic analysis tool being used.
+
+   See http://code.google.com/p/data-race-test/  for more information.
+
+   This file supports the following dynamic analysis tools:
+   - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero).
+      Macros are defined empty.
+   - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1).
+      Macros are defined as calls to non-inlinable empty functions
+      that are intercepted by Valgrind. */
+
+#ifndef __DYNAMIC_ANNOTATIONS_H__
+#define __DYNAMIC_ANNOTATIONS_H__
+
+#ifndef DYNAMIC_ANNOTATIONS_PREFIX
+# define DYNAMIC_ANNOTATIONS_PREFIX
+#endif
+
+#ifndef DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND
+# define DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND 1
+#endif
+
+#ifdef DYNAMIC_ANNOTATIONS_WANT_ATTRIBUTE_WEAK
+# ifdef __GNUC__
+#  define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK __attribute__((weak))
+# else
+/* TODO(glider): for Windows support we may want to change this macro in order
+   to prepend __declspec(selectany) to the annotations' declarations. */
+#  error weak annotations are not supported for your compiler
+# endif
+#else
+# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK
+#endif
+
+/* The following preprocessor magic prepends the value of
+   DYNAMIC_ANNOTATIONS_PREFIX to annotation function names. */
+#define DYNAMIC_ANNOTATIONS_GLUE0(A, B) A##B
+#define DYNAMIC_ANNOTATIONS_GLUE(A, B) DYNAMIC_ANNOTATIONS_GLUE0(A, B)
+#define DYNAMIC_ANNOTATIONS_NAME(name) \
+  DYNAMIC_ANNOTATIONS_GLUE(DYNAMIC_ANNOTATIONS_PREFIX, name)
+
+#ifndef DYNAMIC_ANNOTATIONS_ENABLED
+# define DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0
+
+  /* -------------------------------------------------------------
+     Annotations useful when implementing condition variables such as CondVar,
+     using conditional critical sections (Await/LockWhen) and when constructing
+     user-defined synchronization mechanisms.
+
+     The annotations ANNOTATE_HAPPENS_BEFORE() and ANNOTATE_HAPPENS_AFTER() can
+     be used to define happens-before arcs in user-defined synchronization
+     mechanisms:  the race detector will infer an arc from the former to the
+     latter when they share the same argument pointer.
+
+     Example 1 (reference counting):
+
+     void Unref() {
+       ANNOTATE_HAPPENS_BEFORE(&refcount_);
+       if (AtomicDecrementByOne(&refcount_) == 0) {
+         ANNOTATE_HAPPENS_AFTER(&refcount_);
+         delete this;
+       }
+     }
+
+     Example 2 (message queue):
+
+     void MyQueue::Put(Type *e) {
+       MutexLock lock(&mu_);
+       ANNOTATE_HAPPENS_BEFORE(e);
+       PutElementIntoMyQueue(e);
+     }
+
+     Type *MyQueue::Get() {
+       MutexLock lock(&mu_);
+       Type *e = GetElementFromMyQueue();
+       ANNOTATE_HAPPENS_AFTER(e);
+       return e;
+     }
+
+     Note: when possible, please use the existing reference counting and message
+     queue implementations instead of inventing new ones. */
+
+  /* Report that wait on the condition variable at address "cv" has succeeded
+     and the lock at address "lock" is held. */
+  #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, lock)
+
+  /* Report that wait on the condition variable at "cv" has succeeded.  Variant
+     w/o lock. */
+  #define ANNOTATE_CONDVAR_WAIT(cv) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, NULL)
+
+  /* Report that we are about to signal on the condition variable at address
+     "cv". */
+  #define ANNOTATE_CONDVAR_SIGNAL(cv) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(__FILE__, __LINE__, cv)
+
+  /* Report that we are about to signal_all on the condition variable at address
+     "cv". */
+  #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(__FILE__, __LINE__, cv)
+
+  /* Annotations for user-defined synchronization mechanisms. */
+  #define ANNOTATE_HAPPENS_BEFORE(obj) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(__FILE__, __LINE__, obj)
+  #define ANNOTATE_HAPPENS_AFTER(obj) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(__FILE__, __LINE__, obj)
+
+  /* DEPRECATED. Don't use it. */
+  #define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(__FILE__, __LINE__, \
+        pointer, size)
+
+  /* DEPRECATED. Don't use it. */
+  #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(__FILE__, __LINE__, \
+        pointer, size)
+
+  /* DEPRECATED. Don't use it. */
+  #define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size)   \
+    do {                                              \
+      ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size); \
+      ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size);   \
+    } while (0)
+
+  /* Instruct the tool to create a happens-before arc between mu->Unlock() and
+     mu->Lock(). This annotation may slow down the race detector and hide real
+     races. Normally it is used only when it would be difficult to annotate each
+     of the mutex's critical sections individually using the annotations above.
+     This annotation makes sense only for hybrid race detectors. For pure
+     happens-before detectors this is a no-op. For more details see
+     http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */
+  #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+        mu)
+
+  /* Opposite to ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX.
+     Instruct the tool to NOT create h-b arcs between Unlock and Lock, even in
+     pure happens-before mode. For a hybrid mode this is a no-op. */
+  #define ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX(mu) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(__FILE__, __LINE__, mu)
+
+  /* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */
+  #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+        mu)
+
+  /* -------------------------------------------------------------
+     Annotations useful when defining memory allocators, or when memory that
+     was protected in one way starts to be protected in another. */
+
+  /* Report that a new memory at "address" of size "size" has been allocated.
+     This might be used when the memory has been retrieved from a free list and
+     is about to be reused, or when a the locking discipline for a variable
+     changes. */
+  #define ANNOTATE_NEW_MEMORY(address, size) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(__FILE__, __LINE__, address, \
+        size)
+
+  /* -------------------------------------------------------------
+     Annotations useful when defining FIFO queues that transfer data between
+     threads. */
+
+  /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at
+     address "pcq" has been created.  The ANNOTATE_PCQ_* annotations
+     should be used only for FIFO queues.  For non-FIFO queues use
+     ANNOTATE_HAPPENS_BEFORE (for put) and ANNOTATE_HAPPENS_AFTER (for get). */
+  #define ANNOTATE_PCQ_CREATE(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(__FILE__, __LINE__, pcq)
+
+  /* Report that the queue at address "pcq" is about to be destroyed. */
+  #define ANNOTATE_PCQ_DESTROY(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(__FILE__, __LINE__, pcq)
+
+  /* Report that we are about to put an element into a FIFO queue at address
+     "pcq". */
+  #define ANNOTATE_PCQ_PUT(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(__FILE__, __LINE__, pcq)
+
+  /* Report that we've just got an element from a FIFO queue at address
+     "pcq". */
+  #define ANNOTATE_PCQ_GET(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(__FILE__, __LINE__, pcq)
+
+  /* -------------------------------------------------------------
+     Annotations that suppress errors.  It is usually better to express the
+     program's synchronization using the other annotations, but these can
+     be used when all else fails. */
+
+  /* Report that we may have a benign race at "pointer", with size
+     "sizeof(*(pointer))". "pointer" must be a non-void* pointer.  Insert at the
+     point where "pointer" has been allocated, preferably close to the point
+     where the race happens.  See also ANNOTATE_BENIGN_RACE_STATIC. */
+  #define ANNOTATE_BENIGN_RACE(pointer, description) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+        pointer, sizeof(*(pointer)), description)
+
+  /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to
+     the memory range [address, address+size). */
+  #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+        address, size, description)
+
+  /* Request the analysis tool to ignore all reads in the current thread
+     until ANNOTATE_IGNORE_READS_END is called.
+     Useful to ignore intentional racey reads, while still checking
+     other reads and all writes.
+     See also ANNOTATE_UNPROTECTED_READ. */
+  #define ANNOTATE_IGNORE_READS_BEGIN() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+
+  /* Stop ignoring reads. */
+  #define ANNOTATE_IGNORE_READS_END() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+
+  /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */
+  #define ANNOTATE_IGNORE_WRITES_BEGIN() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+  /* Stop ignoring writes. */
+  #define ANNOTATE_IGNORE_WRITES_END() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+  /* Start ignoring all memory accesses (reads and writes). */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+    do {\
+      ANNOTATE_IGNORE_READS_BEGIN();\
+      ANNOTATE_IGNORE_WRITES_BEGIN();\
+    }while(0)\
+
+  /* Stop ignoring all memory accesses. */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+    do {\
+      ANNOTATE_IGNORE_WRITES_END();\
+      ANNOTATE_IGNORE_READS_END();\
+    }while(0)\
+
+  /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events:
+     RWLOCK* and CONDVAR*. */
+  #define ANNOTATE_IGNORE_SYNC_BEGIN() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(__FILE__, __LINE__)
+
+  /* Stop ignoring sync events. */
+  #define ANNOTATE_IGNORE_SYNC_END() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(__FILE__, __LINE__)
+
+
+  /* Enable (enable!=0) or disable (enable==0) race detection for all threads.
+     This annotation could be useful if you want to skip expensive race analysis
+     during some period of program execution, e.g. during initialization. */
+  #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(__FILE__, __LINE__, \
+        enable)
+
+  /* -------------------------------------------------------------
+     Annotations useful for debugging. */
+
+  /* Request to trace every access to "address". */
+  #define ANNOTATE_TRACE_MEMORY(address) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(__FILE__, __LINE__, address)
+
+  /* Report the current thread name to a race detector. */
+  #define ANNOTATE_THREAD_NAME(name) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(__FILE__, __LINE__, name)
+
+  /* -------------------------------------------------------------
+     Annotations useful when implementing locks.  They are not
+     normally needed by modules that merely use locks.
+     The "lock" argument is a pointer to the lock object. */
+
+  /* Report that a lock has been created at address "lock". */
+  #define ANNOTATE_RWLOCK_CREATE(lock) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+  /* Report that the lock at address "lock" is about to be destroyed. */
+  #define ANNOTATE_RWLOCK_DESTROY(lock) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
+
+  /* Report that the lock at address "lock" has been acquired.
+     is_w=1 for writer lock, is_w=0 for reader lock. */
+  #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(__FILE__, __LINE__, lock, \
+        is_w)
+
+  /* Report that the lock at address "lock" is about to be released. */
+  #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(__FILE__, __LINE__, lock, \
+        is_w)
+
+  /* -------------------------------------------------------------
+     Annotations useful when implementing barriers.  They are not
+     normally needed by modules that merely use barriers.
+     The "barrier" argument is a pointer to the barrier object. */
+
+  /* Report that the "barrier" has been initialized with initial "count".
+   If 'reinitialization_allowed' is true, initialization is allowed to happen
+   multiple times w/o calling barrier_destroy() */
+  #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(__FILE__, __LINE__, barrier, \
+        count, reinitialization_allowed)
+
+  /* Report that we are about to enter barrier_wait("barrier"). */
+  #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(__FILE__, __LINE__, \
+        barrier)
+
+  /* Report that we just exited barrier_wait("barrier"). */
+  #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(__FILE__, __LINE__, \
+        barrier)
+
+  /* Report that the "barrier" has been destroyed. */
+  #define ANNOTATE_BARRIER_DESTROY(barrier) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(__FILE__, __LINE__, \
+        barrier)
+
+  /* -------------------------------------------------------------
+     Annotations useful for testing race detectors. */
+
+  /* Report that we expect a race on the variable at "address".
+     Use only in unit tests for a race detector. */
+  #define ANNOTATE_EXPECT_RACE(address, description) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(__FILE__, __LINE__, address, \
+        description)
+
+  #define ANNOTATE_FLUSH_EXPECTED_RACES() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(__FILE__, __LINE__)
+
+  /* A no-op. Insert where you like to test the interceptors. */
+  #define ANNOTATE_NO_OP(arg) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(__FILE__, __LINE__, arg)
+
+  /* Force the race detector to flush its state. The actual effect depends on
+   * the implementation of the detector. */
+  #define ANNOTATE_FLUSH_STATE() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(__FILE__, __LINE__)
+
+
+#else  /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+  #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */
+  #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
+  #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
+  #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
+  #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */
+  #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */
+  #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */
+  #define ANNOTATE_BARRIER_DESTROY(barrier) /* empty */
+  #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */
+  #define ANNOTATE_CONDVAR_WAIT(cv) /* empty */
+  #define ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */
+  #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */
+  #define ANNOTATE_HAPPENS_BEFORE(obj) /* empty */
+  #define ANNOTATE_HAPPENS_AFTER(obj) /* empty */
+  #define ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */
+  #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size)  /* empty */
+  #define ANNOTATE_SWAP_MEMORY_RANGE(address, size)  /* empty */
+  #define ANNOTATE_PCQ_CREATE(pcq) /* empty */
+  #define ANNOTATE_PCQ_DESTROY(pcq) /* empty */
+  #define ANNOTATE_PCQ_PUT(pcq) /* empty */
+  #define ANNOTATE_PCQ_GET(pcq) /* empty */
+  #define ANNOTATE_NEW_MEMORY(address, size) /* empty */
+  #define ANNOTATE_EXPECT_RACE(address, description) /* empty */
+  #define ANNOTATE_FLUSH_EXPECTED_RACES(address, description) /* empty */
+  #define ANNOTATE_BENIGN_RACE(address, description) /* empty */
+  #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
+  #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */
+  #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */
+  #define ANNOTATE_TRACE_MEMORY(arg) /* empty */
+  #define ANNOTATE_THREAD_NAME(name) /* empty */
+  #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_READS_END() /* empty */
+  #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_WRITES_END() /* empty */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */
+  #define ANNOTATE_IGNORE_SYNC_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_SYNC_END() /* empty */
+  #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
+  #define ANNOTATE_NO_OP(arg) /* empty */
+  #define ANNOTATE_FLUSH_STATE() /* empty */
+
+#endif  /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+/* Use the macros above rather than using these functions directly. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+    const char *file, int line,
+    const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+    const char *file, int line,
+    const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+    const char *file, int line,
+    const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+    const char *file, int line,
+    const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+    const char *file, int line, const volatile void *barrier, long count,
+    long reinitialization_allowed) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+    const char *file, int line,
+    const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+    const char *file, int line,
+    const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+    const char *file, int line,
+    const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+    const char *file, int line, const volatile void *cv,
+    const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+    const char *file, int line,
+    const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+    const char *file, int line,
+    const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(
+    const char *file, int line,
+    const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(
+    const char *file, int line,
+    const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+    const char *file, int line,
+    const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+    const char *file, int line,
+    const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+    const char *file, int line,
+    const volatile void *mem, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+    const char *file, int line, const volatile void *mem, long size,
+    const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+    const char *file, int line,
+    const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+    const char *file, int line,
+    const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+    const char *file, int line,
+    const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+    const char *file, int line,
+    const char *name) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+    const char *file, int line, int enable) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+    const char *file, int line,
+    const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
+/* Return non-zero value if running under valgrind.
+
+  If "valgrind.h" is included into dynamic_annotations.c,
+  the regular valgrind mechanism will be used.
+  See http://valgrind.org/docs/manual/manual-core-adv.html about
+  RUNNING_ON_VALGRIND and other valgrind "client requests".
+  The file "valgrind.h" may be obtained by doing
+     svn co svn://svn.valgrind.org/valgrind/trunk/include
+
+  If for some reason you can't use "valgrind.h" or want to fake valgrind,
+  there are two ways to make this function return non-zero:
+    - Use environment variable: export RUNNING_ON_VALGRIND=1
+    - Make your tool intercept the function RunningOnValgrind() and
+      change its return value.
+ */
+int RunningOnValgrind(void) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
+
+  /* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+
+     Instead of doing
+        ANNOTATE_IGNORE_READS_BEGIN();
+        ... = x;
+        ANNOTATE_IGNORE_READS_END();
+     one can use
+        ... = ANNOTATE_UNPROTECTED_READ(x); */
+  template <class T>
+  inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) {
+    ANNOTATE_IGNORE_READS_BEGIN();
+    T res = x;
+    ANNOTATE_IGNORE_READS_END();
+    return res;
+  }
+  /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
+  #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)        \
+    namespace {                                                       \
+      class static_var ## _annotator {                                \
+       public:                                                        \
+        static_var ## _annotator() {                                  \
+          ANNOTATE_BENIGN_RACE_SIZED(&static_var,                     \
+                                      sizeof(static_var),             \
+            # static_var ": " description);                           \
+        }                                                             \
+      };                                                              \
+      static static_var ## _annotator the ## static_var ## _annotator;\
+    }
+#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+  #define ANNOTATE_UNPROTECTED_READ(x) (x)
+  #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)  /* empty */
+
+#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+#endif  /* __DYNAMIC_ANNOTATIONS_H__ */
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.target.mk b/base/third_party/dynamic_annotations/dynamic_annotations.target.mk
new file mode 100644
index 0000000..0738204
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.target.mk
@@ -0,0 +1,148 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := base_third_party_dynamic_annotations_dynamic_annotations_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	base/third_party/dynamic_annotations/dynamic_annotations.c
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS := \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-mthumb \
+	-march=armv7-a \
+	-mtune=cortex-a8 \
+	-mfloat-abi=softfp \
+	-mfpu=vfpv3-d16 \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-mthumb-interwork \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-Wno-error=extra \
+	-Wno-error=ignored-qualifiers \
+	-Wno-error=type-limits \
+	-Wno-error=non-virtual-dtor \
+	-Wno-error=sign-promo \
+	-Wno-error=address \
+	-Wno-error=format-security \
+	-Wno-error=non-virtual-dtor \
+	-Wno-error=return-type \
+	-Wno-error=sequence-point \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_CFLAGS_C :=
+
+MY_DEFS := \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_PEPPER_THREADING' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DUSE_SKIA=1' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_SYMBOLS_ID=""' \
+	'-DANDROID_UPSTREAM_BRINGUP=1' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH) \
+	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
+	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wno-deprecated \
+	-Wno-abi \
+	-Wno-error=c++0x-compat
+
+### Rules for final target.
+
+LOCAL_LDFLAGS := \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections
+
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: base_third_party_dynamic_annotations_dynamic_annotations_gyp
+
+# Alias gyp target name.
+.PHONY: dynamic_annotations
+dynamic_annotations: base_third_party_dynamic_annotations_dynamic_annotations_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/base/third_party/icu/LICENSE b/base/third_party/icu/LICENSE
new file mode 100644
index 0000000..40282f4
--- /dev/null
+++ b/base/third_party/icu/LICENSE
@@ -0,0 +1,32 @@
+ICU License - ICU 1.8.1 and later
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1995-2009 International Business Machines Corporation and others
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above
+copyright notice(s) and this permission notice appear in all copies of
+the Software and that both the above copyright notice(s) and this
+permission notice appear in supporting documentation.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
+SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in this Software without prior written authorization
+of the copyright holder.
diff --git a/base/third_party/icu/README.chromium b/base/third_party/icu/README.chromium
new file mode 100644
index 0000000..6a9a15a
--- /dev/null
+++ b/base/third_party/icu/README.chromium
@@ -0,0 +1,16 @@
+Name: ICU
+URL: http://site.icu-project.org/
+License: MIT
+License File: NOT_SHIPPED
+
+This file has the relevant components from ICU copied to handle basic
+UTF8/16/32 conversions. Components are copied from utf.h utf8.h utf16.h and
+utf_impl.c
+
+The same module appears in third_party/icu, so we don't repeat the license
+file here.
+
+The main change is that U_/U8_/U16_ prefixes have been replaced with
+CBU_/CBU8_/CBU16_ (for "Chrome Base") to avoid confusion with the "real" ICU
+macros should ICU be in use on the system. For the same reason, the functions
+and types have been put in the "base_icu" namespace.
diff --git a/base/third_party/icu/icu_utf.cc b/base/third_party/icu/icu_utf.cc
new file mode 100644
index 0000000..b47c8ac
--- /dev/null
+++ b/base/third_party/icu/icu_utf.cc
@@ -0,0 +1,228 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  utf_impl.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep13
+*   created by: Markus W. Scherer
+*
+*   This file provides implementation functions for macros in the utfXX.h
+*   that would otherwise be too long as macros.
+*/
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base_icu {
+
+/**
+ * UTF8_ERROR_VALUE_1 and UTF8_ERROR_VALUE_2 are special error values for UTF-8,
+ * which need 1 or 2 bytes in UTF-8:
+ * \code
+ * U+0015 = NAK = Negative Acknowledge, C0 control character
+ * U+009f = highest C1 control character
+ * \endcode
+ *
+ * These are used by UTF8_..._SAFE macros so that they can return an error value
+ * that needs the same number of code units (bytes) as were seen by
+ * a macro. They should be tested with UTF_IS_ERROR() or UTF_IS_VALID().
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define CBUTF8_ERROR_VALUE_1 0x15
+
+/**
+ * See documentation on UTF8_ERROR_VALUE_1 for details.
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define CBUTF8_ERROR_VALUE_2 0x9f
+
+
+/**
+ * Error value for all UTFs. This code point value will be set by macros with e>
+ * checking if an error is detected.
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define CBUTF_ERROR_VALUE 0xffff
+
+/*
+ * This table could be replaced on many machines by
+ * a few lines of assembler code using an
+ * "index of first 0-bit from msb" instruction and
+ * one or two more integer instructions.
+ *
+ * For example, on an i386, do something like
+ * - MOV AL, leadByte
+ * - NOT AL         (8-bit, leave b15..b8==0..0, reverse only b7..b0)
+ * - MOV AH, 0
+ * - BSR BX, AX     (16-bit)
+ * - MOV AX, 6      (result)
+ * - JZ finish      (ZF==1 if leadByte==0xff)
+ * - SUB AX, BX (result)
+ * -finish:
+ * (BSR: Bit Scan Reverse, scans for a 1-bit, starting from the MSB)
+ *
+ * In Unicode, all UTF-8 byte sequences with more than 4 bytes are illegal;
+ * lead bytes above 0xf4 are illegal.
+ * We keep them in this table for skipping long ISO 10646-UTF-8 sequences.
+ */
+const uint8
+utf8_countTrailBytes[256]={
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3,
+    3, 3, 3,    /* illegal in Unicode */
+    4, 4, 4, 4, /* illegal in Unicode */
+    5, 5,       /* illegal in Unicode */
+    0, 0        /* illegal bytes 0xfe and 0xff */
+};
+
+static const UChar32
+utf8_minLegal[4]={ 0, 0x80, 0x800, 0x10000 };
+
+static const UChar32
+utf8_errorValue[6]={
+    CBUTF8_ERROR_VALUE_1, CBUTF8_ERROR_VALUE_2, CBUTF_ERROR_VALUE, 0x10ffff,
+    0x3ffffff, 0x7fffffff
+};
+
+/*
+ * Handle the non-inline part of the U8_NEXT() macro and its obsolete sibling
+ * UTF8_NEXT_CHAR_SAFE().
+ *
+ * The "strict" parameter controls the error behavior:
+ * <0  "Safe" behavior of U8_NEXT(): All illegal byte sequences yield a negative
+ *     code point result.
+ *  0  Obsolete "safe" behavior of UTF8_NEXT_CHAR_SAFE(..., FALSE):
+ *     All illegal byte sequences yield a positive code point such that this
+ *     result code point would be encoded with the same number of bytes as
+ *     the illegal sequence.
+ * >0  Obsolete "strict" behavior of UTF8_NEXT_CHAR_SAFE(..., TRUE):
+ *     Same as the obsolete "safe" behavior, but non-characters are also treated
+ *     like illegal sequences.
+ *
+ * The special negative (<0) value -2 is used for lenient treatment of surrogate
+ * code points as legal. Some implementations use this for roundtripping of
+ * Unicode 16-bit strings that are not well-formed UTF-16, that is, they
+ * contain unpaired surrogates.
+ *
+ * Note that a UBool is the same as an int8_t.
+ */
+UChar32
+utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict) {
+    int32 i=*pi;
+    uint8 count=CBU8_COUNT_TRAIL_BYTES(c);
+    if((i)+count<=(length)) {
+        uint8 trail, illegal=0;
+
+        CBU8_MASK_LEAD_BYTE((c), count);
+        /* count==0 for illegally leading trail bytes and the illegal bytes 0xfe and 0xff */
+        switch(count) {
+        /* each branch falls through to the next one */
+        case 5:
+        case 4:
+            /* count>=4 is always illegal: no more than 3 trail bytes in Unicode's UTF-8 */
+            illegal=1;
+            break;
+        case 3:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            if(c<0x110) {
+                illegal|=(trail&0xc0)^0x80;
+            } else {
+                /* code point>0x10ffff, outside Unicode */
+                illegal=1;
+                break;
+            }
+        case 2:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            illegal|=(trail&0xc0)^0x80;
+        case 1:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            illegal|=(trail&0xc0)^0x80;
+            break;
+        case 0:
+            if(strict>=0) {
+                return CBUTF8_ERROR_VALUE_1;
+            } else {
+                return CBU_SENTINEL;
+            }
+        /* no default branch to optimize switch()  - all values are covered */
+        }
+
+        /*
+         * All the error handling should return a value
+         * that needs count bytes so that UTF8_GET_CHAR_SAFE() works right.
+         *
+         * Starting with Unicode 3.0.1, non-shortest forms are illegal.
+         * Starting with Unicode 3.2, surrogate code points must not be
+         * encoded in UTF-8, and there are no irregular sequences any more.
+         *
+         * U8_ macros (new in ICU 2.4) return negative values for error conditions.
+         */
+
+        /* correct sequence - all trail bytes have (b7..b6)==(10)? */
+        /* illegal is also set if count>=4 */
+        if(illegal || (c)<utf8_minLegal[count] || (CBU_IS_SURROGATE(c) && strict!=-2)) {
+            /* error handling */
+            uint8 errorCount=count;
+            /* don't go beyond this sequence */
+            i=*pi;
+            while(count>0 && CBU8_IS_TRAIL(s[i])) {
+                ++(i);
+                --count;
+            }
+            if(strict>=0) {
+                c=utf8_errorValue[errorCount-count];
+            } else {
+                c=CBU_SENTINEL;
+            }
+        } else if((strict)>0 && CBU_IS_UNICODE_NONCHAR(c)) {
+            /* strict: forbid non-characters like U+fffe */
+            c=utf8_errorValue[count];
+        }
+    } else /* too few bytes left */ {
+        /* error handling */
+        int32 i0=i;
+        /* don't just set (i)=(length) in case there is an illegal sequence */
+        while((i)<(length) && CBU8_IS_TRAIL(s[i])) {
+            ++(i);
+        }
+        if(strict>=0) {
+            c=utf8_errorValue[i-i0];
+        } else {
+            c=CBU_SENTINEL;
+        }
+    }
+    *pi=i;
+    return c;
+}
+
+}  // namespace base_icu
diff --git a/base/third_party/icu/icu_utf.h b/base/third_party/icu/icu_utf.h
new file mode 100644
index 0000000..9cb1247
--- /dev/null
+++ b/base/third_party/icu/icu_utf.h
@@ -0,0 +1,388 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utf.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep09
+*   created by: Markus W. Scherer
+*/
+
+#ifndef BASE_THIRD_PARTY_ICU_ICU_UTF_H_
+#define BASE_THIRD_PARTY_ICU_ICU_UTF_H_
+
+#include "base/basictypes.h"
+
+namespace base_icu {
+
+typedef uint32 UChar32;
+typedef int8 UBool;
+
+// General ---------------------------------------------------------------------
+// from utf.h
+
+/**
+ * This value is intended for sentinel values for APIs that
+ * (take or) return single code points (UChar32).
+ * It is outside of the Unicode code point range 0..0x10ffff.
+ *
+ * For example, a "done" or "error" value in a new API
+ * could be indicated with CBU_SENTINEL.
+ *
+ * ICU APIs designed before ICU 2.4 usually define service-specific "done"
+ * values, mostly 0xffff.
+ * Those may need to be distinguished from
+ * actual U+ffff text contents by calling functions like
+ * CharacterIterator::hasNext() or UnicodeString::length().
+ *
+ * @return -1
+ * @see UChar32
+ * @stable ICU 2.4
+ */
+#define CBU_SENTINEL (-1)
+
+/**
+ * Is this code point a Unicode noncharacter?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_UNICODE_NONCHAR(c) \
+    ((c)>=0xfdd0 && \
+     ((uint32)(c)<=0xfdef || ((c)&0xfffe)==0xfffe) && \
+     (uint32)(c)<=0x10ffff)
+
+/**
+ * Is c a Unicode code point value (0..U+10ffff)
+ * that can be assigned a character?
+ *
+ * Code points that are not characters include:
+ * - single surrogate code points (U+d800..U+dfff, 2048 code points)
+ * - the last two code points on each plane (U+__fffe and U+__ffff, 34 code points)
+ * - U+fdd0..U+fdef (new with Unicode 3.1, 32 code points)
+ * - the highest Unicode code point value is U+10ffff
+ *
+ * This means that all code points below U+d800 are character code points,
+ * and that boundary is tested first for performance.
+ *
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_UNICODE_CHAR(c) \
+    ((uint32)(c)<0xd800 || \
+        ((uint32)(c)>0xdfff && \
+         (uint32)(c)<=0x10ffff && \
+         !CBU_IS_UNICODE_NONCHAR(c)))
+
+/**
+ * Is this code point a surrogate (U+d800..U+dfff)?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
+
+/**
+ * Assuming c is a surrogate code point (U_IS_SURROGATE(c)),
+ * is it a lead surrogate?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+
+// UTF-8 macros ----------------------------------------------------------------
+// from utf8.h
+
+extern const uint8 utf8_countTrailBytes[256];
+
+/**
+ * Count the trail bytes for a UTF-8 lead byte.
+ * @internal
+ */
+#define CBU8_COUNT_TRAIL_BYTES(leadByte) (base_icu::utf8_countTrailBytes[(uint8)leadByte])
+
+/**
+ * Mask a UTF-8 lead byte, leave only the lower bits that form part of the code point value.
+ * @internal
+ */
+#define CBU8_MASK_LEAD_BYTE(leadByte, countTrailBytes) ((leadByte)&=(1<<(6-(countTrailBytes)))-1)
+
+/**
+ * Does this code unit (byte) encode a code point by itself (US-ASCII 0..0x7f)?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_SINGLE(c) (((c)&0x80)==0)
+
+/**
+ * Is this code unit (byte) a UTF-8 lead byte?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_LEAD(c) ((uint8)((c)-0xc0)<0x3e)
+
+/**
+ * Is this code unit (byte) a UTF-8 trail byte?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_TRAIL(c) (((c)&0xc0)==0x80)
+
+/**
+ * How many code units (bytes) are used for the UTF-8 encoding
+ * of this Unicode code point?
+ * @param c 32-bit code point
+ * @return 1..4, or 0 if c is a surrogate or not a Unicode code point
+ * @stable ICU 2.4
+ */
+#define CBU8_LENGTH(c) \
+    ((uint32)(c)<=0x7f ? 1 : \
+        ((uint32)(c)<=0x7ff ? 2 : \
+            ((uint32)(c)<=0xd7ff ? 3 : \
+                ((uint32)(c)<=0xdfff || (uint32)(c)>0x10ffff ? 0 : \
+                    ((uint32)(c)<=0xffff ? 3 : 4)\
+                ) \
+            ) \
+        ) \
+    )
+
+/**
+ * The maximum number of UTF-8 code units (bytes) per Unicode code point (U+0000..U+10ffff).
+ * @return 4
+ * @stable ICU 2.4
+ */
+#define CBU8_MAX_LENGTH 4
+
+/**
+ * Function for handling "next code point" with error-checking.
+ * @internal
+ */
+UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict);
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * The offset may point to the lead byte of a multi-byte sequence,
+ * in which case the macro will read the whole sequence.
+ * If the offset points to a trail byte or an illegal UTF-8 sequence, then
+ * c is set to a negative value.
+ *
+ * @param s const uint8 * string
+ * @param i string offset, i<length
+ * @param length string length
+ * @param c output UChar32 variable, set to <0 in case of an error
+ * @see CBU8_NEXT_UNSAFE
+ * @stable ICU 2.4
+ */
+#define CBU8_NEXT(s, i, length, c) { \
+    (c)=(s)[(i)++]; \
+    if(((uint8)(c))>=0x80) { \
+        if(CBU8_IS_LEAD(c)) { \
+            (c)=base_icu::utf8_nextCharSafeBody((const uint8 *)s, &(i), (int32)(length), c, -1); \
+        } else { \
+            (c)=CBU_SENTINEL; \
+        } \
+    } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 to 4 bytes.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * Otherwise, the result is undefined.
+ *
+ * @param s const uint8 * string buffer
+ * @param i string offset
+ * @param c code point to append
+ * @see CBU8_APPEND
+ * @stable ICU 2.4
+ */
+#define CBU8_APPEND_UNSAFE(s, i, c) { \
+    if((uint32)(c)<=0x7f) { \
+        (s)[(i)++]=(uint8)(c); \
+    } else { \
+        if((uint32)(c)<=0x7ff) { \
+            (s)[(i)++]=(uint8)(((c)>>6)|0xc0); \
+        } else { \
+            if((uint32)(c)<=0xffff) { \
+                (s)[(i)++]=(uint8)(((c)>>12)|0xe0); \
+            } else { \
+                (s)[(i)++]=(uint8)(((c)>>18)|0xf0); \
+                (s)[(i)++]=(uint8)((((c)>>12)&0x3f)|0x80); \
+            } \
+            (s)[(i)++]=(uint8)((((c)>>6)&0x3f)|0x80); \
+        } \
+        (s)[(i)++]=(uint8)(((c)&0x3f)|0x80); \
+    } \
+}
+
+// UTF-16 macros ---------------------------------------------------------------
+// from utf16.h
+
+/**
+ * Does this code unit alone encode a code point (BMP, not a surrogate)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SINGLE(c) !CBU_IS_SURROGATE(c)
+
+/**
+ * Is this code unit a lead surrogate (U+d800..U+dbff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
+
+/**
+ * Is this code unit a trail surrogate (U+dc00..U+dfff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
+
+/**
+ * Is this code unit a surrogate (U+d800..U+dfff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SURROGATE(c) CBU_IS_SURROGATE(c)
+
+/**
+ * Assuming c is a surrogate code point (U16_IS_SURROGATE(c)),
+ * is it a lead surrogate?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+/**
+ * Helper constant for CBU16_GET_SUPPLEMENTARY.
+ * @internal
+ */
+#define CBU16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
+
+/**
+ * Get a supplementary code point value (U+10000..U+10ffff)
+ * from its lead and trail surrogates.
+ * The result is undefined if the input values are not
+ * lead and trail surrogates.
+ *
+ * @param lead lead surrogate (U+d800..U+dbff)
+ * @param trail trail surrogate (U+dc00..U+dfff)
+ * @return supplementary code point (U+10000..U+10ffff)
+ * @stable ICU 2.4
+ */
+#define CBU16_GET_SUPPLEMENTARY(lead, trail) \
+    (((base_icu::UChar32)(lead)<<10UL)+(base_icu::UChar32)(trail)-CBU16_SURROGATE_OFFSET)
+
+
+/**
+ * Get the lead surrogate (0xd800..0xdbff) for a
+ * supplementary code point (0x10000..0x10ffff).
+ * @param supplementary 32-bit code point (U+10000..U+10ffff)
+ * @return lead surrogate (U+d800..U+dbff) for supplementary
+ * @stable ICU 2.4
+ */
+#define CBU16_LEAD(supplementary) (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) (UChar)(((supplementary)&0x3ff)|0xdc00)
+
+/**
+ * How many 16-bit code units are used to encode this Unicode code point? (1 or 2)
+ * The result is not defined if c is not a Unicode code point (U+0000..U+10ffff).
+ * @param c 32-bit code point
+ * @return 1 or 2
+ * @stable ICU 2.4
+ */
+#define CBU16_LENGTH(c) ((uint32)(c)<=0xffff ? 1 : 2)
+
+/**
+ * The maximum number of 16-bit code units per Unicode code point (U+0000..U+10ffff).
+ * @return 2
+ * @stable ICU 2.4
+ */
+#define CBU16_MAX_LENGTH 2
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * The offset may point to the lead surrogate unit
+ * for a supplementary code point, in which case the macro will read
+ * the following trail surrogate as well.
+ * If the offset points to a trail surrogate or
+ * to a single, unpaired lead surrogate, then that itself
+ * will be returned as the code point.
+ *
+ * @param s const UChar * string
+ * @param i string offset, i<length
+ * @param length string length
+ * @param c output UChar32 variable
+ * @stable ICU 2.4
+ */
+#define CBU16_NEXT(s, i, length, c) { \
+    (c)=(s)[(i)++]; \
+    if(CBU16_IS_LEAD(c)) { \
+        uint16 __c2; \
+        if((i)<(length) && CBU16_IS_TRAIL(__c2=(s)[(i)])) { \
+            ++(i); \
+            (c)=CBU16_GET_SUPPLEMENTARY((c), __c2); \
+        } \
+    } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 or 2 code units.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * Otherwise, the result is undefined.
+ *
+ * @param s const UChar * string buffer
+ * @param i string offset
+ * @param c code point to append
+ * @see CBU16_APPEND
+ * @stable ICU 2.4
+ */
+#define CBU16_APPEND_UNSAFE(s, i, c) { \
+    if((uint32)(c)<=0xffff) { \
+        (s)[(i)++]=(uint16)(c); \
+    } else { \
+        (s)[(i)++]=(uint16)(((c)>>10)+0xd7c0); \
+        (s)[(i)++]=(uint16)(((c)&0x3ff)|0xdc00); \
+    } \
+}
+
+}  // namesapce base_icu
+
+#endif  // BASE_THIRD_PARTY_ICU_ICU_UTF_H_
diff --git a/base/third_party/nspr/LICENSE b/base/third_party/nspr/LICENSE
new file mode 100644
index 0000000..eba7b77
--- /dev/null
+++ b/base/third_party/nspr/LICENSE
@@ -0,0 +1,35 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
diff --git a/base/third_party/nspr/README.chromium b/base/third_party/nspr/README.chromium
new file mode 100644
index 0000000..3659a2c
--- /dev/null
+++ b/base/third_party/nspr/README.chromium
@@ -0,0 +1,3 @@
+Name: Netscape Portable Runtime (NSPR)
+URL: http://www.mozilla.org/projects/nspr/
+License: MPL 1.1/GPL 2.0/LGPL 2.1
diff --git a/base/third_party/nspr/prcpucfg.h b/base/third_party/nspr/prcpucfg.h
new file mode 100644
index 0000000..d6ebb47
--- /dev/null
+++ b/base/third_party/nspr/prcpucfg.h
@@ -0,0 +1,51 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef BASE_THIRD_PARTY_NSPR_PRCPUCFG_H__
+#define BASE_THIRD_PARTY_NSPR_PRCPUCFG_H__
+
+#if defined(WIN32)
+#include "base/third_party/nspr/prcpucfg_win.h"
+#elif defined(__APPLE__)
+#include "base/third_party/nspr/prcpucfg_mac.h"
+#elif defined(__native_client__)
+#include "base/third_party/nspr/prcpucfg_nacl.h"
+#elif defined(__linux__) || defined(ANDROID)
+#include "base/third_party/nspr/prcpucfg_linux.h"
+#elif defined(__FreeBSD__)
+#include "base/third_party/nspr/prcpucfg_freebsd.h"
+#elif defined(__OpenBSD__)
+#include "base/third_party/nspr/prcpucfg_openbsd.h"
+#elif defined(__sun)
+#include "base/third_party/nspr/prcpucfg_solaris.h"
+#else
+#error Provide a prcpucfg.h appropriate for your platform
+#endif
+
+#endif  // BASE_THIRD_PARTY_NSPR_PRCPUCFG_H__
diff --git a/base/third_party/nspr/prcpucfg_freebsd.h b/base/third_party/nspr/prcpucfg_freebsd.h
new file mode 100644
index 0000000..76d3542
--- /dev/null
+++ b/base/third_party/nspr/prcpucfg_freebsd.h
@@ -0,0 +1,337 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#ifndef FREEBSD
+#define FREEBSD
+#endif
+
+#define PR_AF_INET6 28  /* same as AF_INET6 */
+
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG
+#endif
+
+#if defined(__i386__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#undef	HAVE_ALIGNED_DOUBLES
+#undef	HAVE_ALIGNED_LONGLONGS
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+
+#elif defined(__alpha__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+
+#elif defined(__sparc__)
+
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+
+#elif defined(__ia64__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#elif defined(__amd64__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#else
+
+#error "Unknown CPU architecture"
+
+#endif
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
+#define BYTES_PER_INT 		PR_BYTES_PER_INT
+#define BYTES_PER_INT64		PR_BYTES_PER_INT64
+#define BYTES_PER_LONG		PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD		PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE		PR_BITS_PER_BYTE
+#define BITS_PER_SHORT		PR_BITS_PER_SHORT
+#define BITS_PER_INT		PR_BITS_PER_INT
+#define BITS_PER_INT64		PR_BITS_PER_INT64
+#define BITS_PER_LONG		PR_BITS_PER_LONG
+#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD		PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT		PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
diff --git a/base/third_party/nspr/prcpucfg_linux.h b/base/third_party/nspr/prcpucfg_linux.h
new file mode 100644
index 0000000..776c21e
--- /dev/null
+++ b/base/third_party/nspr/prcpucfg_linux.h
@@ -0,0 +1,707 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#ifndef LINUX
+#define LINUX
+#endif
+
+#define PR_AF_INET6 10  /* same as AF_INET6 */
+
+#ifdef __powerpc64__
+
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN    1
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__powerpc__)
+
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN    1
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__alpha)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#define PR_BYTES_PER_WORD_LOG2  3
+#define PR_BYTES_PER_DWORD_LOG2 3
+
+#elif defined(__ia64__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#define PR_BYTES_PER_WORD_LOG2  3
+#define PR_BYTES_PER_DWORD_LOG2 3
+
+#elif defined(__x86_64__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#define PR_BYTES_PER_WORD_LOG2  3
+#define PR_BYTES_PER_DWORD_LOG2 3
+
+#elif defined(__mc68000__)
+
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     2
+#define PR_ALIGN_OF_LONG    2
+#define PR_ALIGN_OF_INT64   2
+#define PR_ALIGN_OF_FLOAT   2
+#define PR_ALIGN_OF_DOUBLE  2
+#define PR_ALIGN_OF_POINTER 2
+#define PR_ALIGN_OF_WORD    2
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__sparc__)
+
+#undef	IS_LITTLE_ENDIAN
+#define	IS_BIG_ENDIAN 1
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__i386__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__mips__)
+
+#ifdef __MIPSEB__
+#define IS_BIG_ENDIAN 1
+#undef  IS_LITTLE_ENDIAN
+#elif defined(__MIPSEL__)
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#else
+#error "Unknown MIPS endianness."
+#endif
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__arm__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__hppa__)
+
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN    1
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__s390x__)
+
+#define IS_BIG_ENDIAN 1
+#undef  IS_LITTLE_ENDIAN
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__s390__)
+
+#define IS_BIG_ENDIAN 1
+#undef  IS_LITTLE_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#else
+
+#error "Unknown CPU architecture"
+
+#endif
+
+#define	HAVE_LONG_LONG
+#if PR_ALIGN_OF_DOUBLE == 8
+#define HAVE_ALIGNED_DOUBLES
+#endif
+#if PR_ALIGN_OF_INT64 == 8
+#define HAVE_ALIGNED_LONGLONGS
+#endif
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
+#define BYTES_PER_INT 		PR_BYTES_PER_INT
+#define BYTES_PER_INT64		PR_BYTES_PER_INT64
+#define BYTES_PER_LONG		PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD		PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE		PR_BITS_PER_BYTE
+#define BITS_PER_SHORT		PR_BITS_PER_SHORT
+#define BITS_PER_INT		PR_BITS_PER_INT
+#define BITS_PER_INT64		PR_BITS_PER_INT64
+#define BITS_PER_LONG		PR_BITS_PER_LONG
+#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD		PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT		PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
diff --git a/base/third_party/nspr/prcpucfg_mac.h b/base/third_party/nspr/prcpucfg_mac.h
new file mode 100644
index 0000000..60bea8e
--- /dev/null
+++ b/base/third_party/nspr/prcpucfg_mac.h
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#define PR_AF_INET6 30  /* same as AF_INET6 */
+
+#ifdef __LITTLE_ENDIAN__
+#undef IS_BIG_ENDIAN
+#define  IS_LITTLE_ENDIAN 1
+#else
+#undef IS_LITTLE_ENDIAN
+#define  IS_BIG_ENDIAN 1
+#endif
+
+#ifdef __x86_64__
+#define IS_64
+#endif
+
+#ifndef HAVE_LONG_LONG
+#define	HAVE_LONG_LONG
+#endif
+#undef	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS 1
+
+#ifdef IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+#define PR_BITS_PER_DWORD   64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+#define PR_BITS_PER_DWORD_LOG2  6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+#define PR_ALIGN_OF_DWORD   8
+
+#else /* IS_64 */
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+#define PR_BITS_PER_DWORD   64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#endif /* IS_64 */
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
+#define BYTES_PER_INT 		PR_BYTES_PER_INT
+#define BYTES_PER_INT64		PR_BYTES_PER_INT64
+#define BYTES_PER_LONG		PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD		PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE		PR_BITS_PER_BYTE
+#define BITS_PER_SHORT		PR_BITS_PER_SHORT
+#define BITS_PER_INT		PR_BITS_PER_INT
+#define BITS_PER_INT64		PR_BITS_PER_INT64
+#define BITS_PER_LONG		PR_BITS_PER_LONG
+#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD		PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT		PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
+
diff --git a/base/third_party/nspr/prcpucfg_nacl.h b/base/third_party/nspr/prcpucfg_nacl.h
new file mode 100644
index 0000000..d8602d3
--- /dev/null
+++ b/base/third_party/nspr/prcpucfg_nacl.h
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#ifndef LINUX
+#define LINUX
+#endif
+
+#define PR_AF_INET6 10  /* same as AF_INET6 */
+
+#if defined(__x86_64__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#define PR_BYTES_PER_WORD_LOG2  3
+#define PR_BYTES_PER_DWORD_LOG2 3
+
+#elif defined(__i386__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__arm__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#else
+
+#error "Unknown CPU architecture"
+
+#endif
+
+#define	HAVE_LONG_LONG
+#if PR_ALIGN_OF_DOUBLE == 8
+#define HAVE_ALIGNED_DOUBLES
+#endif
+#if PR_ALIGN_OF_INT64 == 8
+#define HAVE_ALIGNED_LONGLONGS
+#endif
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
+#define BYTES_PER_INT 		PR_BYTES_PER_INT
+#define BYTES_PER_INT64		PR_BYTES_PER_INT64
+#define BYTES_PER_LONG		PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD		PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE		PR_BITS_PER_BYTE
+#define BITS_PER_SHORT		PR_BITS_PER_SHORT
+#define BITS_PER_INT		PR_BITS_PER_INT
+#define BITS_PER_INT64		PR_BITS_PER_INT64
+#define BITS_PER_LONG		PR_BITS_PER_LONG
+#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD		PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT		PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
diff --git a/base/third_party/nspr/prcpucfg_openbsd.h b/base/third_party/nspr/prcpucfg_openbsd.h
new file mode 100644
index 0000000..93c5b32
--- /dev/null
+++ b/base/third_party/nspr/prcpucfg_openbsd.h
@@ -0,0 +1,337 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#ifndef OPENBSD
+#define OPENBSD
+#endif
+
+#define PR_AF_INET6 28  /* same as AF_INET6 */
+
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG
+#endif
+
+#if defined(__i386__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#undef	HAVE_ALIGNED_DOUBLES
+#undef	HAVE_ALIGNED_LONGLONGS
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+
+#elif defined(__alpha__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+
+#elif defined(__sparc__)
+
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+
+#elif defined(__ia64__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#elif defined(__amd64__)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#else
+
+#error "Unknown CPU architecture"
+
+#endif
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
+#define BYTES_PER_INT 		PR_BYTES_PER_INT
+#define BYTES_PER_INT64		PR_BYTES_PER_INT64
+#define BYTES_PER_LONG		PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD		PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE		PR_BITS_PER_BYTE
+#define BITS_PER_SHORT		PR_BITS_PER_SHORT
+#define BITS_PER_INT		PR_BITS_PER_INT
+#define BITS_PER_INT64		PR_BITS_PER_INT64
+#define BITS_PER_LONG		PR_BITS_PER_LONG
+#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD		PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT		PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
diff --git a/base/third_party/nspr/prcpucfg_solaris.h b/base/third_party/nspr/prcpucfg_solaris.h
new file mode 100644
index 0000000..81313e5
--- /dev/null
+++ b/base/third_party/nspr/prcpucfg_solaris.h
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#ifndef SOLARIS
+#define SOLARIS
+#endif
+
+#define PR_AF_INET6 26  /* same as AF_INET6 */
+
+#if defined(sparc) || defined(__sparc)
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_DOUBLE  8
+#if defined(__sparcv9)
+#define IS_64
+#endif
+#elif defined(__x86_64)
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_DOUBLE  8
+#define IS_64
+#elif defined(i386) || defined(__i386)
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_DOUBLE  4
+#else
+#error unknown processor
+#endif
+
+#ifdef IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_POINTER 8
+
+#else /* IS_64 */
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_POINTER 4
+
+#endif /* IS_64 */
+
+#ifndef HAVE_LONG_LONG
+#define	HAVE_LONG_LONG
+#endif
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
+#define BYTES_PER_INT 		PR_BYTES_PER_INT
+#define BYTES_PER_INT64		PR_BYTES_PER_INT64
+#define BYTES_PER_LONG		PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD		PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE		PR_BITS_PER_BYTE
+#define BITS_PER_SHORT		PR_BITS_PER_SHORT
+#define BITS_PER_INT		PR_BITS_PER_INT
+#define BITS_PER_INT64		PR_BITS_PER_INT64
+#define BITS_PER_LONG		PR_BITS_PER_LONG
+#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD		PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT		PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* ifndef nspr_cpucfg___ */
diff --git a/base/third_party/nspr/prcpucfg_win.h b/base/third_party/nspr/prcpucfg_win.h
new file mode 100644
index 0000000..4ad5345
--- /dev/null
+++ b/base/third_party/nspr/prcpucfg_win.h
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_PC
+#define XP_PC
+#endif
+
+#ifndef WIN32
+#define WIN32
+#endif
+
+#ifndef WIN95
+#define WIN95
+#endif
+
+#define PR_AF_INET6 23  /* same as AF_INET6 */
+
+#if defined(_M_IX86) || defined(_X86_)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_WORD	4
+#define PR_BYTES_PER_DWORD	8
+#define PR_BYTES_PER_DOUBLE 8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_WORD	32
+#define PR_BITS_PER_DWORD	64
+#define PR_BITS_PER_DOUBLE  64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_WORD_LOG2	5
+#define PR_BITS_PER_DWORD_LOG2	6
+#define PR_BITS_PER_DOUBLE_LOG2 6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_WORD	4
+#define PR_ALIGN_OF_DWORD	8
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+
+#define PR_BYTES_PER_WORD_LOG2	2
+#define PR_BYTES_PER_DWORD_LOG2	2
+
+#elif defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_WORD	8
+#define PR_BYTES_PER_DWORD	8
+#define PR_BYTES_PER_DOUBLE 8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_WORD	64
+#define PR_BITS_PER_DWORD	64
+#define PR_BITS_PER_DOUBLE  64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_WORD_LOG2	6
+#define PR_BITS_PER_DWORD_LOG2	6
+#define PR_BITS_PER_DOUBLE_LOG2 6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_WORD	8
+#define PR_ALIGN_OF_DWORD	8
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+
+#define PR_BYTES_PER_WORD_LOG2	3
+#define PR_BYTES_PER_DWORD_LOG2	3
+
+#elif defined(_M_IA64) || defined(_IA64_)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_WORD	8
+#define PR_BYTES_PER_DWORD	8
+#define PR_BYTES_PER_DOUBLE 8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_WORD	64
+#define PR_BITS_PER_DWORD	64
+#define PR_BITS_PER_DOUBLE  64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_WORD_LOG2	6
+#define PR_BITS_PER_DWORD_LOG2	6
+#define PR_BITS_PER_DOUBLE_LOG2 6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_WORD	8
+#define PR_ALIGN_OF_DWORD	8
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+
+#define PR_BYTES_PER_WORD_LOG2	3
+#define PR_BYTES_PER_DWORD_LOG2	3
+
+#else /* defined(_M_IX86) || defined(_X86_) */
+
+#error unknown processor architecture
+
+#endif /* defined(_M_IX86) || defined(_X86_) */
+
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG
+#endif
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE      PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT     PR_BYTES_PER_SHORT
+#define BYTES_PER_INT       PR_BYTES_PER_INT
+#define BYTES_PER_INT64     PR_BYTES_PER_INT64
+#define BYTES_PER_LONG      PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT     PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE    PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD      PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD     PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE       PR_BITS_PER_BYTE
+#define BITS_PER_SHORT      PR_BITS_PER_SHORT
+#define BITS_PER_INT        PR_BITS_PER_INT
+#define BITS_PER_INT64      PR_BITS_PER_INT64
+#define BITS_PER_LONG       PR_BITS_PER_LONG
+#define BITS_PER_FLOAT      PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE     PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD       PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2  PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2   PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2  PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2    PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2  PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT      PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT        PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG       PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64      PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT      PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE     PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER    PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD       PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2		PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2    PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2    PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
diff --git a/base/third_party/nspr/prtime.cc b/base/third_party/nspr/prtime.cc
new file mode 100644
index 0000000..5fc89c5
--- /dev/null
+++ b/base/third_party/nspr/prtime.cc
@@ -0,0 +1,1210 @@
+/* Portions are Copyright (C) 2011 Google Inc */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * prtime.cc --
+ * NOTE: The original nspr file name is prtime.c
+ *
+ *     NSPR date and time functions
+ *
+ * CVS revision 3.37
+ */
+
+/*
+ * The following functions were copied from the NSPR prtime.c file.
+ * PR_ParseTimeString
+ *   We inlined the new PR_ParseTimeStringToExplodedTime function to avoid
+ *   copying PR_ExplodeTime and PR_LocalTimeParameters.  (The PR_ExplodeTime
+ *   and PR_ImplodeTime calls cancel each other out.)
+ * PR_NormalizeTime
+ * PR_GMTParameters
+ * PR_ImplodeTime
+ *   This was modified to use the Win32 SYSTEMTIME/FILETIME structures
+ *   and the timezone offsets are applied to the FILETIME structure.
+ * All types and macros are defined in the base/third_party/prtime.h file.
+ * These have been copied from the following nspr files. We have only copied
+ * over the types we need.
+ * 1. prtime.h
+ * 2. prtypes.h
+ * 3. prlong.h
+ */
+
+#include "base/logging.h"
+#include "base/third_party/nspr/prtime.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#elif defined(OS_ANDROID)
+#include <ctype.h>
+#include "base/os_compat_android.h"  // For timegm()
+#elif defined(OS_NACL)
+#include "base/os_compat_nacl.h"  // For timegm()
+#endif
+#include <errno.h>  /* for EINVAL */
+#include <time.h>
+
+/* Implements the Unix localtime_r() function for windows */
+#if defined(OS_WIN)
+static void localtime_r(const time_t* secs, struct tm* time) {
+  (void) localtime_s(time, secs);
+}
+#endif
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * PR_ImplodeTime --
+ *
+ *     Cf. time_t mktime(struct tm *tp)
+ *     Note that 1 year has < 2^25 seconds.  So an PRInt32 is large enough.
+ *
+ *------------------------------------------------------------------------
+ */
+PRTime
+PR_ImplodeTime(const PRExplodedTime *exploded)
+{
+    // This is important, we want to make sure multiplications are
+    // done with the correct precision.
+    static const PRTime kSecondsToMicroseconds = static_cast<PRTime>(1000000);
+#if defined(OS_WIN)
+   // Create the system struct representing our exploded time.
+    SYSTEMTIME st = {0};
+    FILETIME ft = {0};
+    ULARGE_INTEGER uli = {0};
+
+    st.wYear = exploded->tm_year;
+    st.wMonth = exploded->tm_month + 1;
+    st.wDayOfWeek = exploded->tm_wday;
+    st.wDay = exploded->tm_mday;
+    st.wHour = exploded->tm_hour;
+    st.wMinute = exploded->tm_min;
+    st.wSecond = exploded->tm_sec;
+    st.wMilliseconds = exploded->tm_usec/1000;
+     // Convert to FILETIME.
+    if (!SystemTimeToFileTime(&st, &ft)) {
+      NOTREACHED() << "Unable to convert time";
+      return 0;
+    }
+    // Apply offsets.
+    uli.LowPart = ft.dwLowDateTime;
+    uli.HighPart = ft.dwHighDateTime;
+    // Convert from Windows epoch to NSPR epoch, and 100-nanoseconds units
+    // to microsecond units.
+    PRTime result =
+        static_cast<PRTime>((uli.QuadPart / 10) - 11644473600000000i64);
+    // Adjust for time zone and dst.  Convert from seconds to microseconds.
+    result -= (exploded->tm_params.tp_gmt_offset +
+               exploded->tm_params.tp_dst_offset) * kSecondsToMicroseconds;
+    return result;
+#elif defined(OS_MACOSX)
+    // Create the system struct representing our exploded time.
+    CFGregorianDate gregorian_date;
+    gregorian_date.year = exploded->tm_year;
+    gregorian_date.month = exploded->tm_month + 1;
+    gregorian_date.day = exploded->tm_mday;
+    gregorian_date.hour = exploded->tm_hour;
+    gregorian_date.minute = exploded->tm_min;
+    gregorian_date.second = exploded->tm_sec;
+
+    // Compute |absolute_time| in seconds, correct for gmt and dst
+    // (note the combined offset will be negative when we need to add it), then
+    // convert to microseconds which is what PRTime expects.
+    CFAbsoluteTime absolute_time =
+        CFGregorianDateGetAbsoluteTime(gregorian_date, NULL);
+    PRTime result = static_cast<PRTime>(absolute_time);
+    result -= exploded->tm_params.tp_gmt_offset +
+              exploded->tm_params.tp_dst_offset;
+    result += kCFAbsoluteTimeIntervalSince1970;  // PRTime epoch is 1970
+    result *= kSecondsToMicroseconds;
+    result += exploded->tm_usec;
+    return result;
+#elif defined(OS_POSIX)
+    struct tm exp_tm = {0};
+    exp_tm.tm_sec  = exploded->tm_sec;
+    exp_tm.tm_min  = exploded->tm_min;
+    exp_tm.tm_hour = exploded->tm_hour;
+    exp_tm.tm_mday = exploded->tm_mday;
+    exp_tm.tm_mon  = exploded->tm_month;
+    exp_tm.tm_year = exploded->tm_year - 1900;
+
+    time_t absolute_time = timegm(&exp_tm);
+
+    // If timegm returned -1.  Since we don't pass it a time zone, the only
+    // valid case of returning -1 is 1 second before Epoch (Dec 31, 1969).
+    if (absolute_time == -1 &&
+        !(exploded->tm_year == 1969 && exploded->tm_month == 11 &&
+        exploded->tm_mday == 31 && exploded->tm_hour == 23 &&
+        exploded->tm_min == 59 && exploded->tm_sec == 59)) {
+      // If we get here, time_t must be 32 bits.
+      // Date was possibly too far in the future and would overflow.  Return
+      // the most future date possible (year 2038).
+      if (exploded->tm_year >= 1970)
+        return INT_MAX * kSecondsToMicroseconds;
+      // Date was possibly too far in the past and would underflow.  Return
+      // the most past date possible (year 1901).
+      return INT_MIN * kSecondsToMicroseconds;
+    }
+
+    PRTime result = static_cast<PRTime>(absolute_time);
+    result -= exploded->tm_params.tp_gmt_offset +
+              exploded->tm_params.tp_dst_offset;
+    result *= kSecondsToMicroseconds;
+    result += exploded->tm_usec;
+    return result;
+#else
+#error No PR_ImplodeTime implemented on your platform.
+#endif
+}
+
+/* 
+ * The COUNT_LEAPS macro counts the number of leap years passed by
+ * till the start of the given year Y.  At the start of the year 4
+ * A.D. the number of leap years passed by is 0, while at the start of
+ * the year 5 A.D. this count is 1. The number of years divisible by
+ * 100 but not divisible by 400 (the non-leap years) is deducted from
+ * the count to get the correct number of leap years.
+ *
+ * The COUNT_DAYS macro counts the number of days since 01/01/01 till the
+ * start of the given year Y. The number of days at the start of the year
+ * 1 is 0 while the number of days at the start of the year 2 is 365
+ * (which is ((2)-1) * 365) and so on. The reference point is 01/01/01
+ * midnight 00:00:00.
+ */
+
+#define COUNT_LEAPS(Y)   ( ((Y)-1)/4 - ((Y)-1)/100 + ((Y)-1)/400 )
+#define COUNT_DAYS(Y)  ( ((Y)-1)*365 + COUNT_LEAPS(Y) )
+#define DAYS_BETWEEN_YEARS(A, B)  (COUNT_DAYS(B) - COUNT_DAYS(A))
+
+/*
+ * Static variables used by functions in this file
+ */
+
+/*
+ * The following array contains the day of year for the last day of
+ * each month, where index 1 is January, and day 0 is January 1.
+ */
+
+static const int lastDayOfMonth[2][13] = {
+    {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364},
+    {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}
+};
+
+/*
+ * The number of days in a month
+ */
+
+static const PRInt8 nDays[2][12] = {
+    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+};
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * IsLeapYear --
+ *
+ *     Returns 1 if the year is a leap year, 0 otherwise.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static int IsLeapYear(PRInt16 year)
+{
+    if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
+        return 1;
+    else
+        return 0;
+}
+
+/*
+ * 'secOffset' should be less than 86400 (i.e., a day).
+ * 'time' should point to a normalized PRExplodedTime.
+ */
+
+static void
+ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset)
+{
+    time->tm_sec += secOffset;
+
+    /* Note that in this implementation we do not count leap seconds */
+    if (time->tm_sec < 0 || time->tm_sec >= 60) {
+        time->tm_min += time->tm_sec / 60;
+        time->tm_sec %= 60;
+        if (time->tm_sec < 0) {
+            time->tm_sec += 60;
+            time->tm_min--;
+        }
+    }
+
+    if (time->tm_min < 0 || time->tm_min >= 60) {
+        time->tm_hour += time->tm_min / 60;
+        time->tm_min %= 60;
+        if (time->tm_min < 0) {
+            time->tm_min += 60;
+            time->tm_hour--;
+        }
+    }
+
+    if (time->tm_hour < 0) {
+        /* Decrement mday, yday, and wday */
+        time->tm_hour += 24;
+        time->tm_mday--;
+        time->tm_yday--;
+        if (time->tm_mday < 1) {
+            time->tm_month--;
+            if (time->tm_month < 0) {
+                time->tm_month = 11;
+                time->tm_year--;
+                if (IsLeapYear(time->tm_year))
+                    time->tm_yday = 365;
+                else
+                    time->tm_yday = 364;
+            }
+            time->tm_mday = nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        }
+        time->tm_wday--;
+        if (time->tm_wday < 0)
+            time->tm_wday = 6;
+    } else if (time->tm_hour > 23) {
+        /* Increment mday, yday, and wday */
+        time->tm_hour -= 24;
+        time->tm_mday++;
+        time->tm_yday++;
+        if (time->tm_mday >
+                nDays[IsLeapYear(time->tm_year)][time->tm_month]) {
+            time->tm_mday = 1;
+            time->tm_month++;
+            if (time->tm_month > 11) {
+                time->tm_month = 0;
+                time->tm_year++;
+                time->tm_yday = 0;
+            }
+        }
+        time->tm_wday++;
+        if (time->tm_wday > 6)
+            time->tm_wday = 0;
+    }
+}
+
+void
+PR_NormalizeTime(PRExplodedTime *time, PRTimeParamFn params)
+{
+    int daysInMonth;
+    PRInt32 numDays;
+
+    /* Get back to GMT */
+    time->tm_sec -= time->tm_params.tp_gmt_offset
+            + time->tm_params.tp_dst_offset;
+    time->tm_params.tp_gmt_offset = 0;
+    time->tm_params.tp_dst_offset = 0;
+
+    /* Now normalize GMT */
+
+    if (time->tm_usec < 0 || time->tm_usec >= 1000000) {
+        time->tm_sec +=  time->tm_usec / 1000000;
+        time->tm_usec %= 1000000;
+        if (time->tm_usec < 0) {
+            time->tm_usec += 1000000;
+            time->tm_sec--;
+        }
+    }
+
+    /* Note that we do not count leap seconds in this implementation */
+    if (time->tm_sec < 0 || time->tm_sec >= 60) {
+        time->tm_min += time->tm_sec / 60;
+        time->tm_sec %= 60;
+        if (time->tm_sec < 0) {
+            time->tm_sec += 60;
+            time->tm_min--;
+        }
+    }
+
+    if (time->tm_min < 0 || time->tm_min >= 60) {
+        time->tm_hour += time->tm_min / 60;
+        time->tm_min %= 60;
+        if (time->tm_min < 0) {
+            time->tm_min += 60;
+            time->tm_hour--;
+        }
+    }
+
+    if (time->tm_hour < 0 || time->tm_hour >= 24) {
+        time->tm_mday += time->tm_hour / 24;
+        time->tm_hour %= 24;
+        if (time->tm_hour < 0) {
+            time->tm_hour += 24;
+            time->tm_mday--;
+        }
+    }
+
+    /* Normalize month and year before mday */
+    if (time->tm_month < 0 || time->tm_month >= 12) {
+        time->tm_year += 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 = 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)
+{
+#if defined(XP_MAC)
+#pragma unused (gmt)
+#endif
+
+    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
+ *
+ * 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;
+
+  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;
+                        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');
+
+                                /* If we made it here, we've parsed hour and min,
+                                   and possibly sec, so it worked as a unit. */
+
+                                /* skip over whitespace and see if there's an AM or PM
+                                   directly following the time.
+                                 */
+                                if (tmp_hour <= 12)
+                                  {
+                                        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;
+                                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...
+                                   #### But it doesn't handle 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 or 2 digits */
+                                if (*s >= '0' && *s <= '9')
+                                  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 >= '0' && *s <= '9') ||        /* followed by non-alphanum */
+                                        (*s >= 'A' && *s <= 'Z') ||
+                                        (*s >= 'a' && *s <= 'z'))
+                                  break;
+
+                                /* Ok, we parsed three 1-2 digit numbers, with / or -
+                                   between them.  Now decide what the hell they are
+                                   (DD/MM/YY or MM/DD/YY or YY/MM/DD.)
+                                 */
+
+                                if (n1 > 31 || n1 == 0)  /* must be 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;
+                  }
+                }
+
+          /* Skip to the end of this token, whether we parsed it or not.
+                 Tokens are delimited by whitespace, or ,;-/
+                 But explicitly not :+-.
+           */
+          while (*rest &&
+                         *rest != ' ' && *rest != '\t' &&
+                         *rest != ',' && *rest != ';' &&
+                         *rest != '-' && *rest != '+' &&
+                         *rest != '/' &&
+                         *rest != '(' && *rest != ')' && *rest != '[' && *rest != ']')
+                rest++;
+          /* skip over uninteresting chars. */
+        SKIP_MORE:
+          while (*rest &&
+                         (*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;
+                }
+
+        }
+
+  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 (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 = year;
+  if (dotw != TT_UNKNOWN)
+        result->tm_wday = (((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)
+                {
+                  PRInt64 usec_per_sec;
+
+                  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)
+                    {
+                      PRTime usecs64;
+                      LL_I2L(usecs64, secs);
+                      LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
+                      LL_MUL(usecs64, usecs64, usec_per_sec);
+                      *result_imploded = usecs64;
+                      return PR_SUCCESS;
+                    }
+                }
+                
+                /* So mktime() can't handle this case.  We assume the
+                   zone_offset for the date we are parsing is the same as
+                   the zone offset on 00:00:00 2 Jan 1970 GMT. */
+                secs = 86400;
+                localtime_r(&secs, &localTime);
+                zone_offset = localTime.tm_min
+                              + 60 * localTime.tm_hour
+                              + 1440 * (localTime.tm_mday - 2);
+        }
+
+  result->tm_params.tp_gmt_offset = zone_offset * 60;
+  result->tm_params.tp_dst_offset = dst_offset * 60;
+
+  *result_imploded = PR_ImplodeTime(result);
+  return PR_SUCCESS;
+}
diff --git a/base/third_party/nspr/prtime.h b/base/third_party/nspr/prtime.h
new file mode 100644
index 0000000..ffbedec
--- /dev/null
+++ b/base/third_party/nspr/prtime.h
@@ -0,0 +1,238 @@
+/* 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 "base/base_export.h"
+#include "base/third_party/nspr/prtypes.h"
+
+#define PR_ASSERT DCHECK
+
+#define LL_I2L(l, i)    ((l) = (PRInt64)(i))
+#define LL_MUL(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
+ *
+ * If the input string doesn't contain a description of the timezone,
+ * we consult the `default_to_gmt' to decide whether the string should
+ * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE).
+ * The correct value for this argument depends on what standard specified
+ * the time string which you are parsing.
+ */
+
+/*
+ * This is the only funtion that should be called from outside base, and only
+ * from the unit test.
+ */
+
+BASE_EXPORT PRStatus PR_ParseTimeString (
+	const char *string,
+	PRBool default_to_gmt,
+	PRTime *result);
+
+#endif  // BASE_PRTIME_H__
diff --git a/base/third_party/nspr/prtypes.h b/base/third_party/nspr/prtypes.h
new file mode 100644
index 0000000..630df81
--- /dev/null
+++ b/base/third_party/nspr/prtypes.h
@@ -0,0 +1,558 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 ***** */
+
+/*
+** File:                prtypes.h
+** Description: Definitions of NSPR's basic types
+**
+** Prototypes and macros used to make up for deficiencies that we have found
+** in ANSI environments.
+**
+** Since we do not wrap <stdlib.h> and all the other standard headers, authors
+** of portable code will not know in general that they need these definitions.
+** Instead of requiring these authors to find the dependent uses in their code
+** and take the following steps only in those C files, we take steps once here
+** for all C files.
+**/
+
+#ifndef prtypes_h___
+#define prtypes_h___
+
+#ifdef MDCPUCFG
+#include MDCPUCFG
+#else
+#include "base/third_party/nspr/prcpucfg.h"
+#endif
+
+#include <stddef.h>
+
+/***********************************************************************
+** MACROS:      PR_EXTERN
+**              PR_IMPLEMENT
+** DESCRIPTION:
+**      These are only for externally visible routines and globals.  For
+**      internal routines, just use "extern" for type checking and that
+**      will not export internal cross-file or forward-declared symbols.
+**      Define a macro for declaring procedures return types. We use this to
+**      deal with windoze specific type hackery for DLL definitions. Use
+**      PR_EXTERN when the prototype for the method is declared. Use
+**      PR_IMPLEMENT for the implementation of the method.
+**
+** Example:
+**   in dowhim.h
+**     PR_EXTERN( void ) DoWhatIMean( void );
+**   in dowhim.c
+**     PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; }
+**
+**
+***********************************************************************/
+#if 1
+
+/*
+** Local change: the portions of NSPR used by the base module are
+** implementation details.  NSPR symbols do not need to be exported beyond
+** the base module.  For all platforms, avoid decorating functions with
+** specific visibility and access keywords.
+*/
+
+#define PR_EXPORT(__type) extern __type
+#define PR_EXPORT_DATA(__type) extern __type
+#define PR_IMPORT(__type) extern __type
+#define PR_IMPORT_DATA(__type) extern __type
+
+#define PR_EXTERN(__type) extern __type
+#define PR_IMPLEMENT(__type) __type
+#define PR_EXTERN_DATA(__type) extern __type
+#define PR_IMPLEMENT_DATA(__type) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(WIN32)
+
+#define PR_EXPORT(__type) extern __declspec(dllexport) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT(__type) __declspec(dllimport) __type
+#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type
+
+#define PR_EXTERN(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT(__type) __declspec(dllexport) __type
+#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(XP_BEOS)
+
+#define PR_EXPORT(__type) extern __declspec(dllexport) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type
+
+#define PR_EXTERN(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT(__type) __declspec(dllexport) __type
+#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(XP_OS2) && defined(__declspec)
+
+#define PR_EXPORT(__type) extern __declspec(dllexport) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT(__type) extern  __declspec(dllimport) __type
+#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type
+
+#define PR_EXTERN(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT(__type) __declspec(dllexport) __type
+#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(SYMBIAN)
+
+#define PR_EXPORT(__type) extern __declspec(dllexport) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+#ifdef __WINS__
+#define PR_IMPORT(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type
+#else
+#define PR_IMPORT(__type) extern __declspec(dllimport) __type
+#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type
+#endif
+
+#define PR_EXTERN(__type) extern __type
+#define PR_IMPLEMENT(__type) __type
+#define PR_EXTERN_DATA(__type) extern __type
+#define PR_IMPLEMENT_DATA(__type) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#else /* Unix */
+
+/* GCC 3.3 and later support the visibility attribute. */
+#if (__GNUC__ >= 4) || \
+    (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+#define PR_VISIBILITY_DEFAULT __attribute__((visibility("default")))
+#else
+#define PR_VISIBILITY_DEFAULT
+#endif
+
+#define PR_EXPORT(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_EXPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPORT(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type
+
+#define PR_EXTERN(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPLEMENT(__type) PR_VISIBILITY_DEFAULT __type
+#define PR_EXTERN_DATA(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPLEMENT_DATA(__type) PR_VISIBILITY_DEFAULT __type
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#endif
+
+#if defined(_NSPR_BUILD_)
+#define NSPR_API(__type) PR_EXPORT(__type)
+#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type)
+#else
+#define NSPR_API(__type) PR_IMPORT(__type)
+#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type)
+#endif
+
+/***********************************************************************
+** MACROS:      PR_BEGIN_MACRO
+**              PR_END_MACRO
+** DESCRIPTION:
+**      Macro body brackets so that macros with compound statement definitions
+**      behave syntactically more like functions when called.
+***********************************************************************/
+#define PR_BEGIN_MACRO  do {
+#define PR_END_MACRO    } while (0)
+
+/***********************************************************************
+** MACROS:      PR_BEGIN_EXTERN_C
+**              PR_END_EXTERN_C
+** DESCRIPTION:
+**      Macro shorthands for conditional C++ extern block delimiters.
+***********************************************************************/
+#ifdef __cplusplus
+#define PR_BEGIN_EXTERN_C       extern "C" {
+#define PR_END_EXTERN_C         }
+#else
+#define PR_BEGIN_EXTERN_C
+#define PR_END_EXTERN_C
+#endif
+
+/***********************************************************************
+** MACROS:      PR_BIT
+**              PR_BITMASK
+** DESCRIPTION:
+** Bit masking macros.  XXX n must be <= 31 to be portable
+***********************************************************************/
+#define PR_BIT(n)       ((PRUint32)1 << (n))
+#define PR_BITMASK(n)   (PR_BIT(n) - 1)
+
+/***********************************************************************
+** MACROS:      PR_ROUNDUP
+**              PR_MIN
+**              PR_MAX
+**              PR_ABS
+** DESCRIPTION:
+**      Commonly used macros for operations on compatible types.
+***********************************************************************/
+#define PR_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y))
+#define PR_MIN(x,y)     ((x)<(y)?(x):(y))
+#define PR_MAX(x,y)     ((x)>(y)?(x):(y))
+#define PR_ABS(x)       ((x)<0?-(x):(x))
+
+PR_BEGIN_EXTERN_C
+
+/************************************************************************
+** TYPES:       PRUint8
+**              PRInt8
+** DESCRIPTION:
+**  The int8 types are known to be 8 bits each. There is no type that
+**      is equivalent to a plain "char". 
+************************************************************************/
+#if PR_BYTES_PER_BYTE == 1
+typedef unsigned char PRUint8;
+/*
+** Some cfront-based C++ compilers do not like 'signed char' and
+** issue the warning message:
+**     warning: "signed" not implemented (ignored)
+** For these compilers, we have to define PRInt8 as plain 'char'.
+** Make sure that plain 'char' is indeed signed under these compilers.
+*/
+#if (defined(HPUX) && defined(__cplusplus) \
+        && !defined(__GNUC__) && __cplusplus < 199707L) \
+    || (defined(SCO) && defined(__cplusplus) \
+        && !defined(__GNUC__) && __cplusplus == 1L)
+typedef char PRInt8;
+#else
+typedef signed char PRInt8;
+#endif
+#else
+#error No suitable type for PRInt8/PRUint8
+#endif
+
+/************************************************************************
+ * MACROS:      PR_INT8_MAX
+ *              PR_INT8_MIN
+ *              PR_UINT8_MAX
+ * DESCRIPTION:
+ *  The maximum and minimum values of a PRInt8 or PRUint8.
+************************************************************************/
+
+#define PR_INT8_MAX 127
+#define PR_INT8_MIN (-128)
+#define PR_UINT8_MAX 255U
+
+/************************************************************************
+** TYPES:       PRUint16
+**              PRInt16
+** DESCRIPTION:
+**  The int16 types are known to be 16 bits each. 
+************************************************************************/
+#if PR_BYTES_PER_SHORT == 2
+typedef unsigned short PRUint16;
+typedef short PRInt16;
+#else
+#error No suitable type for PRInt16/PRUint16
+#endif
+
+/************************************************************************
+ * MACROS:      PR_INT16_MAX
+ *              PR_INT16_MIN
+ *              PR_UINT16_MAX
+ * DESCRIPTION:
+ *  The maximum and minimum values of a PRInt16 or PRUint16.
+************************************************************************/
+
+#define PR_INT16_MAX 32767
+#define PR_INT16_MIN (-32768)
+#define PR_UINT16_MAX 65535U
+
+/************************************************************************
+** TYPES:       PRUint32
+**              PRInt32
+** DESCRIPTION:
+**  The int32 types are known to be 32 bits each. 
+************************************************************************/
+#if PR_BYTES_PER_INT == 4
+typedef unsigned int PRUint32;
+typedef int PRInt32;
+#define PR_INT32(x)  x
+#define PR_UINT32(x) x ## U
+#elif PR_BYTES_PER_LONG == 4
+typedef unsigned long PRUint32;
+typedef long PRInt32;
+#define PR_INT32(x)  x ## L
+#define PR_UINT32(x) x ## UL
+#else
+#error No suitable type for PRInt32/PRUint32
+#endif
+
+/************************************************************************
+ * MACROS:      PR_INT32_MAX
+ *              PR_INT32_MIN
+ *              PR_UINT32_MAX
+ * DESCRIPTION:
+ *  The maximum and minimum values of a PRInt32 or PRUint32.
+************************************************************************/
+
+#define PR_INT32_MAX PR_INT32(2147483647)
+#define PR_INT32_MIN (-PR_INT32_MAX - 1)
+#define PR_UINT32_MAX PR_UINT32(4294967295)
+
+/************************************************************************
+** TYPES:       PRUint64
+**              PRInt64
+** DESCRIPTION:
+**  The int64 types are known to be 64 bits each. Care must be used when
+**      declaring variables of type PRUint64 or PRInt64. Different hardware
+**      architectures and even different compilers have varying support for
+**      64 bit values. The only guaranteed portability requires the use of
+**      the LL_ macros (see prlong.h).
+************************************************************************/
+#ifdef HAVE_LONG_LONG
+/* Keep this in sync with prlong.h. */
+/*
+ * On 64-bit Mac OS X, uint64 needs to be defined as unsigned long long to
+ * match uint64_t, otherwise our uint64 typedef conflicts with the uint64
+ * typedef in cssmconfig.h, which CoreServices.h includes indirectly.
+ */
+#if PR_BYTES_PER_LONG == 8 && !defined(__APPLE__)
+typedef long PRInt64;
+typedef unsigned long PRUint64;
+#elif defined(WIN32) && !defined(__GNUC__)
+typedef __int64  PRInt64;
+typedef unsigned __int64 PRUint64;
+#else
+typedef long long PRInt64;
+typedef unsigned long long PRUint64;
+#endif /* PR_BYTES_PER_LONG == 8 */
+#else  /* !HAVE_LONG_LONG */
+typedef struct {
+#ifdef IS_LITTLE_ENDIAN
+    PRUint32 lo, hi;
+#else
+    PRUint32 hi, lo;
+#endif
+} PRInt64;
+typedef PRInt64 PRUint64;
+#endif /* !HAVE_LONG_LONG */
+
+/************************************************************************
+** TYPES:       PRUintn
+**              PRIntn
+** DESCRIPTION:
+**  The PRIntn types are most appropriate for automatic variables. They are
+**      guaranteed to be at least 16 bits, though various architectures may
+**      define them to be wider (e.g., 32 or even 64 bits). These types are
+**      never valid for fields of a structure. 
+************************************************************************/
+#if PR_BYTES_PER_INT >= 2
+typedef int PRIntn;
+typedef unsigned int PRUintn;
+#else
+#error 'sizeof(int)' not sufficient for platform use
+#endif
+
+/************************************************************************
+** TYPES:       PRFloat64
+** DESCRIPTION:
+**  NSPR's floating point type is always 64 bits. 
+************************************************************************/
+typedef double          PRFloat64;
+
+/************************************************************************
+** TYPES:       PRSize
+** DESCRIPTION:
+**  A type for representing the size of objects. 
+************************************************************************/
+typedef size_t PRSize;
+
+
+/************************************************************************
+** TYPES:       PROffset32, PROffset64
+** DESCRIPTION:
+**  A type for representing byte offsets from some location. 
+************************************************************************/
+typedef PRInt32 PROffset32;
+typedef PRInt64 PROffset64;
+
+/************************************************************************
+** TYPES:       PRPtrDiff
+** DESCRIPTION:
+**  A type for pointer difference. Variables of this type are suitable
+**      for storing a pointer or pointer subtraction. 
+************************************************************************/
+typedef ptrdiff_t PRPtrdiff;
+
+/************************************************************************
+** TYPES:       PRUptrdiff
+** DESCRIPTION:
+**  A type for pointer difference. Variables of this type are suitable
+**      for storing a pointer or pointer sutraction. 
+************************************************************************/
+#ifdef _WIN64
+typedef PRUint64 PRUptrdiff;
+#else
+typedef unsigned long PRUptrdiff;
+#endif
+
+/************************************************************************
+** TYPES:       PRBool
+** DESCRIPTION:
+**  Use PRBool for variables and parameter types. Use PR_FALSE and PR_TRUE
+**      for clarity of target type in assignments and actual arguments. Use
+**      'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans
+**      just as you would C int-valued conditions. 
+************************************************************************/
+typedef PRIntn PRBool;
+#define PR_TRUE 1
+#define PR_FALSE 0
+
+/************************************************************************
+** TYPES:       PRPackedBool
+** DESCRIPTION:
+**  Use PRPackedBool within structs where bitfields are not desirable
+**      but minimum and consistant overhead matters.
+************************************************************************/
+typedef PRUint8 PRPackedBool;
+
+/*
+** Status code used by some routines that have a single point of failure or 
+** special status return.
+*/
+typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
+
+#ifndef __PRUNICHAR__
+#define __PRUNICHAR__
+#ifdef WIN32
+typedef wchar_t PRUnichar;
+#else
+typedef PRUint16 PRUnichar;
+#endif
+#endif
+
+/*
+** WARNING: The undocumented data types PRWord and PRUword are
+** only used in the garbage collection and arena code.  Do not
+** use PRWord and PRUword in new code.
+**
+** A PRWord is an integer that is the same size as a void*.
+** It implements the notion of a "word" in the Java Virtual
+** Machine.  (See Sec. 3.4 "Words", The Java Virtual Machine
+** Specification, Addison-Wesley, September 1996.
+** http://java.sun.com/docs/books/vmspec/index.html.)
+*/
+#ifdef _WIN64
+typedef PRInt64 PRWord;
+typedef PRUint64 PRUword;
+#else
+typedef long PRWord;
+typedef unsigned long PRUword;
+#endif
+
+#if defined(NO_NSPR_10_SUPPORT)
+#else
+/********* ???????????????? FIX ME       ??????????????????????????? *****/
+/********************** Some old definitions until pr=>ds transition is done ***/
+/********************** Also, we are still using NSPR 1.0. GC ******************/
+/*
+** Fundamental NSPR macros, used nearly everywhere.
+*/
+
+#define PR_PUBLIC_API		PR_IMPLEMENT
+
+/*
+** Macro body brackets so that macros with compound statement definitions
+** behave syntactically more like functions when called.
+*/
+#define NSPR_BEGIN_MACRO        do {
+#define NSPR_END_MACRO          } while (0)
+
+/*
+** Macro shorthands for conditional C++ extern block delimiters.
+*/
+#ifdef NSPR_BEGIN_EXTERN_C
+#undef NSPR_BEGIN_EXTERN_C
+#endif
+#ifdef NSPR_END_EXTERN_C
+#undef NSPR_END_EXTERN_C
+#endif
+
+#ifdef __cplusplus
+#define NSPR_BEGIN_EXTERN_C     extern "C" {
+#define NSPR_END_EXTERN_C       }
+#else
+#define NSPR_BEGIN_EXTERN_C
+#define NSPR_END_EXTERN_C
+#endif
+
+/********* ????????????? End Fix me ?????????????????????????????? *****/
+#endif /* NO_NSPR_10_SUPPORT */
+
+/*
+** Compile-time assert. "condition" must be a constant expression.
+** The macro can be used only in places where an "extern" declaration is
+** allowed.
+*/
+#define PR_STATIC_ASSERT(condition) \
+    extern void pr_static_assert(int arg[(condition) ? 1 : -1])
+
+PR_END_EXTERN_C
+
+#if !defined(NO_NSPR_10_SUPPORT)
+#include "base/basictypes.h"
+#endif
+
+#endif /* prtypes_h___ */
+
diff --git a/base/third_party/symbolize/DEPS b/base/third_party/symbolize/DEPS
new file mode 100644
index 0000000..73eab50
--- /dev/null
+++ b/base/third_party/symbolize/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+glog",
+]
diff --git a/base/third_party/symbolize/LICENSE b/base/third_party/symbolize/LICENSE
new file mode 100644
index 0000000..433a3d1
--- /dev/null
+++ b/base/third_party/symbolize/LICENSE
@@ -0,0 +1,28 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/third_party/symbolize/README.chromium b/base/third_party/symbolize/README.chromium
new file mode 100644
index 0000000..b86b4e0
--- /dev/null
+++ b/base/third_party/symbolize/README.chromium
@@ -0,0 +1,18 @@
+Name: google-glog's symbolization library
+URL: http://code.google.com/p/google-glog/
+License: BSD
+
+The following files are copied AS-IS from:
+http://code.google.com/p/google-glog/source/browse/#svn/trunk/src (r76)
+
+- demangle.cc
+- demangle.h
+- symbolize.cc
+- symbolize.h
+
+The following files are minimal stubs created for use in Chromium:
+
+- config.h
+- glog/logging.h
+- glog/raw_logging.h
+- utilities.h
diff --git a/base/third_party/symbolize/config.h b/base/third_party/symbolize/config.h
new file mode 100644
index 0000000..945f5a6
--- /dev/null
+++ b/base/third_party/symbolize/config.h
@@ -0,0 +1,7 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define GOOGLE_NAMESPACE google
+#define _END_GOOGLE_NAMESPACE_ }
+#define _START_GOOGLE_NAMESPACE_ namespace google {
diff --git a/base/third_party/symbolize/demangle.cc b/base/third_party/symbolize/demangle.cc
new file mode 100644
index 0000000..46556bf
--- /dev/null
+++ b/base/third_party/symbolize/demangle.cc
@@ -0,0 +1,1231 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+
+#include <stdio.h>  // for NULL
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+typedef struct {
+  const char *abbrev;
+  const char *real_name;
+} AbbrevPair;
+
+// List of operators from Itanium C++ ABI.
+static const AbbrevPair kOperatorList[] = {
+  { "nw", "new" },
+  { "na", "new[]" },
+  { "dl", "delete" },
+  { "da", "delete[]" },
+  { "ps", "+" },
+  { "ng", "-" },
+  { "ad", "&" },
+  { "de", "*" },
+  { "co", "~" },
+  { "pl", "+" },
+  { "mi", "-" },
+  { "ml", "*" },
+  { "dv", "/" },
+  { "rm", "%" },
+  { "an", "&" },
+  { "or", "|" },
+  { "eo", "^" },
+  { "aS", "=" },
+  { "pL", "+=" },
+  { "mI", "-=" },
+  { "mL", "*=" },
+  { "dV", "/=" },
+  { "rM", "%=" },
+  { "aN", "&=" },
+  { "oR", "|=" },
+  { "eO", "^=" },
+  { "ls", "<<" },
+  { "rs", ">>" },
+  { "lS", "<<=" },
+  { "rS", ">>=" },
+  { "eq", "==" },
+  { "ne", "!=" },
+  { "lt", "<" },
+  { "gt", ">" },
+  { "le", "<=" },
+  { "ge", ">=" },
+  { "nt", "!" },
+  { "aa", "&&" },
+  { "oo", "||" },
+  { "pp", "++" },
+  { "mm", "--" },
+  { "cm", "," },
+  { "pm", "->*" },
+  { "pt", "->" },
+  { "cl", "()" },
+  { "ix", "[]" },
+  { "qu", "?" },
+  { "st", "sizeof" },
+  { "sz", "sizeof" },
+  { NULL, NULL },
+};
+
+// List of builtin types from Itanium C++ ABI.
+static const AbbrevPair kBuiltinTypeList[] = {
+  { "v", "void" },
+  { "w", "wchar_t" },
+  { "b", "bool" },
+  { "c", "char" },
+  { "a", "signed char" },
+  { "h", "unsigned char" },
+  { "s", "short" },
+  { "t", "unsigned short" },
+  { "i", "int" },
+  { "j", "unsigned int" },
+  { "l", "long" },
+  { "m", "unsigned long" },
+  { "x", "long long" },
+  { "y", "unsigned long long" },
+  { "n", "__int128" },
+  { "o", "unsigned __int128" },
+  { "f", "float" },
+  { "d", "double" },
+  { "e", "long double" },
+  { "g", "__float128" },
+  { "z", "ellipsis" },
+  { NULL, NULL }
+};
+
+// List of substitutions Itanium C++ ABI.
+static const AbbrevPair kSubstitutionList[] = {
+  { "St", "" },
+  { "Sa", "allocator" },
+  { "Sb", "basic_string" },
+  // std::basic_string<char, std::char_traits<char>,std::allocator<char> >
+  { "Ss", "string"},
+  // std::basic_istream<char, std::char_traits<char> >
+  { "Si", "istream" },
+  // std::basic_ostream<char, std::char_traits<char> >
+  { "So", "ostream" },
+  // std::basic_iostream<char, std::char_traits<char> >
+  { "Sd", "iostream" },
+  { NULL, NULL }
+};
+
+// State needed for demangling.
+typedef struct {
+  const char *mangled_cur;  // Cursor of mangled name.
+  const char *mangled_end;  // End of mangled name.
+  char *out_cur;            // Cursor of output string.
+  const char *out_begin;    // Beginning of output string.
+  const char *out_end;      // End of output string.
+  const char *prev_name;    // For constructors/destructors.
+  int prev_name_length;     // For constructors/destructors.
+  int nest_level;           // For nested names.
+  int number;               // Remember the previous number.
+  bool append;              // Append flag.
+  bool overflowed;          // True if output gets overflowed.
+} State;
+
+// We don't use strlen() in libc since it's not guaranteed to be async
+// signal safe.
+static size_t StrLen(const char *str) {
+  size_t len = 0;
+  while (*str != '\0') {
+    ++str;
+    ++len;
+  }
+  return len;
+}
+
+// Returns true if "str" has "prefix" as a prefix.
+static bool StrPrefix(const char *str, const char *prefix) {
+  size_t i = 0;
+  while (str[i] != '\0' && prefix[i] != '\0' &&
+         str[i] == prefix[i]) {
+    ++i;
+  }
+  return prefix[i] == '\0';  // Consumed everything in "prefix".
+}
+
+static void InitState(State *state, const char *mangled,
+                      char *out, int out_size) {
+  state->mangled_cur = mangled;
+  state->mangled_end = mangled + StrLen(mangled);
+  state->out_cur = out;
+  state->out_begin = out;
+  state->out_end = out + out_size;
+  state->prev_name  = NULL;
+  state->prev_name_length = -1;
+  state->nest_level = -1;
+  state->number = -1;
+  state->append = true;
+  state->overflowed = false;
+}
+
+// Calculates the remaining length of the mangled name.
+static int RemainingLength(State *state) {
+  return state->mangled_end - state->mangled_cur;
+}
+
+// Returns true and advances "mangled_cur" if we find "c" at
+// "mangled_cur" position.
+static bool ParseChar(State *state, const char c) {
+  if (RemainingLength(state) >= 1 && *state->mangled_cur == c) {
+    ++state->mangled_cur;
+    return true;
+  }
+  return false;
+}
+
+// Returns true and advances "mangled_cur" if we find "two_chars" at
+// "mangled_cur" position.
+static bool ParseTwoChar(State *state, const char *two_chars) {
+  if (RemainingLength(state) >= 2 &&
+      state->mangled_cur[0] == two_chars[0] &&
+      state->mangled_cur[1] == two_chars[1]) {
+    state->mangled_cur += 2;
+    return true;
+  }
+  return false;
+}
+
+// Returns true and advances "mangled_cur" if we find any character in
+// "char_class" at "mangled_cur" position.
+static bool ParseCharClass(State *state, const char *char_class) {
+  if (state->mangled_cur == state->mangled_end) {
+    return false;
+  }
+  const char *p = char_class;
+  for (; *p != '\0'; ++p) {
+    if (*state->mangled_cur == *p) {
+      state->mangled_cur += 1;
+      return true;
+    }
+  }
+  return false;
+}
+
+// This function is used for handling an optional non-terminal.
+static bool Optional(bool status) {
+  return true;
+}
+
+// This function is used for handling <non-terminal>+ syntax.
+typedef bool (*ParseFunc)(State *);
+static bool OneOrMore(ParseFunc parse_func, State *state) {
+  if (parse_func(state)) {
+    while (parse_func(state)) {
+    }
+    return true;
+  }
+  return false;
+}
+
+// Append "str" at "out_cur".  If there is an overflow, "overflowed"
+// is set to true for later use.  The output string is ensured to
+// always terminate with '\0' as long as there is no overflow.
+static void Append(State *state, const char * const str, const int length) {
+  int i;
+  for (i = 0; i < length; ++i) {
+    if (state->out_cur + 1 < state->out_end) {  // +1 for '\0'
+      *state->out_cur = str[i];
+      ++state->out_cur;
+    } else {
+      state->overflowed = true;
+      break;
+    }
+  }
+  if (!state->overflowed) {
+    *state->out_cur = '\0';  // Terminate it with '\0'
+  }
+}
+
+// We don't use equivalents in libc to avoid locale issues.
+static bool IsLower(char c) {
+  return c >= 'a' && c <= 'z';
+}
+
+static bool IsAlpha(char c) {
+  return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+}
+
+// Append "str" with some tweaks, iff "append" state is true.
+// Returns true so that it can be placed in "if" conditions.
+static void MaybeAppendWithLength(State *state, const char * const str,
+                                  const int length) {
+  if (state->append && length > 0) {
+    // Append a space if the output buffer ends with '<' and "str"
+    // starts with '<' to avoid <<<.
+    if (str[0] == '<' && state->out_begin < state->out_cur  &&
+        state->out_cur[-1] == '<') {
+      Append(state, " ", 1);
+    }
+    // Remember the last identifier name for ctors/dtors.
+    if (IsAlpha(str[0]) || str[0] == '_') {
+      state->prev_name = state->out_cur;
+      state->prev_name_length = length;
+    }
+    Append(state, str, length);
+  }
+}
+
+// A convenient wrapper arount MaybeAppendWithLength().
+static bool MaybeAppend(State *state, const char * const str) {
+  if (state->append) {
+    int length = StrLen(str);
+    MaybeAppendWithLength(state, str, length);
+  }
+  return true;
+}
+
+// This function is used for handling nested names.
+static bool EnterNestedName(State *state) {
+  state->nest_level = 0;
+  return true;
+}
+
+// This function is used for handling nested names.
+static bool LeaveNestedName(State *state, int prev_value) {
+  state->nest_level = prev_value;
+  return true;
+}
+
+// Disable the append mode not to print function parameters, etc.
+static bool DisableAppend(State *state) {
+  state->append = false;
+  return true;
+}
+
+// Restore the append mode to the previous state.
+static bool RestoreAppend(State *state, bool prev_value) {
+  state->append = prev_value;
+  return true;
+}
+
+// Increase the nest level for nested names.
+static void MaybeIncreaseNestLevel(State *state) {
+  if (state->nest_level > -1) {
+    ++state->nest_level;
+  }
+}
+
+// Appends :: for nested names if necessary.
+static void MaybeAppendSeparator(State *state) {
+  if (state->nest_level >= 1) {
+    MaybeAppend(state, "::");
+  }
+}
+
+// Cancel the last separator if necessary.
+static void MaybeCancelLastSeparator(State *state) {
+  if (state->nest_level >= 1 && state->append &&
+      state->out_begin <= state->out_cur - 2) {
+    state->out_cur -= 2;
+    *state->out_cur = '\0';
+  }
+}
+
+// Returns true if identifier pointed by "mangled_cur" is anonymous
+// namespace.
+static bool IdentifierIsAnonymousNamespace(State *state) {
+  const char anon_prefix[] = "_GLOBAL__N_";
+  return (state->number > sizeof(anon_prefix) - 1 &&  // Should be longer.
+          StrPrefix(state->mangled_cur, anon_prefix));
+}
+
+// Forward declarations of our parsing functions.
+static bool ParseMangledName(State *state);
+static bool ParseEncoding(State *state);
+static bool ParseName(State *state);
+static bool ParseUnscopedName(State *state);
+static bool ParseUnscopedTemplateName(State *state);
+static bool ParseNestedName(State *state);
+static bool ParsePrefix(State *state);
+static bool ParseUnqualifiedName(State *state);
+static bool ParseSourceName(State *state);
+static bool ParseLocalSourceName(State *state);
+static bool ParseNumber(State *state);
+static bool ParseFloatNumber(State *state);
+static bool ParseSeqId(State *state);
+static bool ParseIdentifier(State *state);
+static bool ParseOperatorName(State *state);
+static bool ParseSpecialName(State *state);
+static bool ParseCallOffset(State *state);
+static bool ParseNVOffset(State *state);
+static bool ParseVOffset(State *state);
+static bool ParseCtorDtorName(State *state);
+static bool ParseType(State *state);
+static bool ParseCVQualifiers(State *state);
+static bool ParseBuiltinType(State *state);
+static bool ParseFunctionType(State *state);
+static bool ParseBareFunctionType(State *state);
+static bool ParseClassEnumType(State *state);
+static bool ParseArrayType(State *state);
+static bool ParsePointerToMemberType(State *state);
+static bool ParseTemplateParam(State *state);
+static bool ParseTemplateTemplateParam(State *state);
+static bool ParseTemplateArgs(State *state);
+static bool ParseTemplateArg(State *state);
+static bool ParseExpression(State *state);
+static bool ParseExprPrimary(State *state);
+static bool ParseLocalName(State *state);
+static bool ParseDiscriminator(State *state);
+static bool ParseSubstitution(State *state);
+
+// Implementation note: the following code is a straightforward
+// translation of the Itanium C++ ABI defined in BNF with a couple of
+// exceptions.
+//
+// - Support GNU extensions not defined in the Itanium C++ ABI
+// - <prefix> and <template-prefix> are combined to avoid infinite loop
+// - Reorder patterns to shorten the code
+// - Reorder patterns to give greedier functions precedence
+//   We'll mark "Less greedy than" for these cases in the code
+//
+// Each parsing function changes the state and returns true on
+// success.  Otherwise, don't change the state and returns false.  To
+// ensure that the state isn't changed in the latter case, we save the
+// original state before we call more than one parsing functions
+// consecutively with &&, and restore the state if unsuccessful.  See
+// ParseEncoding() as an example of this convention.  We follow the
+// convention throughout the code.
+//
+// Originally we tried to do demangling without following the full ABI
+// syntax but it turned out we needed to follow the full syntax to
+// parse complicated cases like nested template arguments.  Note that
+// implementing a full-fledged demangler isn't trivial (libiberty's
+// cp-demangle.c has +4300 lines).
+//
+// Note that (foo) in <(foo) ...> is a modifier to be ignored.
+//
+// Reference:
+// - Itanium C++ ABI
+//   <http://www.codesourcery.com/cxx-abi/abi.html#mangling>
+
+// <mangled-name> ::= _Z <encoding>
+static bool ParseMangledName(State *state) {
+  if (ParseTwoChar(state, "_Z") && ParseEncoding(state)) {
+    // Append trailing version suffix if any.
+    // ex. _Z3foo@@GLIBCXX_3.4
+    if (state->mangled_cur < state->mangled_end &&
+        state->mangled_cur[0] == '@') {
+      MaybeAppend(state, state->mangled_cur);
+      state->mangled_cur = state->mangled_end;
+    }
+    return true;
+  }
+  return false;
+}
+
+// <encoding> ::= <(function) name> <bare-function-type>
+//            ::= <(data) name>
+//            ::= <special-name>
+static bool ParseEncoding(State *state) {
+  State copy = *state;
+  if (ParseName(state) && ParseBareFunctionType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseName(state) || ParseSpecialName(state)) {
+    return true;
+  }
+  return false;
+}
+
+// <name> ::= <nested-name>
+//        ::= <unscoped-template-name> <template-args>
+//        ::= <unscoped-name>
+//        ::= <local-name>
+static bool ParseName(State *state) {
+  if (ParseNestedName(state) || ParseLocalName(state)) {
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseUnscopedTemplateName(state) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // Less greedy than <unscoped-template-name> <template-args>.
+  if (ParseUnscopedName(state)) {
+    return true;
+  }
+  return false;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+//                 ::= St <unqualified-name>
+static bool ParseUnscopedName(State *state) {
+  if (ParseUnqualifiedName(state)) {
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseTwoChar(state, "St") &&
+      MaybeAppend(state, "std::") &&
+      ParseUnqualifiedName(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <unscoped-template-name> ::= <unscoped-name>
+//                          ::= <substitution>
+static bool ParseUnscopedTemplateName(State *state) {
+  return ParseUnscopedName(state) || ParseSubstitution(state);
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+//               ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+static bool ParseNestedName(State *state) {
+  State copy = *state;
+  if (ParseChar(state, 'N') &&
+      EnterNestedName(state) &&
+      Optional(ParseCVQualifiers(state)) &&
+      ParsePrefix(state) &&
+      LeaveNestedName(state, copy.nest_level) &&
+      ParseChar(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// This part is tricky.  If we literally translate them to code, we'll
+// end up infinite loop.  Hence we merge them to avoid the case.
+//
+// <prefix> ::= <prefix> <unqualified-name>
+//          ::= <template-prefix> <template-args>
+//          ::= <template-param>
+//          ::= <substitution>
+//          ::= # empty
+// <template-prefix> ::= <prefix> <(template) unqualified-name>
+//                   ::= <template-param>
+//                   ::= <substitution>
+static bool ParsePrefix(State *state) {
+  bool has_something = false;
+  while (true) {
+    MaybeAppendSeparator(state);
+    if (ParseTemplateParam(state) ||
+        ParseSubstitution(state) ||
+        ParseUnscopedName(state)) {
+      has_something = true;
+      MaybeIncreaseNestLevel(state);
+      continue;
+    }
+    MaybeCancelLastSeparator(state);
+    if (has_something && ParseTemplateArgs(state)) {
+      return ParsePrefix(state);
+    } else {
+      break;
+    }
+  }
+  return true;
+}
+
+// <unqualified-name> ::= <operator-name>
+//                    ::= <ctor-dtor-name>
+//                    ::= <source-name>
+//                    ::= <local-source-name>
+static bool ParseUnqualifiedName(State *state) {
+  return (ParseOperatorName(state) ||
+          ParseCtorDtorName(state) ||
+          ParseSourceName(state) ||
+          ParseLocalSourceName(state));
+}
+
+// <source-name> ::= <positive length number> <identifier>
+static bool ParseSourceName(State *state) {
+  State copy = *state;
+  if (ParseNumber(state) && ParseIdentifier(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <local-source-name> ::= L <source-name> [<discriminator>]
+//
+// References:
+//   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
+//   http://gcc.gnu.org/viewcvs?view=rev&revision=124467
+static bool ParseLocalSourceName(State *state) {
+  State copy = *state;
+  if (ParseChar(state, 'L') && ParseSourceName(state) &&
+      Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+static bool ParseNumber(State *state) {
+  int sign = 1;
+  if (ParseChar(state, 'n')) {
+    sign = -1;
+  }
+  const char *p = state->mangled_cur;
+  int number = 0;
+  for (;p < state->mangled_end; ++p) {
+    if ((*p >= '0' && *p <= '9')) {
+      number = number * 10 + (*p - '0');
+    } else {
+      break;
+    }
+  }
+  if (p != state->mangled_cur) {  // Conversion succeeded.
+    state->mangled_cur = p;
+    state->number = number * sign;
+    return true;
+  }
+  return false;
+}
+
+// Floating-point literals are encoded using a fixed-length lowercase
+// hexadecimal string.
+static bool ParseFloatNumber(State *state) {
+  const char *p = state->mangled_cur;
+  int number = 0;
+  for (;p < state->mangled_end; ++p) {
+    if ((*p >= '0' && *p <= '9')) {
+      number = number * 16 + (*p - '0');
+    } else if (*p >= 'a' && *p <= 'f') {
+      number = number * 16 + (*p - 'a' + 10);
+    } else {
+      break;
+    }
+  }
+  if (p != state->mangled_cur) {  // Conversion succeeded.
+    state->mangled_cur = p;
+    state->number = number;
+    return true;
+  }
+  return false;
+}
+
+// The <seq-id> is a sequence number in base 36,
+// using digits and upper case letters
+static bool ParseSeqId(State *state) {
+  const char *p = state->mangled_cur;
+  int number = 0;
+  for (;p < state->mangled_end; ++p) {
+    if ((*p >= '0' && *p <= '9')) {
+      number = number * 36 + (*p - '0');
+    } else if (*p >= 'A' && *p <= 'Z') {
+      number = number * 36 + (*p - 'A' + 10);
+    } else {
+      break;
+    }
+  }
+  if (p != state->mangled_cur) {  // Conversion succeeded.
+    state->mangled_cur = p;
+    state->number = number;
+    return true;
+  }
+  return false;
+}
+
+// <identifier> ::= <unqualified source code identifier>
+static bool ParseIdentifier(State *state) {
+  if (state->number == -1 ||
+      RemainingLength(state) < state->number) {
+    return false;
+  }
+  if (IdentifierIsAnonymousNamespace(state)) {
+    MaybeAppend(state, "(anonymous namespace)");
+  } else {
+    MaybeAppendWithLength(state, state->mangled_cur, state->number);
+  }
+  state->mangled_cur += state->number;
+  state->number = -1;  // Reset the number.
+  return true;
+}
+
+// <operator-name> ::= nw, and other two letters cases
+//                 ::= cv <type>  # (cast)
+//                 ::= v  <digit> <source-name> # vendor extended operator
+static bool ParseOperatorName(State *state) {
+  if (RemainingLength(state) < 2) {
+    return false;
+  }
+  // First check with "cv" (cast) case.
+  State copy = *state;
+  if (ParseTwoChar(state, "cv") &&
+      MaybeAppend(state, "operator ") &&
+      EnterNestedName(state) &&
+      ParseType(state) &&
+      LeaveNestedName(state, copy.nest_level)) {
+    return true;
+  }
+  *state = copy;
+
+  // Then vendor extended operators.
+  if (ParseChar(state, 'v') && ParseCharClass(state, "0123456789") &&
+      ParseSourceName(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // Other operator names should start with a lower alphabet followed
+  // by a lower/upper alphabet.
+  if (!(IsLower(state->mangled_cur[0]) &&
+        IsAlpha(state->mangled_cur[1]))) {
+    return false;
+  }
+  // We may want to perform a binary search if we really need speed.
+  const AbbrevPair *p;
+  for (p = kOperatorList; p->abbrev != NULL; ++p) {
+    if (state->mangled_cur[0] == p->abbrev[0] &&
+        state->mangled_cur[1] == p->abbrev[1]) {
+      MaybeAppend(state, "operator");
+      if (IsLower(*p->real_name)) {  // new, delete, etc.
+        MaybeAppend(state, " ");
+      }
+      MaybeAppend(state, p->real_name);
+      state->mangled_cur += 2;
+      return true;
+    }
+  }
+  return false;
+}
+
+// <special-name> ::= TV <type>
+//                ::= TT <type>
+//                ::= TI <type>
+//                ::= TS <type>
+//                ::= Tc <call-offset> <call-offset> <(base) encoding>
+//                ::= GV <(object) name>
+//                ::= T <call-offset> <(base) encoding>
+// G++ extensions:
+//                ::= TC <type> <(offset) number> _ <(base) type>
+//                ::= TF <type>
+//                ::= TJ <type>
+//                ::= GR <name>
+//                ::= GA <encoding>
+//                ::= Th <call-offset> <(base) encoding>
+//                ::= Tv <call-offset> <(base) encoding>
+//
+// Note: we don't care much about them since they don't appear in
+// stack traces.  The are special data.
+static bool ParseSpecialName(State *state) {
+  State copy = *state;
+  if (ParseChar(state, 'T') &&
+      ParseCharClass(state, "VTIS") &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoChar(state, "Tc") && ParseCallOffset(state) &&
+      ParseCallOffset(state) && ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoChar(state, "GV") &&
+      ParseName(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseChar(state, 'T') && ParseCallOffset(state) &&
+      ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // G++ extensions
+  if (ParseTwoChar(state, "TC") && ParseType(state) &&
+      ParseNumber(state) && ParseChar(state, '_') &&
+      DisableAppend(state) &&
+      ParseType(state)) {
+    RestoreAppend(state, copy.append);
+    return true;
+  }
+  *state = copy;
+
+  if (ParseChar(state, 'T') && ParseCharClass(state, "FJ") &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoChar(state, "GR") && ParseName(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoChar(state, "GA") && ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseChar(state, 'T') && ParseCharClass(state, "hv") &&
+      ParseCallOffset(state) && ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <call-offset> ::= h <nv-offset> _
+//               ::= v <v-offset> _
+static bool ParseCallOffset(State *state) {
+  State copy = *state;
+  if (ParseChar(state, 'h') &&
+      ParseNVOffset(state) && ParseChar(state, '_')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseChar(state, 'v') &&
+      ParseVOffset(state) && ParseChar(state, '_')) {
+    return true;
+  }
+  *state = copy;
+
+  return false;
+}
+
+// <nv-offset> ::= <(offset) number>
+static bool ParseNVOffset(State *state) {
+  return ParseNumber(state);
+}
+
+// <v-offset>  ::= <(offset) number> _ <(virtual offset) number>
+static bool ParseVOffset(State *state) {
+  State copy = *state;
+  if (ParseNumber(state) && ParseChar(state, '_') &&
+      ParseNumber(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <ctor-dtor-name> ::= C1 | C2 | C3
+//                  ::= D0 | D1 | D2
+static bool ParseCtorDtorName(State *state) {
+  State copy = *state;
+  if (ParseChar(state, 'C') &&
+      ParseCharClass(state, "123")) {
+    const char * const prev_name = state->prev_name;
+    const int prev_name_length = state->prev_name_length;
+    MaybeAppendWithLength(state, prev_name, prev_name_length);
+    return true;
+  }
+  *state = copy;
+
+  if (ParseChar(state, 'D') &&
+      ParseCharClass(state, "012")) {
+    const char * const prev_name = state->prev_name;
+    const int prev_name_length = state->prev_name_length;
+    MaybeAppend(state, "~");
+    MaybeAppendWithLength(state, prev_name, prev_name_length);
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <type> ::= <CV-qualifiers> <type>
+//        ::= P <type>
+//        ::= R <type>
+//        ::= C <type>
+//        ::= G <type>
+//        ::= U <source-name> <type>
+//        ::= <builtin-type>
+//        ::= <function-type>
+//        ::= <class-enum-type>
+//        ::= <array-type>
+//        ::= <pointer-to-member-type>
+//        ::= <template-template-param> <template-args>
+//        ::= <template-param>
+//        ::= <substitution>
+static bool ParseType(State *state) {
+  // We should check CV-qualifers, and PRGC things first.
+  State copy = *state;
+  if (ParseCVQualifiers(state) && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseCharClass(state, "PRCG") && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseChar(state, 'U') && ParseSourceName(state) &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseBuiltinType(state) ||
+      ParseFunctionType(state) ||
+      ParseClassEnumType(state) ||
+      ParseArrayType(state) ||
+      ParsePointerToMemberType(state) ||
+      ParseSubstitution(state)) {
+    return true;
+  }
+
+  if (ParseTemplateTemplateParam(state) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // Less greedy than <template-template-param> <template-args>.
+  if (ParseTemplateParam(state)) {
+    return true;
+  }
+
+  return false;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+// We don't allow empty <CV-qualifiers> to avoid infinite loop in
+// ParseType().
+static bool ParseCVQualifiers(State *state) {
+  int num_cv_qualifiers = 0;
+  num_cv_qualifiers += ParseChar(state, 'r');
+  num_cv_qualifiers += ParseChar(state, 'V');
+  num_cv_qualifiers += ParseChar(state, 'K');
+  return num_cv_qualifiers > 0;
+}
+
+// <builtin-type> ::= v, etc.
+//                ::= u <source-name>
+static bool ParseBuiltinType(State *state) {
+  const AbbrevPair *p;
+  for (p = kBuiltinTypeList; p->abbrev != NULL; ++p) {
+    if (state->mangled_cur[0] == p->abbrev[0]) {
+      MaybeAppend(state, p->real_name);
+      ++state->mangled_cur;
+      return true;
+    }
+  }
+
+  State copy = *state;
+  if (ParseChar(state, 'u') && ParseSourceName(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <function-type> ::= F [Y] <bare-function-type> E
+static bool ParseFunctionType(State *state) {
+  State copy = *state;
+  if (ParseChar(state, 'F') && Optional(ParseChar(state, 'Y')) &&
+      ParseBareFunctionType(state) && ParseChar(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <bare-function-type> ::= <(signature) type>+
+static bool ParseBareFunctionType(State *state) {
+  State copy = *state;
+  DisableAppend(state);
+  if (OneOrMore(ParseType, state)) {
+    RestoreAppend(state, copy.append);
+    MaybeAppend(state, "()");
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <class-enum-type> ::= <name>
+static bool ParseClassEnumType(State *state) {
+  return ParseName(state);
+}
+
+// <array-type> ::= A <(positive dimension) number> _ <(element) type>
+//              ::= A [<(dimension) expression>] _ <(element) type>
+static bool ParseArrayType(State *state) {
+  State copy = *state;
+  if (ParseChar(state, 'A') && ParseNumber(state) &&
+      ParseChar(state, '_') && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseChar(state, 'A') && Optional(ParseExpression(state)) &&
+      ParseChar(state, '_') && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <pointer-to-member-type> ::= M <(class) type> <(member) type>
+static bool ParsePointerToMemberType(State *state) {
+  State copy = *state;
+  if (ParseChar(state, 'M') && ParseType(state) &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <template-param> ::= T_
+//                  ::= T <parameter-2 non-negative number> _
+static bool ParseTemplateParam(State *state) {
+  if (ParseTwoChar(state, "T_")) {
+    MaybeAppend(state, "?");  // We don't support template substitutions.
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseChar(state, 'T') && ParseNumber(state) &&
+      ParseChar(state, '_')) {
+    MaybeAppend(state, "?");  // We don't support template substitutions.
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+
+// <template-template-param> ::= <template-param>
+//                           ::= <substitution>
+static bool ParseTemplateTemplateParam(State *state) {
+  return (ParseTemplateParam(state) ||
+          ParseSubstitution(state));
+}
+
+// <template-args> ::= I <template-arg>+ E
+static bool ParseTemplateArgs(State *state) {
+  State copy = *state;
+  DisableAppend(state);
+  if (ParseChar(state, 'I') &&
+      OneOrMore(ParseTemplateArg, state) &&
+      ParseChar(state, 'E')) {
+    RestoreAppend(state, copy.append);
+    MaybeAppend(state, "<>");
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <template-arg>  ::= <type>
+//                 ::= <expr-primary>
+//                 ::= X <expression> E
+static bool ParseTemplateArg(State *state) {
+  if (ParseType(state) ||
+      ParseExprPrimary(state)) {
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseChar(state, 'X') && ParseExpression(state) &&
+      ParseChar(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <expression> ::= <template-param>
+//              ::= <expr-primary>
+//              ::= <unary operator-name> <expression>
+//              ::= <binary operator-name> <expression> <expression>
+//              ::= <trinary operator-name> <expression> <expression>
+//                  <expression>
+//              ::= st <type>
+//              ::= sr <type> <unqualified-name> <template-args>
+//              ::= sr <type> <unqualified-name>
+static bool ParseExpression(State *state) {
+  if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseOperatorName(state) &&
+      ParseExpression(state) &&
+      ParseExpression(state) &&
+      ParseExpression(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOperatorName(state) &&
+      ParseExpression(state) &&
+      ParseExpression(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOperatorName(state) &&
+      ParseExpression(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoChar(state, "st") && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoChar(state, "sr") && ParseType(state) &&
+      ParseUnqualifiedName(state) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoChar(state, "sr") && ParseType(state) &&
+      ParseUnqualifiedName(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <expr-primary> ::= L <type> <(value) number> E
+//                ::= L <type> <(value) float> E
+//                ::= L <mangled-name> E
+//                // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
+//                ::= LZ <encoding> E
+static bool ParseExprPrimary(State *state) {
+  State copy = *state;
+  if (ParseChar(state, 'L') && ParseType(state) &&
+      ParseNumber(state) &&
+      ParseChar(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseChar(state, 'L') && ParseType(state) &&
+      ParseFloatNumber(state) &&
+      ParseChar(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseChar(state, 'L') && ParseMangledName(state) &&
+      ParseChar(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoChar(state, "LZ") && ParseEncoding(state) &&
+      ParseChar(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  return false;
+}
+
+// <local-name> := Z <(function) encoding> E <(entity) name>
+//                 [<discriminator>]
+//              := Z <(function) encoding> E s [<discriminator>]
+static bool ParseLocalName(State *state) {
+  State copy = *state;
+  if (ParseChar(state, 'Z') && ParseEncoding(state) &&
+      ParseChar(state, 'E') && MaybeAppend(state, "::") &&
+      ParseName(state) && Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseChar(state, 'Z') && ParseEncoding(state) &&
+      ParseTwoChar(state, "Es") && Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <discriminator> := _ <(non-negative) number>
+static bool ParseDiscriminator(State *state) {
+  State copy = *state;
+  if (ParseChar(state, '_') && ParseNumber(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <substitution> ::= S_
+//                ::= S <seq-id> _
+//                ::= St, etc.
+static bool ParseSubstitution(State *state) {
+  if (ParseTwoChar(state, "S_")) {
+    MaybeAppend(state, "?");  // We don't support substitutions.
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseChar(state, 'S') && ParseSeqId(state) &&
+      ParseChar(state, '_')) {
+    MaybeAppend(state, "?");  // We don't support substitutions.
+    return true;
+  }
+  *state = copy;
+
+  // Expand abbreviations like "St" => "std".
+  if (ParseChar(state, 'S')) {
+    const AbbrevPair *p;
+    for (p = kSubstitutionList; p->abbrev != NULL; ++p) {
+      if (state->mangled_cur[0] == p->abbrev[1]) {
+        MaybeAppend(state, "std");
+        if (p->real_name[0] != '\0') {
+          MaybeAppend(state, "::");
+          MaybeAppend(state, p->real_name);
+        }
+        state->mangled_cur += 1;
+        return true;
+      }
+    }
+  }
+  *state = copy;
+  return false;
+}
+
+// The demangler entry point.
+bool Demangle(const char *mangled, char *out, int out_size) {
+  State state;
+  InitState(&state, mangled, out, out_size);
+  return (ParseMangledName(&state) &&
+          state.overflowed == false &&
+          RemainingLength(&state) == 0);
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/base/third_party/symbolize/demangle.h b/base/third_party/symbolize/demangle.h
new file mode 100644
index 0000000..9c75915
--- /dev/null
+++ b/base/third_party/symbolize/demangle.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
+// (aka G++ V3 ABI).
+
+// The demangler is implemented to be used in async signal handlers to
+// symbolize stack traces.  We cannot use libstdc++'s
+// abi::__cxa_demangle() in such signal handlers since it's not async
+// signal safe (it uses malloc() internally).
+//
+// Note that this demangler doesn't support full demangling.  More
+// specifically, it doesn't print types of function parameters and
+// types of template arguments.  It just skips them.  However, it's
+// still very useful to extract basic information such as class,
+// function, constructor, destructor, and operator names.
+//
+// See the implementation note in demangle.cc if you are interested.
+//
+// Example:
+//
+// | Mangled Name  | The Demangler | abi::__cxa_demangle()
+// |---------------|---------------|-----------------------
+// | _Z1fv         | f()           | f()
+// | _Z1fi         | f()           | f(int)
+// | _Z3foo3bar    | foo()         | foo(bar)
+// | _Z1fIiEvi     | f<>()         | void f<int>(int)
+// | _ZN1N1fE      | N::f          | N::f
+// | _ZN3Foo3BarEv | Foo::Bar()    | Foo::Bar()
+// | _Zrm1XS_"     | operator%()   | operator%(X, X)
+// | _ZN3FooC1Ev   | Foo::Foo()    | Foo::Foo()
+// | _Z1fSs        | f()           | f(std::basic_string<char,
+// |               |               |   std::char_traits<char>,
+// |               |               |   std::allocator<char> >)
+//
+// See the unit test for more examples.
+//
+// Note: we might want to write demanglers for ABIs other than Itanium
+// C++ ABI in the future.
+//
+
+#ifndef BASE_DEMANGLE_H_
+#define BASE_DEMANGLE_H_
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// Demangle "mangled".  On success, return true and write the
+// demangled symbol name to "out".  Otherwise, return false.
+// "out" is modified even if demangling is unsuccessful.
+bool Demangle(const char *mangled, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif  // BASE_DEMANGLE_H_
diff --git a/base/third_party/symbolize/glog/logging.h b/base/third_party/symbolize/glog/logging.h
new file mode 100644
index 0000000..a42c306
--- /dev/null
+++ b/base/third_party/symbolize/glog/logging.h
@@ -0,0 +1,5 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Empty.
diff --git a/base/third_party/symbolize/glog/raw_logging.h b/base/third_party/symbolize/glog/raw_logging.h
new file mode 100644
index 0000000..f5515c4
--- /dev/null
+++ b/base/third_party/symbolize/glog/raw_logging.h
@@ -0,0 +1,6 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define WARNING 1;
+#define RAW_LOG(severity, ...);  // Do nothing.
diff --git a/base/third_party/symbolize/symbolize.cc b/base/third_party/symbolize/symbolize.cc
new file mode 100644
index 0000000..f765fae
--- /dev/null
+++ b/base/third_party/symbolize/symbolize.cc
@@ -0,0 +1,685 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+// Stack-footprint reduction work done by Raksit Ashok
+//
+// Implementation note:
+//
+// We don't use heaps but only use stacks.  We want to reduce the
+// stack consumption so that the symbolizer can run on small stacks.
+//
+// Here are some numbers collected with GCC 4.1.0 on x86:
+// - sizeof(Elf32_Sym)  = 16
+// - sizeof(Elf32_Shdr) = 40
+// - sizeof(Elf64_Sym)  = 24
+// - sizeof(Elf64_Shdr) = 64
+//
+// This implementation is intended to be async-signal-safe but uses
+// some functions which are not guaranteed to be so, such as memchr()
+// and memmove().  We assume they are async-signal-safe.
+//
+
+#include "build/build_config.h"
+#include "utilities.h"
+
+#if defined(HAVE_SYMBOLIZE)
+
+#include <limits>
+
+#include "symbolize.h"
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// We don't use assert() since it's not guaranteed to be
+// async-signal-safe.  Instead we define a minimal assertion
+// macro. So far, we don't need pretty printing for __FILE__, etc.
+
+// A wrapper for abort() to make it callable in ? :.
+static int AssertFail() {
+  abort();
+  return 0;  // Should not reach.
+}
+
+#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
+
+static SymbolizeCallback g_symbolize_callback = NULL;
+void InstallSymbolizeCallback(SymbolizeCallback callback) {
+  g_symbolize_callback = callback;
+}
+
+// This function wraps the Demangle function to provide an interface
+// where the input symbol is demangled in-place.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
+  char demangled[256];  // Big enough for sane demangled symbols.
+  if (Demangle(out, demangled, sizeof(demangled))) {
+    // Demangling succeeded. Copy to out if the space allows.
+    int len = strlen(demangled);
+    if (len + 1 <= out_size) {  // +1 for '\0'.
+      SAFE_ASSERT(len < sizeof(demangled));
+      memmove(out, demangled, len + 1);
+    }
+  }
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#if defined(__ELF__)
+
+#include <dlfcn.h>
+#if defined(OS_OPENBSD)
+#include <sys/exec_elf.h>
+#else
+#include <elf.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "symbolize.h"
+#include "config.h"
+#include "glog/raw_logging.h"
+
+// Re-runs fn until it doesn't cause EINTR.
+#define NO_INTR(fn)   do {} while ((fn) < 0 && errno == EINTR)
+
+_START_GOOGLE_NAMESPACE_
+
+// Read up to "count" bytes from file descriptor "fd" into the buffer
+// starting at "buf" while handling short reads and EINTR.  On
+// success, return the number of bytes read.  Otherwise, return -1.
+static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
+  SAFE_ASSERT(fd >= 0);
+  SAFE_ASSERT(count <= std::numeric_limits<ssize_t>::max());
+  char *buf0 = reinterpret_cast<char *>(buf);
+  ssize_t num_bytes = 0;
+  while (num_bytes < count) {
+    ssize_t len;
+    NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
+    if (len < 0) {  // There was an error other than EINTR.
+      return -1;
+    }
+    if (len == 0) {  // Reached EOF.
+      break;
+    }
+    num_bytes += len;
+  }
+  SAFE_ASSERT(num_bytes <= count);
+  return num_bytes;
+}
+
+// Read up to "count" bytes from "offset" in the file pointed by file
+// descriptor "fd" into the buffer starting at "buf".  On success,
+// return the number of bytes read.  Otherwise, return -1.
+static ssize_t ReadFromOffset(const int fd, void *buf,
+                              const size_t count, const off_t offset) {
+  off_t off = lseek(fd, offset, SEEK_SET);
+  if (off == (off_t)-1) {
+    return -1;
+  }
+  return ReadPersistent(fd, buf, count);
+}
+
+// Try reading exactly "count" bytes from "offset" bytes in a file
+// pointed by "fd" into the buffer starting at "buf" while handling
+// short reads and EINTR.  On success, return true. Otherwise, return
+// false.
+static bool ReadFromOffsetExact(const int fd, void *buf,
+                                const size_t count, const off_t offset) {
+  ssize_t len = ReadFromOffset(fd, buf, count, offset);
+  return len == count;
+}
+
+// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
+static int FileGetElfType(const int fd) {
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return -1;
+  }
+  if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
+    return -1;
+  }
+  return elf_header.e_type;
+}
+
+// Read the section headers in the given ELF binary, and if a section
+// of the specified type is found, set the output to this section header
+// and return true.  Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
+                       ElfW(Word) type, ElfW(Shdr) *out) {
+  // Read at most 16 section headers at a time to save read calls.
+  ElfW(Shdr) buf[16];
+  for (int i = 0; i < sh_num;) {
+    const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
+    const ssize_t num_bytes_to_read =
+        (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
+    const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
+                                       sh_offset + i * sizeof(buf[0]));
+    SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+    const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
+    SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
+    for (int j = 0; j < num_headers_in_buf; ++j) {
+      if (buf[j].sh_type == type) {
+        *out = buf[j];
+        return true;
+      }
+    }
+    i += num_headers_in_buf;
+  }
+  return false;
+}
+
+// There is no particular reason to limit section name to 63 characters,
+// but there has (as yet) been no need for anything longer either.
+const int kMaxSectionNameLen = 64;
+
+// name_len should include terminating '\0'.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+                            ElfW(Shdr) *out) {
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return false;
+  }
+
+  ElfW(Shdr) shstrtab;
+  off_t shstrtab_offset = (elf_header.e_shoff +
+                           elf_header.e_shentsize * elf_header.e_shstrndx);
+  if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
+    return false;
+  }
+
+  for (int i = 0; i < elf_header.e_shnum; ++i) {
+    off_t section_header_offset = (elf_header.e_shoff +
+                                   elf_header.e_shentsize * i);
+    if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
+      return false;
+    }
+    char header_name[kMaxSectionNameLen];
+    if (sizeof(header_name) < name_len) {
+      RAW_LOG(WARNING, "Section name '%s' is too long (%"PRIuS"); "
+              "section will not be found (even if present).", name, name_len);
+      // No point in even trying.
+      return false;
+    }
+    off_t name_offset = shstrtab.sh_offset + out->sh_name;
+    ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
+    if (n_read == -1) {
+      return false;
+    } else if (n_read != name_len) {
+      // Short read -- name could be at end of file.
+      continue;
+    }
+    if (memcmp(header_name, name, name_len) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Read a symbol table and look for the symbol containing the
+// pc. Iterate over symbols in a symbol table and look for the symbol
+// containing "pc".  On success, return true and write the symbol name
+// to out.  Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
+           uint64_t symbol_offset, const ElfW(Shdr) *strtab,
+           const ElfW(Shdr) *symtab) {
+  if (symtab == NULL) {
+    return false;
+  }
+  const int num_symbols = symtab->sh_size / symtab->sh_entsize;
+  for (int i = 0; i < num_symbols;) {
+    off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
+
+    // If we are reading Elf64_Sym's, we want to limit this array to
+    // 32 elements (to keep stack consumption low), otherwise we can
+    // have a 64 element Elf32_Sym array.
+#if __WORDSIZE == 64
+#define NUM_SYMBOLS 32
+#else
+#define NUM_SYMBOLS 64
+#endif
+
+    // Read at most NUM_SYMBOLS symbols at once to save read() calls.
+    ElfW(Sym) buf[NUM_SYMBOLS];
+    const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
+    SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+    const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
+    SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
+    for (int j = 0; j < num_symbols_in_buf; ++j) {
+      const ElfW(Sym)& symbol = buf[j];
+      uint64_t start_address = symbol.st_value;
+      start_address += symbol_offset;
+      uint64_t end_address = start_address + symbol.st_size;
+      if (symbol.st_value != 0 &&  // Skip null value symbols.
+          symbol.st_shndx != 0 &&  // Skip undefined symbols.
+          start_address <= pc && pc < end_address) {
+        ssize_t len1 = ReadFromOffset(fd, out, out_size,
+                                      strtab->sh_offset + symbol.st_name);
+        if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
+          return false;
+        }
+        return true;  // Obtained the symbol name.
+      }
+    }
+    i += num_symbols_in_buf;
+  }
+  return false;
+}
+
+// Get the symbol name of "pc" from the file pointed by "fd".  Process
+// both regular and dynamic symbol tables if necessary.  On success,
+// write the symbol name to "out" and return true.  Otherwise, return
+// false.
+static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
+                                    char *out, int out_size,
+                                    uint64_t map_start_address) {
+  // Read the ELF header.
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return false;
+  }
+
+  uint64_t symbol_offset = 0;
+  if (elf_header.e_type == ET_DYN) {  // DSO needs offset adjustment.
+    symbol_offset = map_start_address;
+  }
+
+  ElfW(Shdr) symtab, strtab;
+
+  // Consult a regular symbol table first.
+  if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+                              SHT_SYMTAB, &symtab)) {
+    return false;
+  }
+  if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+                           symtab.sh_link * sizeof(symtab))) {
+    return false;
+  }
+  if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+                 &strtab, &symtab)) {
+    return true;  // Found the symbol in a regular symbol table.
+  }
+
+  // If the symbol is not found, then consult a dynamic symbol table.
+  if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+                              SHT_DYNSYM, &symtab)) {
+    return false;
+  }
+  if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+                           symtab.sh_link * sizeof(symtab))) {
+    return false;
+  }
+  if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+                 &strtab, &symtab)) {
+    return true;  // Found the symbol in a dynamic symbol table.
+  }
+
+  return false;
+}
+
+namespace {
+// Thin wrapper around a file descriptor so that the file descriptor
+// gets closed for sure.
+struct FileDescriptor {
+  const int fd_;
+  explicit FileDescriptor(int fd) : fd_(fd) {}
+  ~FileDescriptor() {
+    if (fd_ >= 0) {
+      NO_INTR(close(fd_));
+    }
+  }
+  int get() { return fd_; }
+
+ private:
+  explicit FileDescriptor(const FileDescriptor&);
+  void operator=(const FileDescriptor&);
+};
+
+// Helper class for reading lines from file.
+//
+// Note: we don't use ProcMapsIterator since the object is big (it has
+// a 5k array member) and uses async-unsafe functions such as sscanf()
+// and snprintf().
+class LineReader {
+ public:
+  explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
+    buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
+  }
+
+  // Read '\n'-terminated line from file.  On success, modify "bol"
+  // and "eol", then return true.  Otherwise, return false.
+  //
+  // Note: if the last line doesn't end with '\n', the line will be
+  // dropped.  It's an intentional behavior to make the code simple.
+  bool ReadLine(const char **bol, const char **eol) {
+    if (BufferIsEmpty()) {  // First time.
+      const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
+      if (num_bytes <= 0) {  // EOF or error.
+        return false;
+      }
+      eod_ = buf_ + num_bytes;
+      bol_ = buf_;
+    } else {
+      bol_ = eol_ + 1;  // Advance to the next line in the buffer.
+      SAFE_ASSERT(bol_ <= eod_);  // "bol_" can point to "eod_".
+      if (!HasCompleteLine()) {
+        const int incomplete_line_length = eod_ - bol_;
+        // Move the trailing incomplete line to the beginning.
+        memmove(buf_, bol_, incomplete_line_length);
+        // Read text from file and append it.
+        char * const append_pos = buf_ + incomplete_line_length;
+        const int capacity_left = buf_len_ - incomplete_line_length;
+        const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
+                                                 capacity_left);
+        if (num_bytes <= 0) {  // EOF or error.
+          return false;
+        }
+        eod_ = append_pos + num_bytes;
+        bol_ = buf_;
+      }
+    }
+    eol_ = FindLineFeed();
+    if (eol_ == NULL) {  // '\n' not found.  Malformed line.
+      return false;
+    }
+    *eol_ = '\0';  // Replace '\n' with '\0'.
+
+    *bol = bol_;
+    *eol = eol_;
+    return true;
+  }
+
+  // Beginning of line.
+  const char *bol() {
+    return bol_;
+  }
+
+  // End of line.
+  const char *eol() {
+    return eol_;
+  }
+
+ private:
+  explicit LineReader(const LineReader&);
+  void operator=(const LineReader&);
+
+  char *FindLineFeed() {
+    return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
+  }
+
+  bool BufferIsEmpty() {
+    return buf_ == eod_;
+  }
+
+  bool HasCompleteLine() {
+    return !BufferIsEmpty() && FindLineFeed() != NULL;
+  }
+
+  const int fd_;
+  char * const buf_;
+  const int buf_len_;
+  char *bol_;
+  char *eol_;
+  const char *eod_;  // End of data in "buf_".
+};
+}  // namespace
+
+// Place the hex number read from "start" into "*hex".  The pointer to
+// the first non-hex character or "end" is returned.
+static char *GetHex(const char *start, const char *end, uint64_t *hex) {
+  *hex = 0;
+  const char *p;
+  for (p = start; p < end; ++p) {
+    int ch = *p;
+    if ((ch >= '0' && ch <= '9') ||
+        (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
+      *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
+    } else {  // Encountered the first non-hex character.
+      break;
+    }
+  }
+  SAFE_ASSERT(p <= end);
+  return const_cast<char *>(p);
+}
+
+// Search for the object file (from /proc/self/maps) that contains
+// the specified pc. If found, open this file and return the file handle,
+// and also set start_address to the start address of where this object
+// file is mapped to in memory. Otherwise, return -1.
+static ATTRIBUTE_NOINLINE int
+OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
+                                             uint64_t &start_address) {
+  int object_fd;
+
+  // Open /proc/self/maps.
+  int maps_fd;
+  NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
+  FileDescriptor wrapped_maps_fd(maps_fd);
+  if (wrapped_maps_fd.get() < 0) {
+    return -1;
+  }
+
+  // Iterate over maps and look for the map containing the pc.  Then
+  // look into the symbol tables inside.
+  char buf[1024];  // Big enough for line of sane /proc/self/maps
+  LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
+  while (true) {
+    const char *cursor;
+    const char *eol;
+    if (!reader.ReadLine(&cursor, &eol)) {  // EOF or malformed line.
+      return -1;
+    }
+
+    // Start parsing line in /proc/self/maps.  Here is an example:
+    //
+    // 08048000-0804c000 r-xp 00000000 08:01 2142121    /bin/cat
+    //
+    // We want start address (08048000), end address (0804c000), flags
+    // (r-xp) and file name (/bin/cat).
+
+    // Read start address.
+    cursor = GetHex(cursor, eol, &start_address);
+    if (cursor == eol || *cursor != '-') {
+      return -1;  // Malformed line.
+    }
+    ++cursor;  // Skip '-'.
+
+    // Read end address.
+    uint64_t end_address;
+    cursor = GetHex(cursor, eol, &end_address);
+    if (cursor == eol || *cursor != ' ') {
+      return -1;  // Malformed line.
+    }
+    ++cursor;  // Skip ' '.
+
+    // Check start and end addresses.
+    if (!(start_address <= pc && pc < end_address)) {
+      continue;  // We skip this map.  PC isn't in this map.
+    }
+
+    // Read flags.  Skip flags until we encounter a space or eol.
+    const char * const flags_start = cursor;
+    while (cursor < eol && *cursor != ' ') {
+      ++cursor;
+    }
+    // We expect at least four letters for flags (ex. "r-xp").
+    if (cursor == eol || cursor < flags_start + 4) {
+      return -1;  // Malformed line.
+    }
+
+    // Check flags.  We are only interested in "r-x" maps.
+    if (memcmp(flags_start, "r-x", 3) != 0) {  // Not a "r-x" map.
+      continue;  // We skip this map.
+    }
+    ++cursor;  // Skip ' '.
+
+    // Skip to file name.  "cursor" now points to file offset.  We need to
+    // skip at least three spaces for file offset, dev, and inode.
+    int num_spaces = 0;
+    while (cursor < eol) {
+      if (*cursor == ' ') {
+        ++num_spaces;
+      } else if (num_spaces >= 3) {
+        // The first non-space character after  skipping three spaces
+        // is the beginning of the file name.
+        break;
+      }
+      ++cursor;
+    }
+    if (cursor == eol) {
+      return -1;  // Malformed line.
+    }
+
+    // Finally, "cursor" now points to file name of our interest.
+    NO_INTR(object_fd = open(cursor, O_RDONLY));
+    if (object_fd < 0) {
+      return -1;
+    }
+    return object_fd;
+  }
+}
+
+// The implementation of our symbolization routine.  If it
+// successfully finds the symbol containing "pc" and obtains the
+// symbol name, returns true and write the symbol name to "out".
+// Otherwise, returns false. If Callback function is installed via
+// InstallSymbolizeCallback(), the function is also called in this function,
+// and "out" is used as its output.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+                                                    int out_size) {
+  uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
+  uint64_t start_address = 0;
+
+  int object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0,
+                                                               start_address);
+  if (object_fd == -1) {
+    return false;
+  }
+  FileDescriptor wrapped_object_fd(object_fd);
+  int elf_type = FileGetElfType(wrapped_object_fd.get());
+  if (elf_type == -1) {
+    return false;
+  }
+  if (g_symbolize_callback) {
+    // Run the call back if it's installed.
+    // Note: relocation (and much of the rest of this code) will be
+    // wrong for prelinked shared libraries and PIE executables.
+    uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
+    int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
+                                                 pc, out, out_size,
+                                                 relocation);
+    if (num_bytes_written > 0) {
+      out += num_bytes_written;
+      out_size -= num_bytes_written;
+    }
+  }
+  if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
+                               out, out_size, start_address)) {
+    return false;
+  }
+
+  // Symbolization succeeded.  Now we try to demangle the symbol.
+  DemangleInplace(out, out_size);
+  return true;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
+
+#include <dlfcn.h>
+#include <string.h>
+
+_START_GOOGLE_NAMESPACE_
+
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+                                                    int out_size) {
+  Dl_info info;
+  if (dladdr(pc, &info)) {
+    if (strlen(info.dli_sname) < out_size) {
+      strcpy(out, info.dli_sname);
+      // Symbolization succeeded.  Now we try to demangle the symbol.
+      DemangleInplace(out, out_size);
+      return true;
+    }
+  }
+  return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else
+# error BUG: HAVE_SYMBOLIZE was wrongly set
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+bool Symbolize(void *pc, char *out, int out_size) {
+  SAFE_ASSERT(out_size >= 0);
+  return SymbolizeAndDemangle(pc, out, out_size);
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else  /* HAVE_SYMBOLIZE */
+
+#include <assert.h>
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// TODO: Support other environments.
+bool Symbolize(void *pc, char *out, int out_size) {
+  assert(0);
+  return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
diff --git a/base/third_party/symbolize/symbolize.h b/base/third_party/symbolize/symbolize.h
new file mode 100644
index 0000000..441e543
--- /dev/null
+++ b/base/third_party/symbolize/symbolize.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// This library provides Symbolize() function that symbolizes program
+// counters to their corresponding symbol names on linux platforms.
+// This library has a minimal implementation of an ELF symbol table
+// reader (i.e. it doesn't depend on libelf, etc.).
+//
+// The algorithm used in Symbolize() is as follows.
+//
+//   1. Go through a list of maps in /proc/self/maps and find the map
+//   containing the program counter.
+//
+//   2. Open the mapped file and find a regular symbol table inside.
+//   Iterate over symbols in the symbol table and look for the symbol
+//   containing the program counter.  If such a symbol is found,
+//   obtain the symbol name, and demangle the symbol if possible.
+//   If the symbol isn't found in the regular symbol table (binary is
+//   stripped), try the same thing with a dynamic symbol table.
+//
+// Note that Symbolize() is originally implemented to be used in
+// FailureSignalHandler() in base/google.cc.  Hence it doesn't use
+// malloc() and other unsafe operations.  It should be both
+// thread-safe and async-signal-safe.
+
+#ifndef BASE_SYMBOLIZE_H_
+#define BASE_SYMBOLIZE_H_
+
+#include "utilities.h"
+#include "config.h"
+#include "glog/logging.h"
+
+#ifdef HAVE_SYMBOLIZE
+
+#if defined(__ELF__)  // defined by gcc
+#if defined(__OpenBSD__)
+#include <sys/exec_elf.h>
+#else
+#include <elf.h>
+#endif
+
+#if !defined(ANDROID)
+#include <link.h>  // For ElfW() macro.
+#endif
+
+// For systems where SIZEOF_VOID_P is not defined, determine it
+// based on __LP64__ (defined by gcc on 64-bit systems)
+#if !defined(SIZEOF_VOID_P)
+# if defined(__LP64__)
+#  define SIZEOF_VOID_P 8
+# else
+#  define SIZEOF_VOID_P 4
+# endif
+#endif
+
+// If there is no ElfW macro, let's define it by ourself.
+#ifndef ElfW
+# if SIZEOF_VOID_P == 4
+#  define ElfW(type) Elf32_##type
+# elif SIZEOF_VOID_P == 8
+#  define ElfW(type) Elf64_##type
+# else
+#  error "Unknown sizeof(void *)"
+# endif
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Gets the section header for the given name, if it exists. Returns true on
+// success. Otherwise, returns false.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+                            ElfW(Shdr) *out);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif  /* __ELF__ */
+
+_START_GOOGLE_NAMESPACE_
+
+// Installs a callback function, which will be called right before a symbol name
+// is printed. The callback is intended to be used for showing a file name and a
+// line number preceding a symbol name.
+// "fd" is a file descriptor of the object file containing the program
+// counter "pc". The callback function should write output to "out"
+// and return the size of the output written. On error, the callback
+// function should return -1.
+typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size,
+                                 uint64 relocation);
+void InstallSymbolizeCallback(SymbolizeCallback callback);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Symbolizes a program counter.  On success, returns true and write the
+// symbol name to "out".  The symbol name is demangled if possible
+// (supports symbols generated by GCC 3.x or newer).  Otherwise,
+// returns false.
+bool Symbolize(void *pc, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif  // BASE_SYMBOLIZE_H_
diff --git a/base/third_party/symbolize/utilities.h b/base/third_party/symbolize/utilities.h
new file mode 100644
index 0000000..0bed526
--- /dev/null
+++ b/base/third_party/symbolize/utilities.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+typedef uint64_t uint64;
+#define HAVE_SYMBOLIZE 1
+#define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
diff --git a/base/third_party/valgrind/LICENSE b/base/third_party/valgrind/LICENSE
new file mode 100644
index 0000000..41f677b
--- /dev/null
+++ b/base/third_party/valgrind/LICENSE
@@ -0,0 +1,39 @@
+   Notice that the following BSD-style license applies to the Valgrind header
+   files used by Chromium (valgrind.h and memcheck.h). However, the rest of
+   Valgrind is licensed under the terms of the GNU General Public License,
+   version 2, unless otherwise indicated.
+
+   ----------------------------------------------------------------
+
+   Copyright (C) 2000-2008 Julian Seward.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+   2. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/third_party/valgrind/README.chromium b/base/third_party/valgrind/README.chromium
new file mode 100644
index 0000000..56a1cbb
--- /dev/null
+++ b/base/third_party/valgrind/README.chromium
@@ -0,0 +1,11 @@
+Name: valgrind
+URL: http://valgrind.org
+License: BSD
+
+Header files in this directory define runtime macros that determine whether the
+current process is running under Valgrind and tell Memcheck tool about custom
+memory allocators.
+
+These header files were taken from Valgrind source code
+(svn://svn.valgrind.org/valgrind/trunk@11504, dated 21 Jan 2011). The files are
+covered under BSD license as described within.
diff --git a/base/third_party/valgrind/memcheck.h b/base/third_party/valgrind/memcheck.h
new file mode 100644
index 0000000..f59c212
--- /dev/null
+++ b/base/third_party/valgrind/memcheck.h
@@ -0,0 +1,279 @@
+
+/*
+   ----------------------------------------------------------------
+
+   Notice that the following BSD-style license applies to this one
+   file (memcheck.h) only.  The rest of Valgrind is licensed under the
+   terms of the GNU General Public License, version 2, unless
+   otherwise indicated.  See the COPYING file in the source
+   distribution for details.
+
+   ----------------------------------------------------------------
+
+   This file is part of MemCheck, a heavyweight Valgrind tool for
+   detecting memory errors.
+
+   Copyright (C) 2000-2010 Julian Seward.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+   2. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   ----------------------------------------------------------------
+
+   Notice that the above BSD-style license applies to this one file
+   (memcheck.h) only.  The entire rest of Valgrind is licensed under
+   the terms of the GNU General Public License, version 2.  See the
+   COPYING file in the source distribution for details.
+
+   ---------------------------------------------------------------- 
+*/
+
+
+#ifndef __MEMCHECK_H
+#define __MEMCHECK_H
+
+
+/* This file is for inclusion into client (your!) code.
+
+   You can use these macros to manipulate and query memory permissions
+   inside your own programs.
+
+   See comment near the top of valgrind.h on how to use them.
+*/
+
+#include "valgrind.h"
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! 
+   This enum comprises an ABI exported by Valgrind to programs
+   which use client requests.  DO NOT CHANGE THE ORDER OF THESE
+   ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+typedef
+   enum { 
+      VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'),
+      VG_USERREQ__MAKE_MEM_UNDEFINED,
+      VG_USERREQ__MAKE_MEM_DEFINED,
+      VG_USERREQ__DISCARD,
+      VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,
+      VG_USERREQ__CHECK_MEM_IS_DEFINED,
+      VG_USERREQ__DO_LEAK_CHECK,
+      VG_USERREQ__COUNT_LEAKS,
+
+      VG_USERREQ__GET_VBITS,
+      VG_USERREQ__SET_VBITS,
+
+      VG_USERREQ__CREATE_BLOCK,
+
+      VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE,
+
+      /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */
+      VG_USERREQ__COUNT_LEAK_BLOCKS,
+
+      /* This is just for memcheck's internal use - don't use it */
+      _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR 
+         = VG_USERREQ_TOOL_BASE('M','C') + 256
+   } Vg_MemCheckClientRequest;
+
+
+
+/* Client-code macros to manipulate the state of memory. */
+
+/* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len)           \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__MAKE_MEM_NOACCESS,       \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+      
+/* Similarly, mark memory at _qzz_addr as addressable but undefined
+   for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len)          \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__MAKE_MEM_UNDEFINED,      \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Similarly, mark memory at _qzz_addr as addressable and defined
+   for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len)            \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__MAKE_MEM_DEFINED,        \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is
+   not altered: bytes which are addressable are marked as defined,
+   but those which are not addressable are left unchanged. */
+#define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len)     \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,              \
+                            VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Create a block-description handle.  The description is an ascii
+   string which is included in any messages pertaining to addresses
+   within the specified memory range.  Has no other effect on the
+   properties of the memory range. */
+#define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc)	   \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,        \
+                            VG_USERREQ__CREATE_BLOCK,              \
+                            (_qzz_addr), (_qzz_len), (_qzz_desc),  \
+                            0, 0)
+
+/* Discard a block-description-handle. Returns 1 for an
+   invalid handle, 0 for a valid handle. */
+#define VALGRIND_DISCARD(_qzz_blkindex)                          \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__DISCARD,                 \
+                            0, (_qzz_blkindex), 0, 0, 0)
+
+
+/* Client-code macros to check the state of memory. */
+
+/* Check that memory at _qzz_addr is addressable for _qzz_len bytes.
+   If suitable addressibility is not established, Valgrind prints an
+   error message and returns the address of the first offending byte.
+   Otherwise it returns zero. */
+#define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len)      \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                             \
+                            VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,  \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Check that memory at _qzz_addr is addressable and defined for
+   _qzz_len bytes.  If suitable addressibility and definedness are not
+   established, Valgrind prints an error message and returns the
+   address of the first offending byte.  Otherwise it returns zero. */
+#define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len)        \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                           \
+                            VG_USERREQ__CHECK_MEM_IS_DEFINED,    \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Use this macro to force the definedness and addressibility of an
+   lvalue to be checked.  If suitable addressibility and definedness
+   are not established, Valgrind prints an error message and returns
+   the address of the first offending byte.  Otherwise it returns
+   zero. */
+#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue)                \
+   VALGRIND_CHECK_MEM_IS_DEFINED(                                \
+      (volatile unsigned char *)&(__lvalue),                     \
+                      (unsigned long)(sizeof (__lvalue)))
+
+
+/* Do a full memory leak check (like --leak-check=full) mid-execution. */
+#define VALGRIND_DO_LEAK_CHECK                                   \
+   {unsigned long _qzz_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__DO_LEAK_CHECK,           \
+                            0, 0, 0, 0, 0);                      \
+   }
+
+/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */
+#define VALGRIND_DO_QUICK_LEAK_CHECK				 \
+   {unsigned long _qzz_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__DO_LEAK_CHECK,           \
+                            1, 0, 0, 0, 0);                      \
+   }
+
+/* Return number of leaked, dubious, reachable and suppressed bytes found by
+   all previous leak checks.  They must be lvalues.  */
+#define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed)     \
+   /* For safety on 64-bit platforms we assign the results to private
+      unsigned long variables, then assign these to the lvalues the user
+      specified, which works no matter what type 'leaked', 'dubious', etc
+      are.  We also initialise '_qzz_leaked', etc because
+      VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
+      defined. */                                                        \
+   {unsigned long _qzz_res;                                              \
+    unsigned long _qzz_leaked    = 0, _qzz_dubious    = 0;               \
+    unsigned long _qzz_reachable = 0, _qzz_suppressed = 0;               \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                              \
+                               VG_USERREQ__COUNT_LEAKS,                  \
+                               &_qzz_leaked, &_qzz_dubious,              \
+                               &_qzz_reachable, &_qzz_suppressed, 0);    \
+    leaked     = _qzz_leaked;                                            \
+    dubious    = _qzz_dubious;                                           \
+    reachable  = _qzz_reachable;                                         \
+    suppressed = _qzz_suppressed;                                        \
+   }
+
+/* Return number of leaked, dubious, reachable and suppressed bytes found by
+   all previous leak checks.  They must be lvalues.  */
+#define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \
+   /* For safety on 64-bit platforms we assign the results to private
+      unsigned long variables, then assign these to the lvalues the user
+      specified, which works no matter what type 'leaked', 'dubious', etc
+      are.  We also initialise '_qzz_leaked', etc because
+      VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
+      defined. */                                                        \
+   {unsigned long _qzz_res;                                              \
+    unsigned long _qzz_leaked    = 0, _qzz_dubious    = 0;               \
+    unsigned long _qzz_reachable = 0, _qzz_suppressed = 0;               \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                              \
+                               VG_USERREQ__COUNT_LEAK_BLOCKS,            \
+                               &_qzz_leaked, &_qzz_dubious,              \
+                               &_qzz_reachable, &_qzz_suppressed, 0);    \
+    leaked     = _qzz_leaked;                                            \
+    dubious    = _qzz_dubious;                                           \
+    reachable  = _qzz_reachable;                                         \
+    suppressed = _qzz_suppressed;                                        \
+   }
+
+
+/* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it
+   into the provided zzvbits array.  Return values:
+      0   if not running on valgrind
+      1   success
+      2   [previously indicated unaligned arrays;  these are now allowed]
+      3   if any parts of zzsrc/zzvbits are not addressable.
+   The metadata is not copied in cases 0, 2 or 3 so it should be
+   impossible to segfault your system by using this call.
+*/
+#define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes)                \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                          \
+                                    VG_USERREQ__GET_VBITS,      \
+                                    (const char*)(zza),         \
+                                    (char*)(zzvbits),           \
+                                    (zznbytes), 0, 0)
+
+/* Set the validity data for addresses [zza..zza+zznbytes-1], copying it
+   from the provided zzvbits array.  Return values:
+      0   if not running on valgrind
+      1   success
+      2   [previously indicated unaligned arrays;  these are now allowed]
+      3   if any parts of zza/zzvbits are not addressable.
+   The metadata is not copied in cases 0, 2 or 3 so it should be
+   impossible to segfault your system by using this call.
+*/
+#define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes)                \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                          \
+                                    VG_USERREQ__SET_VBITS,      \
+                                    (const char*)(zza),         \
+                                    (const char*)(zzvbits),     \
+                                    (zznbytes), 0, 0 )
+
+#endif
+
diff --git a/base/third_party/valgrind/valgrind.h b/base/third_party/valgrind/valgrind.h
new file mode 100644
index 0000000..0bae0aa
--- /dev/null
+++ b/base/third_party/valgrind/valgrind.h
@@ -0,0 +1,4792 @@
+/* -*- c -*-
+   ----------------------------------------------------------------
+
+   Notice that the following BSD-style license applies to this one
+   file (valgrind.h) only.  The rest of Valgrind is licensed under the
+   terms of the GNU General Public License, version 2, unless
+   otherwise indicated.  See the COPYING file in the source
+   distribution for details.
+
+   ----------------------------------------------------------------
+
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2010 Julian Seward.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+   2. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   ----------------------------------------------------------------
+
+   Notice that the above BSD-style license applies to this one file
+   (valgrind.h) only.  The entire rest of Valgrind is licensed under
+   the terms of the GNU General Public License, version 2.  See the
+   COPYING file in the source distribution for details.
+
+   ---------------------------------------------------------------- 
+*/
+
+
+/* This file is for inclusion into client (your!) code.
+
+   You can use these macros to manipulate and query Valgrind's 
+   execution inside your own programs.
+
+   The resulting executables will still run without Valgrind, just a
+   little bit more slowly than they otherwise would, but otherwise
+   unchanged.  When not running on valgrind, each client request
+   consumes very few (eg. 7) instructions, so the resulting performance
+   loss is negligible unless you plan to execute client requests
+   millions of times per second.  Nevertheless, if that is still a
+   problem, you can compile with the NVALGRIND symbol defined (gcc
+   -DNVALGRIND) so that client requests are not even compiled in.  */
+
+#ifndef __VALGRIND_H
+#define __VALGRIND_H
+
+
+/* ------------------------------------------------------------------ */
+/* VERSION NUMBER OF VALGRIND                                         */
+/* ------------------------------------------------------------------ */
+
+/* Specify Valgrind's version number, so that user code can
+   conditionally compile based on our version number.  Note that these
+   were introduced at version 3.6 and so do not exist in version 3.5
+   or earlier.  The recommended way to use them to check for "version
+   X.Y or later" is (eg)
+
+#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__)   \
+    && (__VALGRIND_MAJOR__ > 3                                   \
+        || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
+*/
+#define __VALGRIND_MAJOR__    3
+#define __VALGRIND_MINOR__    6
+
+
+#include <stdarg.h>
+
+/* Nb: this file might be included in a file compiled with -ansi.  So
+   we can't use C++ style "//" comments nor the "asm" keyword (instead
+   use "__asm__"). */
+
+/* Derive some tags indicating what the target platform is.  Note
+   that in this file we're using the compiler's CPP symbols for
+   identifying architectures, which are different to the ones we use
+   within the rest of Valgrind.  Note, __powerpc__ is active for both
+   32 and 64-bit PPC, whereas __powerpc64__ is only active for the
+   latter (on Linux, that is).
+
+   Misc note: how to find out what's predefined in gcc by default:
+   gcc -Wp,-dM somefile.c
+*/
+#undef PLAT_ppc64_aix5
+#undef PLAT_ppc32_aix5
+#undef PLAT_x86_darwin
+#undef PLAT_amd64_darwin
+#undef PLAT_x86_win32
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_arm_linux
+
+#if defined(_AIX) && defined(__64BIT__)
+#  define PLAT_ppc64_aix5 1
+#elif defined(_AIX) && !defined(__64BIT__)
+#  define PLAT_ppc32_aix5 1
+#elif defined(__APPLE__) && defined(__i386__)
+#  define PLAT_x86_darwin 1
+#elif defined(__APPLE__) && defined(__x86_64__)
+#  define PLAT_amd64_darwin 1
+#elif defined(__MINGW32__) || defined(__CYGWIN32__) || defined(_WIN32) && defined(_M_IX86)
+#  define PLAT_x86_win32 1
+#elif defined(__linux__) && defined(__i386__)
+#  define PLAT_x86_linux 1
+#elif defined(__linux__) && defined(__x86_64__)
+#  define PLAT_amd64_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
+#  define PLAT_ppc32_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
+#  define PLAT_ppc64_linux 1
+#elif defined(__linux__) && defined(__arm__)
+#  define PLAT_arm_linux 1
+#else
+/* If we're not compiling for our target platform, don't generate
+   any inline asms.  */
+#  if !defined(NVALGRIND)
+#    define NVALGRIND 1
+#  endif
+#endif
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS.  There is nothing */
+/* in here of use to end-users -- skip to the next section.           */
+/* ------------------------------------------------------------------ */
+
+#if defined(NVALGRIND)
+
+/* Define NVALGRIND to completely remove the Valgrind magic sequence
+   from the compiled code (analogous to NDEBUG's effects on
+   assert()) */
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+   {                                                              \
+      (_zzq_rlval) = (_zzq_default);                              \
+   }
+
+#else  /* ! NVALGRIND */
+
+/* The following defines the magic code sequences which the JITter
+   spots and handles magically.  Don't look too closely at them as
+   they will rot your brain.
+
+   The assembly code sequences for all architectures is in this one
+   file.  This is because this file must be stand-alone, and we don't
+   want to have multiple files.
+
+   For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default
+   value gets put in the return slot, so that everything works when
+   this is executed not under Valgrind.  Args are passed in a memory
+   block, and so there's no intrinsic limit to the number that could
+   be passed, but it's currently five.
+   
+   The macro args are: 
+      _zzq_rlval    result lvalue
+      _zzq_default  default value (result returned when running on real CPU)
+      _zzq_request  request code
+      _zzq_arg1..5  request params
+
+   The other two macros are used to support function wrapping, and are
+   a lot simpler.  VALGRIND_GET_NR_CONTEXT returns the value of the
+   guest's NRADDR pseudo-register and whatever other information is
+   needed to safely run the call original from the wrapper: on
+   ppc64-linux, the R2 value at the divert point is also needed.  This
+   information is abstracted into a user-visible type, OrigFn.
+
+   VALGRIND_CALL_NOREDIR_* behaves the same as the following on the
+   guest, but guarantees that the branch instruction will not be
+   redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64:
+   branch-and-link-to-r11.  VALGRIND_CALL_NOREDIR is just text, not a
+   complete inline asm, since it needs to be combined with more magic
+   inline asm stuff to be useful.
+*/
+
+/* ------------------------- x86-{linux,darwin} ---------------- */
+
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)  \
+    ||  (defined(PLAT_x86_win32) && defined(__GNUC__))
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "roll $3,  %%edi ; roll $13, %%edi\n\t"      \
+                     "roll $29, %%edi ; roll $19, %%edi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile unsigned int _zzq_args[6];                           \
+    volatile unsigned int _zzq_result;                            \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %EDX = client_request ( %EAX ) */         \
+                     "xchgl %%ebx,%%ebx"                          \
+                     : "=d" (_zzq_result)                         \
+                     : "a" (&_zzq_args[0]), "0" (_zzq_default)    \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned int __addr;                                 \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %EAX = guest_NRADDR */                    \
+                     "xchgl %%ecx,%%ecx"                          \
+                     : "=a" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_EAX                                 \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* call-noredir *%EAX */                     \
+                     "xchgl %%edx,%%edx\n\t"
+#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) */
+
+/* ------------------------- x86-Win32 ------------------------- */
+
+#if defined(PLAT_x86_win32) && !defined(__GNUC__)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#if defined(_MSC_VER)
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     __asm rol edi, 3  __asm rol edi, 13          \
+                     __asm rol edi, 29 __asm rol edi, 19
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile uintptr_t _zzq_args[6];                              \
+    volatile unsigned int _zzq_result;                            \
+    _zzq_args[0] = (uintptr_t)(_zzq_request);                     \
+    _zzq_args[1] = (uintptr_t)(_zzq_arg1);                        \
+    _zzq_args[2] = (uintptr_t)(_zzq_arg2);                        \
+    _zzq_args[3] = (uintptr_t)(_zzq_arg3);                        \
+    _zzq_args[4] = (uintptr_t)(_zzq_arg4);                        \
+    _zzq_args[5] = (uintptr_t)(_zzq_arg5);                        \
+    __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default  \
+            __SPECIAL_INSTRUCTION_PREAMBLE                        \
+            /* %EDX = client_request ( %EAX ) */                  \
+            __asm xchg ebx,ebx                                    \
+            __asm mov _zzq_result, edx                            \
+    }                                                             \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned int __addr;                                 \
+    __asm { __SPECIAL_INSTRUCTION_PREAMBLE                        \
+            /* %EAX = guest_NRADDR */                             \
+            __asm xchg ecx,ecx                                    \
+            __asm mov __addr, eax                                 \
+    }                                                             \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_EAX ERROR
+
+#else
+#error Unsupported compiler.
+#endif
+
+#endif /* PLAT_x86_win32 */
+
+/* ------------------------ amd64-{linux,darwin} --------------- */
+
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rolq $3,  %%rdi ; rolq $13, %%rdi\n\t"      \
+                     "rolq $61, %%rdi ; rolq $51, %%rdi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile unsigned long long int _zzq_args[6];                 \
+    volatile unsigned long long int _zzq_result;                  \
+    _zzq_args[0] = (unsigned long long int)(_zzq_request);        \
+    _zzq_args[1] = (unsigned long long int)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned long long int)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned long long int)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned long long int)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned long long int)(_zzq_arg5);           \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %RDX = client_request ( %RAX ) */         \
+                     "xchgq %%rbx,%%rbx"                          \
+                     : "=d" (_zzq_result)                         \
+                     : "a" (&_zzq_args[0]), "0" (_zzq_default)    \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned long long int __addr;                       \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %RAX = guest_NRADDR */                    \
+                     "xchgq %%rcx,%%rcx"                          \
+                     : "=a" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_RAX                                 \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* call-noredir *%RAX */                     \
+                     "xchgq %%rdx,%%rdx\n\t"
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rlwinm 0,0,3,0,0  ; rlwinm 0,0,13,0,0\n\t"  \
+                     "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned int  _zzq_args[6];                          \
+             unsigned int  _zzq_result;                           \
+             unsigned int* _zzq_ptr;                              \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 3,%1\n\t" /*default*/                    \
+                     "mr 4,%2\n\t" /*ptr*/                        \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"     /*result*/                     \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_default), "b" (_zzq_ptr)         \
+                     : "cc", "memory", "r3", "r4");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    unsigned int __addr;                                          \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory", "r3"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+      unsigned long long int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rotldi 0,0,3  ; rotldi 0,0,13\n\t"          \
+                     "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned long long int  _zzq_args[6];                \
+    register unsigned long long int  _zzq_result __asm__("r3");   \
+    register unsigned long long int* _zzq_ptr __asm__("r4");      \
+    _zzq_args[0] = (unsigned long long int)(_zzq_request);        \
+    _zzq_args[1] = (unsigned long long int)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned long long int)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned long long int)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned long long int)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned long long int)(_zzq_arg5);           \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1"                                   \
+                     : "=r" (_zzq_result)                         \
+                     : "0" (_zzq_default), "r" (_zzq_ptr)         \
+                     : "cc", "memory");                           \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned long long int __addr __asm__("r3");         \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2"                                   \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4"                                   \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+            "mov r12, r12, ror #3  ; mov r12, r12, ror #13 \n\t"  \
+            "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  { volatile unsigned int  _zzq_args[6];                          \
+    volatile unsigned int  _zzq_result;                           \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    __asm__ volatile("mov r3, %1\n\t" /*default*/                 \
+                     "mov r4, %2\n\t" /*ptr*/                     \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* R3 = client_request ( R4 ) */             \
+                     "orr r10, r10, r10\n\t"                      \
+                     "mov %0, r3"     /*result*/                  \
+                     : "=r" (_zzq_result)                         \
+                     : "r" (_zzq_default), "r" (&_zzq_args[0])    \
+                     : "cc","memory", "r3", "r4");                \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    unsigned int __addr;                                          \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* R3 = guest_NRADDR */                      \
+                     "orr r11, r11, r11\n\t"                      \
+                     "mov %0, r3"                                 \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory", "r3"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                    \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R4 */        \
+                     "orr r12, r12, r12\n\t"
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+      unsigned int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rlwinm 0,0,3,0,0  ; rlwinm 0,0,13,0,0\n\t"  \
+                     "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned int  _zzq_args[7];                          \
+    register unsigned int  _zzq_result;                           \
+    register unsigned int* _zzq_ptr;                              \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    _zzq_args[6] = (unsigned int)(_zzq_default);                  \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 4,%1\n\t"                                \
+                     "lwz 3, 24(4)\n\t"                           \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_ptr)                             \
+                     : "r3", "r4", "cc", "memory");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned int __addr;                                 \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+      unsigned long long int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rotldi 0,0,3  ; rotldi 0,0,13\n\t"          \
+                     "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned long long int  _zzq_args[7];                \
+    register unsigned long long int  _zzq_result;                 \
+    register unsigned long long int* _zzq_ptr;                    \
+    _zzq_args[0] = (unsigned int long long)(_zzq_request);        \
+    _zzq_args[1] = (unsigned int long long)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned int long long)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned int long long)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned int long long)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned int long long)(_zzq_arg5);           \
+    _zzq_args[6] = (unsigned int long long)(_zzq_default);        \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 4,%1\n\t"                                \
+                     "ld 3, 48(4)\n\t"                            \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_ptr)                             \
+                     : "r3", "r4", "cc", "memory");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned long long int __addr;                       \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_aix5 */
+
+/* Insert assembly code for other platforms here... */
+
+#endif /* NVALGRIND */
+
+
+/* ------------------------------------------------------------------ */
+/* PLATFORM SPECIFICS for FUNCTION WRAPPING.  This is all very        */
+/* ugly.  It's the least-worst tradeoff I can think of.               */
+/* ------------------------------------------------------------------ */
+
+/* This section defines magic (a.k.a appalling-hack) macros for doing
+   guaranteed-no-redirection macros, so as to get from function
+   wrappers to the functions they are wrapping.  The whole point is to
+   construct standard call sequences, but to do the call itself with a
+   special no-redirect call pseudo-instruction that the JIT
+   understands and handles specially.  This section is long and
+   repetitious, and I can't see a way to make it shorter.
+
+   The naming scheme is as follows:
+
+      CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc}
+
+   'W' stands for "word" and 'v' for "void".  Hence there are
+   different macros for calling arity 0, 1, 2, 3, 4, etc, functions,
+   and for each, the possibility of returning a word-typed result, or
+   no result.
+*/
+
+/* Use these to write the name of your wrapper.  NOTE: duplicates
+   VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */
+
+/* Use an extra level of macroisation so as to ensure the soname/fnname
+   args are fully macro-expanded before pasting them together. */
+#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd
+
+#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname)                    \
+   VG_CONCAT4(_vgwZU_,soname,_,fnname)
+
+#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname)                    \
+   VG_CONCAT4(_vgwZZ_,soname,_,fnname)
+
+/* Use this macro from within a wrapper function to collect the
+   context (address and possibly other info) of the original function.
+   Once you have that you can then use it in one of the CALL_FN_
+   macros.  The type of the argument _lval is OrigFn. */
+#define VALGRIND_GET_ORIG_FN(_lval)  VALGRIND_GET_NR_CONTEXT(_lval)
+
+/* Derivatives of the main macros below, for calling functions
+   returning void. */
+
+#define CALL_FN_v_v(fnptr)                                        \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_v(_junk,fnptr); } while (0)
+
+#define CALL_FN_v_W(fnptr, arg1)                                  \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_W(_junk,fnptr,arg1); } while (0)
+
+#define CALL_FN_v_WW(fnptr, arg1,arg2)                            \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0)
+
+#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3)                      \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0)
+
+#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4)                \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0)
+
+#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5)             \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0)
+
+#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6)        \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0)
+
+#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7)   \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0)
+
+/* ------------------------- x86-{linux,darwin} ---------------- */
+
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)
+
+/* These regs are trashed by the hidden call.  No need to mention eax
+   as gcc can already see that, plus causes gcc to bomb. */
+#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx"
+
+/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         "subl $12, %%esp\n\t"                                    \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         "subl $8, %%esp\n\t"                                     \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         "subl $4, %%esp\n\t"                                     \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         "subl $12, %%esp\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         "subl $8, %%esp\n\t"                                     \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         "subl $4, %%esp\n\t"                                     \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         "subl $12, %%esp\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         "subl $8, %%esp\n\t"                                     \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11)                          \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         "subl $4, %%esp\n\t"                                     \
+         "pushl 44(%%eax)\n\t"                                    \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11,arg12)                    \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         "pushl 48(%%eax)\n\t"                                    \
+         "pushl 44(%%eax)\n\t"                                    \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_x86_linux || PLAT_x86_darwin */
+
+/* ------------------------ amd64-{linux,darwin} --------------- */
+
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
+
+/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi",       \
+                            "rdi", "r8", "r9", "r10", "r11"
+
+/* This is all pretty complex.  It's so as to make stack unwinding
+   work reliably.  See bug 243270.  The basic problem is the sub and
+   add of 128 of %rsp in all of the following macros.  If gcc believes
+   the CFA is in %rsp, then unwinding may fail, because what's at the
+   CFA is not what gcc "expected" when it constructs the CFIs for the
+   places where the macros are instantiated.
+
+   But we can't just add a CFI annotation to increase the CFA offset
+   by 128, to match the sub of 128 from %rsp, because we don't know
+   whether gcc has chosen %rsp as the CFA at that point, or whether it
+   has chosen some other register (eg, %rbp).  In the latter case,
+   adding a CFI annotation to change the CFA offset is simply wrong.
+
+   So the solution is to get hold of the CFA using
+   __builtin_dwarf_cfa(), put it in a known register, and add a
+   CFI annotation to say what the register is.  We choose %rbp for
+   this (perhaps perversely), because:
+
+   (1) %rbp is already subject to unwinding.  If a new register was
+       chosen then the unwinder would have to unwind it in all stack
+       traces, which is expensive, and
+
+   (2) %rbp is already subject to precise exception updates in the
+       JIT.  If a new register was chosen, we'd have to have precise
+       exceptions for it too, which reduces performance of the
+       generated code.
+
+   However .. one extra complication.  We can't just whack the result
+   of __builtin_dwarf_cfa() into %rbp and then add %rbp to the
+   list of trashed registers at the end of the inline assembly
+   fragments; gcc won't allow %rbp to appear in that list.  Hence
+   instead we need to stash %rbp in %r15 for the duration of the asm,
+   and say that %r15 is trashed instead.  gcc seems happy to go with
+   that.
+
+   Oh .. and this all needs to be conditionalised so that it is
+   unchanged from before this commit, when compiled with older gccs
+   that don't support __builtin_dwarf_cfa.  Furthermore, since
+   this header file is freestanding, it has to be independent of
+   config.h, and so the following conditionalisation cannot depend on
+   configure time checks.
+
+   Although it's not clear from
+   'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)',
+   this expression excludes Darwin.
+   .cfi directives in Darwin assembly appear to be completely
+   different and I haven't investigated how they work.
+
+   For even more entertainment value, note we have to use the
+   completely undocumented __builtin_dwarf_cfa(), which appears to
+   really compute the CFA, whereas __builtin_frame_address(0) claims
+   to but actually doesn't.  See
+   https://bugs.kde.org/show_bug.cgi?id=243270#c47
+*/
+#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)
+#  define __FRAME_POINTER                                         \
+      ,"r"(__builtin_dwarf_cfa())
+#  define VALGRIND_CFI_PROLOGUE                                   \
+      "movq %%rbp, %%r15\n\t"                                     \
+      "movq %2, %%rbp\n\t"                                        \
+      ".cfi_remember_state\n\t"                                   \
+      ".cfi_def_cfa rbp, 0\n\t"
+#  define VALGRIND_CFI_EPILOGUE                                   \
+      "movq %%r15, %%rbp\n\t"                                     \
+      ".cfi_restore_state\n\t"
+#else
+#  define __FRAME_POINTER
+#  define VALGRIND_CFI_PROLOGUE
+#  define VALGRIND_CFI_EPILOGUE
+#endif
+
+
+/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned
+   long) == 8. */
+
+/* NB 9 Sept 07.  There is a nasty kludge here in all these CALL_FN_
+   macros.  In order not to trash the stack redzone, we need to drop
+   %rsp by 128 before the hidden call, and restore afterwards.  The
+   nastyness is that it is only by luck that the stack still appears
+   to be unwindable during the hidden call - since then the behaviour
+   of any routine using this macro does not match what the CFI data
+   says.  Sigh.
+
+   Why is this important?  Imagine that a wrapper has a stack
+   allocated local, and passes to the hidden call, a pointer to it.
+   Because gcc does not know about the hidden call, it may allocate
+   that local in the redzone.  Unfortunately the hidden call may then
+   trash it before it comes to use it.  So we must step clear of the
+   redzone, for the duration of the hidden call, to make it safe.
+
+   Probably the same problem afflicts the other redzone-style ABIs too
+   (ppc64-linux, ppc32-aix5, ppc64-aix5); but for those, the stack is
+   self describing (none of this CFI nonsense) so at least messing
+   with the stack pointer doesn't give a danger of non-unwindable
+   stack. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $136,%%rsp\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $8, %%rsp\n"                                       \
+         "addq $136,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $16, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $136,%%rsp\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $24, %%rsp\n"                                      \
+         "addq $136,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $32, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $136,%%rsp\n\t"                                    \
+         "pushq 88(%%rax)\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $40, %%rsp\n"                                      \
+         "addq $136,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 96(%%rax)\n\t"                                    \
+         "pushq 88(%%rax)\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $48, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+/* This is useful for finding out about the on-stack stuff:
+
+   extern int f9  ( int,int,int,int,int,int,int,int,int );
+   extern int f10 ( int,int,int,int,int,int,int,int,int,int );
+   extern int f11 ( int,int,int,int,int,int,int,int,int,int,int );
+   extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int );
+
+   int g9 ( void ) {
+      return f9(11,22,33,44,55,66,77,88,99);
+   }
+   int g10 ( void ) {
+      return f10(11,22,33,44,55,66,77,88,99,110);
+   }
+   int g11 ( void ) {
+      return f11(11,22,33,44,55,66,77,88,99,110,121);
+   }
+   int g12 ( void ) {
+      return f12(11,22,33,44,55,66,77,88,99,110,121,132);
+   }
+*/
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc32-linux, 
+   sizeof(unsigned long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-16\n\t"                                       \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,16\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-16\n\t"                                       \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,16\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      _argvec[11] = (unsigned long)arg11;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-32\n\t"                                       \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,16(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,32\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      _argvec[11] = (unsigned long)arg11;                         \
+      _argvec[12] = (unsigned long)arg12;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-32\n\t"                                       \
+         /* arg12 */                                              \
+         "lwz 3,48(11)\n\t"                                       \
+         "stw 3,20(1)\n\t"                                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,16(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,32\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned
+   long) == 8. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-128\n\t"  /* expand stack frame */            \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,128"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-128\n\t"  /* expand stack frame */            \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,128"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-144\n\t"  /* expand stack frame */            \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,144"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-144\n\t"  /* expand stack frame */            \
+         /* arg12 */                                              \
+         "ld  3,96(11)\n\t"                                       \
+         "std 3,136(1)\n\t"                                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,144"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4","r14"
+
+/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory",  __CALLER_SAVED_REGS         \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "push {r0} \n\t"                                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #4 \n\t"                                    \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "push {r0, r1} \n\t"                                     \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #8 \n\t"                                    \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "push {r0, r1, r2} \n\t"                                 \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #12 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "push {r0, r1, r2, r3} \n\t"                             \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #16 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #20 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "push {r0} \n\t"                                         \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #24 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11)                          \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "ldr r1, [%1, #44] \n\t"                                 \
+         "push {r0, r1} \n\t"                                     \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #28 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory",__CALLER_SAVED_REGS           \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11,arg12)                    \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "ldr r1, [%1, #44] \n\t"                                 \
+         "ldr r2, [%1, #48] \n\t"                                 \
+         "push {r0, r1, r2} \n\t"                                 \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #32 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+   still works.  Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr)                      \
+         "addi 1,1,-" #_n_fr "\n\t"                               \
+         "lwz  3," #_n_fr "(1)\n\t"                               \
+         "stw  3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr)                               \
+         "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t" /* arg2->r4 */                       \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(64)                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(64)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(64)                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(64)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(72)                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,64(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(72)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(72)                        \
+         /* arg12 */                                              \
+         "lwz 3,48(11)\n\t"                                       \
+         "stw 3,68(1)\n\t"                                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,64(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(72)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+   still works.  Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr)                      \
+         "addi 1,1,-" #_n_fr "\n\t"                               \
+         "ld   3," #_n_fr "(1)\n\t"                               \
+         "std  3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr)                               \
+         "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc64-aix5, sizeof(unsigned
+   long) == 8. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(128)                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(128)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(128)                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(128)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(144)                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(144)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(144)                       \
+         /* arg12 */                                              \
+         "ld  3,96(11)\n\t"                                       \
+         "std 3,136(1)\n\t"                                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(144)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc64_aix5 */
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS.               */
+/*                                                                    */
+/* ------------------------------------------------------------------ */
+
+/* Some request codes.  There are many more of these, but most are not
+   exposed to end-user view.  These are the public ones, all of the
+   form 0x1000 + small_number.
+
+   Core ones are in the range 0x00000000--0x0000ffff.  The non-public
+   ones start at 0x2000.
+*/
+
+/* These macros are used by tools -- they must be public, but don't
+   embed them into other programs. */
+#define VG_USERREQ_TOOL_BASE(a,b) \
+   ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16))
+#define VG_IS_TOOL_USERREQ(a, b, v) \
+   (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000))
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! 
+   This enum comprises an ABI exported by Valgrind to programs
+   which use client requests.  DO NOT CHANGE THE ORDER OF THESE
+   ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+typedef
+   enum { VG_USERREQ__RUNNING_ON_VALGRIND  = 0x1001,
+          VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002,
+
+          /* These allow any function to be called from the simulated
+             CPU but run on the real CPU.  Nb: the first arg passed to
+             the function is always the ThreadId of the running
+             thread!  So CLIENT_CALL0 actually requires a 1 arg
+             function, etc. */
+          VG_USERREQ__CLIENT_CALL0 = 0x1101,
+          VG_USERREQ__CLIENT_CALL1 = 0x1102,
+          VG_USERREQ__CLIENT_CALL2 = 0x1103,
+          VG_USERREQ__CLIENT_CALL3 = 0x1104,
+
+          /* Can be useful in regression testing suites -- eg. can
+             send Valgrind's output to /dev/null and still count
+             errors. */
+          VG_USERREQ__COUNT_ERRORS = 0x1201,
+
+          /* These are useful and can be interpreted by any tool that
+             tracks malloc() et al, by using vg_replace_malloc.c. */
+          VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301,
+          VG_USERREQ__FREELIKE_BLOCK   = 0x1302,
+          /* Memory pool support. */
+          VG_USERREQ__CREATE_MEMPOOL   = 0x1303,
+          VG_USERREQ__DESTROY_MEMPOOL  = 0x1304,
+          VG_USERREQ__MEMPOOL_ALLOC    = 0x1305,
+          VG_USERREQ__MEMPOOL_FREE     = 0x1306,
+          VG_USERREQ__MEMPOOL_TRIM     = 0x1307,
+          VG_USERREQ__MOVE_MEMPOOL     = 0x1308,
+          VG_USERREQ__MEMPOOL_CHANGE   = 0x1309,
+          VG_USERREQ__MEMPOOL_EXISTS   = 0x130a,
+
+          /* Allow printfs to valgrind log. */
+          /* The first two pass the va_list argument by value, which
+             assumes it is the same size as or smaller than a UWord,
+             which generally isn't the case.  Hence are deprecated.
+             The second two pass the vargs by reference and so are
+             immune to this problem. */
+          /* both :: char* fmt, va_list vargs (DEPRECATED) */
+          VG_USERREQ__PRINTF           = 0x1401,
+          VG_USERREQ__PRINTF_BACKTRACE = 0x1402,
+          /* both :: char* fmt, va_list* vargs */
+          VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403,
+          VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404,
+
+          /* Stack support. */
+          VG_USERREQ__STACK_REGISTER   = 0x1501,
+          VG_USERREQ__STACK_DEREGISTER = 0x1502,
+          VG_USERREQ__STACK_CHANGE     = 0x1503,
+
+          /* Wine support */
+          VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601,
+
+          /* Querying of debug info. */
+          VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701
+   } Vg_ClientRequest;
+
+#if !defined(__GNUC__)
+#  define __extension__ /* */
+#endif
+
+
+/*
+ * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind
+ * client request and whose value equals the client request result.
+ */
+
+#if defined(NVALGRIND)
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR(                               \
+        _zzq_default, _zzq_request,                                    \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)         \
+   (_zzq_default)
+
+#else /*defined(NVALGRIND)*/
+
+#if defined(_MSC_VER)
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR(                                \
+        _zzq_default, _zzq_request,                                     \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)          \
+   (vg_VALGRIND_DO_CLIENT_REQUEST_EXPR((uintptr_t)(_zzq_default),       \
+        (_zzq_request), (uintptr_t)(_zzq_arg1), (uintptr_t)(_zzq_arg2), \
+        (uintptr_t)(_zzq_arg3), (uintptr_t)(_zzq_arg4),                 \
+        (uintptr_t)(_zzq_arg5)))
+
+static __inline unsigned
+vg_VALGRIND_DO_CLIENT_REQUEST_EXPR(uintptr_t _zzq_default,
+                                   unsigned _zzq_request, uintptr_t _zzq_arg1,
+                                   uintptr_t _zzq_arg2, uintptr_t _zzq_arg3,
+                                   uintptr_t _zzq_arg4, uintptr_t _zzq_arg5)
+{
+    unsigned _zzq_rlval;
+    VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, _zzq_request,
+                      _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5);
+    return _zzq_rlval;
+}
+
+#else /*defined(_MSC_VER)*/
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR(                               \
+        _zzq_default, _zzq_request,                                    \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)         \
+   (__extension__({unsigned int _zzq_rlval;                            \
+    VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, _zzq_request, \
+                _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+    _zzq_rlval;                                                        \
+   }))
+
+#endif /*defined(_MSC_VER)*/
+
+#endif /*defined(NVALGRIND)*/
+
+
+/* Returns the number of Valgrinds this code is running under.  That
+   is, 0 if running natively, 1 if running under Valgrind, 2 if
+   running under Valgrind which is running under another Valgrind,
+   etc. */
+#define RUNNING_ON_VALGRIND                                           \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */,                   \
+                                    VG_USERREQ__RUNNING_ON_VALGRIND,  \
+                                    0, 0, 0, 0, 0)                    \
+
+
+/* Discard translation of code in the range [_qzz_addr .. _qzz_addr +
+   _qzz_len - 1].  Useful if you are debugging a JITter or some such,
+   since it provides a way to make sure valgrind will retranslate the
+   invalidated area.  Returns no value. */
+#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len)         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__DISCARD_TRANSLATIONS,  \
+                               _qzz_addr, _qzz_len, 0, 0, 0);     \
+   }
+
+
+/* These requests are for getting Valgrind itself to print something.
+   Possibly with a backtrace.  This is a really ugly hack.  The return value
+   is the number of characters printed, excluding the "**<pid>** " part at the
+   start and the backtrace (if present). */
+
+#if defined(NVALGRIND)
+
+#  define VALGRIND_PRINTF(...)
+#  define VALGRIND_PRINTF_BACKTRACE(...)
+
+#else /* NVALGRIND */
+
+#if !defined(_MSC_VER)
+/* Modern GCC will optimize the static routine out if unused,
+   and unused attribute will shut down warnings about it.  */
+static int VALGRIND_PRINTF(const char *format, ...)
+   __attribute__((format(__printf__, 1, 2), __unused__));
+#endif
+static int
+#if defined(_MSC_VER)
+__inline
+#endif
+VALGRIND_PRINTF(const char *format, ...)
+{
+   unsigned long _qzz_res;
+   va_list vargs;
+   va_start(vargs, format);
+#if defined(_MSC_VER)
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_VALIST_BY_REF,
+                              (uintptr_t)format,
+                              (uintptr_t)&vargs,
+                              0, 0, 0);
+#else
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_VALIST_BY_REF,
+                              (unsigned long)format,
+                              (unsigned long)&vargs, 
+                              0, 0, 0);
+#endif
+   va_end(vargs);
+   return (int)_qzz_res;
+}
+
+#if !defined(_MSC_VER)
+static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+   __attribute__((format(__printf__, 1, 2), __unused__));
+#endif
+static int
+#if defined(_MSC_VER)
+__inline
+#endif
+VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+{
+   unsigned long _qzz_res;
+   va_list vargs;
+   va_start(vargs, format);
+#if defined(_MSC_VER)
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+                              (uintptr_t)format,
+                              (uintptr_t)&vargs,
+                              0, 0, 0);
+#else
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+                              (unsigned long)format,
+                              (unsigned long)&vargs, 
+                              0, 0, 0);
+#endif
+   va_end(vargs);
+   return (int)_qzz_res;
+}
+
+#endif /* NVALGRIND */
+
+
+/* These requests allow control to move from the simulated CPU to the
+   real CPU, calling an arbitary function.
+   
+   Note that the current ThreadId is inserted as the first argument.
+   So this call:
+
+     VALGRIND_NON_SIMD_CALL2(f, arg1, arg2)
+
+   requires f to have this signature:
+
+     Word f(Word tid, Word arg1, Word arg2)
+
+   where "Word" is a word-sized type.
+
+   Note that these client requests are not entirely reliable.  For example,
+   if you call a function with them that subsequently calls printf(),
+   there's a high chance Valgrind will crash.  Generally, your prospects of
+   these working are made higher if the called function does not refer to
+   any global variables, and does not refer to any libc or other functions
+   (printf et al).  Any kind of entanglement with libc or dynamic linking is
+   likely to have a bad outcome, for tricky reasons which we've grappled
+   with a lot in the past.
+*/
+#define VALGRIND_NON_SIMD_CALL0(_qyy_fn)                          \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL0,          \
+                               _qyy_fn,                           \
+                               0, 0, 0, 0);                       \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1)               \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL1,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, 0, 0, 0);               \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2)    \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL2,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, _qyy_arg2, 0, 0);       \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL3,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, _qyy_arg2,              \
+                               _qyy_arg3, 0);                     \
+    _qyy_res;                                                     \
+   })
+
+
+/* Counts the number of errors that have been recorded by a tool.  Nb:
+   the tool must record the errors with VG_(maybe_record_error)() or
+   VG_(unique_error)() for them to be counted. */
+#define VALGRIND_COUNT_ERRORS                                     \
+   __extension__                                                  \
+   ({unsigned int _qyy_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__COUNT_ERRORS,          \
+                               0, 0, 0, 0, 0);                    \
+    _qyy_res;                                                     \
+   })
+
+/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing
+   when heap blocks are allocated in order to give accurate results.  This
+   happens automatically for the standard allocator functions such as
+   malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete,
+   delete[], etc.
+
+   But if your program uses a custom allocator, this doesn't automatically
+   happen, and Valgrind will not do as well.  For example, if you allocate
+   superblocks with mmap() and then allocates chunks of the superblocks, all
+   Valgrind's observations will be at the mmap() level and it won't know that
+   the chunks should be considered separate entities.  In Memcheck's case,
+   that means you probably won't get heap block overrun detection (because
+   there won't be redzones marked as unaddressable) and you definitely won't
+   get any leak detection.
+
+   The following client requests allow a custom allocator to be annotated so
+   that it can be handled accurately by Valgrind.
+
+   VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated
+   by a malloc()-like function.  For Memcheck (an illustrative case), this
+   does two things:
+
+   - It records that the block has been allocated.  This means any addresses
+     within the block mentioned in error messages will be
+     identified as belonging to the block.  It also means that if the block
+     isn't freed it will be detected by the leak checker.
+
+   - It marks the block as being addressable and undefined (if 'is_zeroed' is
+     not set), or addressable and defined (if 'is_zeroed' is set).  This
+     controls how accesses to the block by the program are handled.
+   
+   'addr' is the start of the usable block (ie. after any
+   redzone), 'sizeB' is its size.  'rzB' is the redzone size if the allocator
+   can apply redzones -- these are blocks of padding at the start and end of
+   each block.  Adding redzones is recommended as it makes it much more likely
+   Valgrind will spot block overruns.  `is_zeroed' indicates if the memory is
+   zeroed (or filled with another predictable value), as is the case for
+   calloc().
+   
+   VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a
+   heap block -- that will be used by the client program -- is allocated.
+   It's best to put it at the outermost level of the allocator if possible;
+   for example, if you have a function my_alloc() which calls
+   internal_alloc(), and the client request is put inside internal_alloc(),
+   stack traces relating to the heap block will contain entries for both
+   my_alloc() and internal_alloc(), which is probably not what you want.
+
+   For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out
+   custom blocks from within a heap block, B, that has been allocated with
+   malloc/calloc/new/etc, then block B will be *ignored* during leak-checking
+   -- the custom blocks will take precedence.
+
+   VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK.  For
+   Memcheck, it does two things:
+
+   - It records that the block has been deallocated.  This assumes that the
+     block was annotated as having been allocated via
+     VALGRIND_MALLOCLIKE_BLOCK.  Otherwise, an error will be issued.
+
+   - It marks the block as being unaddressable.
+
+   VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a
+   heap block is deallocated.
+
+   In many cases, these two client requests will not be enough to get your
+   allocator working well with Memcheck.  More specifically, if your allocator
+   writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call
+   will be necessary to mark the memory as addressable just before the zeroing
+   occurs, otherwise you'll get a lot of invalid write errors.  For example,
+   you'll need to do this if your allocator recycles freed blocks, but it
+   zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK).
+   Alternatively, if your allocator reuses freed blocks for allocator-internal
+   data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary.
+
+   Really, what's happening is a blurring of the lines between the client
+   program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the
+   memory should be considered unaddressable to the client program, but the
+   allocator knows more than the rest of the client program and so may be able
+   to safely access it.  Extra client requests are necessary for Valgrind to
+   understand the distinction between the allocator and the rest of the
+   program.
+
+   Note: there is currently no VALGRIND_REALLOCLIKE_BLOCK client request;  it
+   has to be emulated with MALLOCLIKE/FREELIKE and memory copying.
+   
+   Ignored if addr == 0.
+*/
+#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed)    \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MALLOCLIKE_BLOCK,      \
+                               addr, sizeB, rzB, is_zeroed, 0);   \
+   }
+
+/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details.
+   Ignored if addr == 0.
+*/
+#define VALGRIND_FREELIKE_BLOCK(addr, rzB)                        \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__FREELIKE_BLOCK,        \
+                               addr, rzB, 0, 0, 0);               \
+   }
+
+/* Create a memory pool. */
+#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed)             \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__CREATE_MEMPOOL,        \
+                               pool, rzB, is_zeroed, 0, 0);       \
+   }
+
+/* Destroy a memory pool. */
+#define VALGRIND_DESTROY_MEMPOOL(pool)                            \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__DESTROY_MEMPOOL,       \
+                               pool, 0, 0, 0, 0);                 \
+   }
+
+/* Associate a piece of memory with a memory pool. */
+#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size)                  \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_ALLOC,         \
+                               pool, addr, size, 0, 0);           \
+   }
+
+/* Disassociate a piece of memory from a memory pool. */
+#define VALGRIND_MEMPOOL_FREE(pool, addr)                         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_FREE,          \
+                               pool, addr, 0, 0, 0);              \
+   }
+
+/* Disassociate any pieces outside a particular range. */
+#define VALGRIND_MEMPOOL_TRIM(pool, addr, size)                   \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_TRIM,          \
+                               pool, addr, size, 0, 0);           \
+   }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MOVE_MEMPOOL(poolA, poolB)                       \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MOVE_MEMPOOL,          \
+                               poolA, poolB, 0, 0, 0);            \
+   }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size)         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_CHANGE,        \
+                               pool, addrA, addrB, size, 0);      \
+   }
+
+/* Return 1 if a mempool exists, else 0. */
+#define VALGRIND_MEMPOOL_EXISTS(pool)                             \
+   __extension__                                                  \
+   ({unsigned int _qzz_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_EXISTS,        \
+                               pool, 0, 0, 0, 0);                 \
+    _qzz_res;                                                     \
+   })
+
+/* Mark a piece of memory as being a stack. Returns a stack id. */
+#define VALGRIND_STACK_REGISTER(start, end)                       \
+   __extension__                                                  \
+   ({unsigned int _qzz_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_REGISTER,        \
+                               start, end, 0, 0, 0);              \
+    _qzz_res;                                                     \
+   })
+
+/* Unmark the piece of memory associated with a stack id as being a
+   stack. */
+#define VALGRIND_STACK_DEREGISTER(id)                             \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_DEREGISTER,      \
+                               id, 0, 0, 0, 0);                   \
+   }
+
+/* Change the start and end address of the stack id. */
+#define VALGRIND_STACK_CHANGE(id, start, end)                     \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_CHANGE,          \
+                               id, start, end, 0, 0);             \
+   }
+
+/* Load PDB debug info for Wine PE image_map. */
+#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta)   \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__LOAD_PDB_DEBUGINFO,    \
+                               fd, ptr, total_size, delta, 0);    \
+   }
+
+/* Map a code address to a source file name and line number.  buf64
+   must point to a 64-byte buffer in the caller's address space.  The
+   result will be dumped in there and is guaranteed to be zero
+   terminated.  If no info is found, the first byte is set to zero. */
+#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64)                    \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MAP_IP_TO_SRCLOC,      \
+                               addr, buf64, 0, 0, 0);             \
+   }
+
+
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_arm_linux
+#undef PLAT_ppc32_aix5
+#undef PLAT_ppc64_aix5
+
+#endif   /* __VALGRIND_H */
diff --git a/base/third_party/xdg_user_dirs/LICENSE b/base/third_party/xdg_user_dirs/LICENSE
new file mode 100644
index 0000000..540e803
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/LICENSE
@@ -0,0 +1,21 @@
+  Copyright (c) 2007 Red Hat, inc
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions: 
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software. 
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
diff --git a/base/third_party/xdg_user_dirs/README.chromium b/base/third_party/xdg_user_dirs/README.chromium
new file mode 100644
index 0000000..b4cf6d7
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/README.chromium
@@ -0,0 +1,7 @@
+Name: xdg-user-dirs
+URL: http://www.freedesktop.org/wiki/Software/xdg-user-dirs
+License: MIT
+
+This directory include xdg-user-dir-lookup.c renamed as xdg_user_dir_lookup.cc
+from xdg-user-dirs 0.10. We made xdg_user_dir_lookup() non-static and added a
+xdg_user_dir_lookup.h.
diff --git a/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc
new file mode 100644
index 0000000..343f70c
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc
@@ -0,0 +1,232 @@
+/*
+  This file is not licenced under the GPL like the rest of the code.
+  Its is under the MIT license, to encourage reuse by cut-and-paste.
+
+  Copyright (c) 2007 Red Hat, inc
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions: 
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software. 
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * xdg_user_dir_lookup_with_fallback:
+ * @type: a string specifying the type of directory
+ * @fallback: value to use if the directory isn't specified by the user
+ * @returns: a newly allocated absolute pathname
+ *
+ * Looks up a XDG user directory of the specified type.
+ * Example of types are "DESKTOP" and "DOWNLOAD".
+ *
+ * In case the user hasn't specified any directory for the specified
+ * type the value returned is @fallback.
+ *
+ * The return value is newly allocated and must be freed with
+ * free(). The return value is never NULL if @fallback != NULL, unless
+ * out of memory.
+ **/
+static char *
+xdg_user_dir_lookup_with_fallback (const char *type, const char *fallback)
+{
+  FILE *file;
+  char *home_dir, *config_home, *config_file;
+  char buffer[512];
+  char *user_dir;
+  char *p, *d;
+  int len;
+  int relative;
+  
+  home_dir = getenv ("HOME");
+
+  if (home_dir == NULL)
+    goto error;
+
+  config_home = getenv ("XDG_CONFIG_HOME");
+  if (config_home == NULL || config_home[0] == 0)
+    {
+      config_file = (char*) malloc (strlen (home_dir) + strlen ("/.config/user-dirs.dirs") + 1);
+      if (config_file == NULL)
+        goto error;
+
+      strcpy (config_file, home_dir);
+      strcat (config_file, "/.config/user-dirs.dirs");
+    }
+  else
+    {
+      config_file = (char*) malloc (strlen (config_home) + strlen ("/user-dirs.dirs") + 1);
+      if (config_file == NULL)
+        goto error;
+
+      strcpy (config_file, config_home);
+      strcat (config_file, "/user-dirs.dirs");
+    }
+
+  file = fopen (config_file, "r");
+  free (config_file);
+  if (file == NULL)
+    goto error;
+
+  user_dir = NULL;
+  while (fgets (buffer, sizeof (buffer), file))
+    {
+      /* Remove newline at end */
+      len = strlen (buffer);
+      if (len > 0 && buffer[len-1] == '\n')
+	buffer[len-1] = 0;
+      
+      p = buffer;
+      while (*p == ' ' || *p == '\t')
+	p++;
+      
+      if (strncmp (p, "XDG_", 4) != 0)
+	continue;
+      p += 4;
+      if (strncmp (p, type, strlen (type)) != 0)
+	continue;
+      p += strlen (type);
+      if (strncmp (p, "_DIR", 4) != 0)
+	continue;
+      p += 4;
+
+      while (*p == ' ' || *p == '\t')
+	p++;
+
+      if (*p != '=')
+	continue;
+      p++;
+      
+      while (*p == ' ' || *p == '\t')
+	p++;
+
+      if (*p != '"')
+	continue;
+      p++;
+      
+      relative = 0;
+      if (strncmp (p, "$HOME/", 6) == 0)
+	{
+	  p += 6;
+	  relative = 1;
+	}
+      else if (*p != '/')
+	continue;
+      
+      if (relative)
+	{
+	  user_dir = (char*) malloc (strlen (home_dir) + 1 + strlen (p) + 1);
+          if (user_dir == NULL)
+            goto error2;
+
+	  strcpy (user_dir, home_dir);
+	  strcat (user_dir, "/");
+	}
+      else
+	{
+	  user_dir = (char*) malloc (strlen (p) + 1);
+          if (user_dir == NULL)
+            goto error2;
+
+	  *user_dir = 0;
+	}
+      
+      d = user_dir + strlen (user_dir);
+      while (*p && *p != '"')
+	{
+	  if ((*p == '\\') && (*(p+1) != 0))
+	    p++;
+	  *d++ = *p++;
+	}
+      *d = 0;
+    }
+error2:
+  fclose (file);
+
+  if (user_dir)
+    return user_dir;
+
+ error:
+  if (fallback)
+    return strdup (fallback);
+  return NULL;
+}
+
+/**
+ * xdg_user_dir_lookup:
+ * @type: a string specifying the type of directory
+ * @returns: a newly allocated absolute pathname
+ *
+ * Looks up a XDG user directory of the specified type.
+ * Example of types are "DESKTOP" and "DOWNLOAD".
+ *
+ * The return value is always != NULL (unless out of memory),
+ * and if a directory
+ * for the type is not specified by the user the default
+ * is the home directory. Except for DESKTOP which defaults
+ * to ~/Desktop.
+ *
+ * The return value is newly allocated and must be freed with
+ * free().
+ **/
+char *
+xdg_user_dir_lookup (const char *type)
+{
+  char *dir, *home_dir, *user_dir;
+	  
+  dir = xdg_user_dir_lookup_with_fallback (type, NULL);
+  if (dir != NULL)
+    return dir;
+  
+  home_dir = getenv ("HOME");
+  
+  if (home_dir == NULL)
+    return strdup ("/tmp");
+  
+  /* Special case desktop for historical compatibility */
+  if (strcmp (type, "DESKTOP") == 0)
+    {
+      user_dir = (char*) malloc (strlen (home_dir) + strlen ("/Desktop") + 1);
+      if (user_dir == NULL)
+        return NULL;
+
+      strcpy (user_dir, home_dir);
+      strcat (user_dir, "/Desktop");
+      return user_dir;
+    }
+  
+  return strdup (home_dir);
+}
+
+#ifdef STANDALONE_XDG_USER_DIR_LOOKUP
+int
+main (int argc, char *argv[])
+{
+  if (argc != 2)
+    {
+      fprintf (stderr, "Usage %s <dir-type>\n", argv[0]);
+      exit (1);
+    }
+  
+  printf ("%s\n", xdg_user_dir_lookup (argv[1]));
+  return 0;
+}
+#endif
diff --git a/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h
new file mode 100644
index 0000000..9e81e1b
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h
@@ -0,0 +1,33 @@
+/*
+  This file is not licenced under the GPL like the rest of the code.
+  Its is under the MIT license, to encourage reuse by cut-and-paste.
+
+  Copyright (c) 2007 Red Hat, inc
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions: 
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software. 
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+*/
+
+#ifndef CHROME_THIRD_PARTY_XDG_USER_DIRS_XDG_USER_DIR_LOOKUP_H_
+#define CHROME_THIRD_PARTY_XDG_USER_DIRS_XDG_USER_DIR_LOOKUP_H_
+
+char* xdg_user_dir_lookup(const char *type);
+
+#endif  // CHROME_THIRD_PARTY_XDG_USER_DIRS_XDG_USER_DIR_LOOKUP_H_
diff --git a/base/thread_task_runner_handle.cc b/base/thread_task_runner_handle.cc
new file mode 100644
index 0000000..d1b07aa
--- /dev/null
+++ b/base/thread_task_runner_handle.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/thread_task_runner_handle.h"
+
+#include "base/lazy_instance.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_local.h"
+
+namespace base {
+
+namespace {
+
+base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle> >
+    lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// static
+scoped_refptr<SingleThreadTaskRunner> ThreadTaskRunnerHandle::Get() {
+  ThreadTaskRunnerHandle* current = lazy_tls_ptr.Pointer()->Get();
+  DCHECK(current);
+  return current->task_runner_;
+}
+
+ThreadTaskRunnerHandle::ThreadTaskRunnerHandle(
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+    : task_runner_(task_runner) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(!lazy_tls_ptr.Pointer()->Get());
+  lazy_tls_ptr.Pointer()->Set(this);
+}
+
+ThreadTaskRunnerHandle::~ThreadTaskRunnerHandle() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK_EQ(lazy_tls_ptr.Pointer()->Get(), this);
+  lazy_tls_ptr.Pointer()->Set(NULL);
+}
+
+}  // namespace base
diff --git a/base/thread_task_runner_handle.h b/base/thread_task_runner_handle.h
new file mode 100644
index 0000000..599d15b
--- /dev/null
+++ b/base/thread_task_runner_handle.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_THREAD_TASK_RUNNER_HANDLE_H_
+#define BASE_THREAD_TASK_RUNNER_HANDLE_H_
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+// ThreadTaskRunnerHandle stores a reference to the main task runner
+// for each thread. Not more than one of these objects can be created
+// per thread. After an instance of this object is created the Get()
+// function will return the |task_runner| specified in the
+// constructor.
+class BASE_EXPORT ThreadTaskRunnerHandle {
+ public:
+  // Gets the SingleThreadTaskRunner for the current thread.
+  static scoped_refptr<SingleThreadTaskRunner> Get();
+
+  ThreadTaskRunnerHandle(
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+  ~ThreadTaskRunnerHandle();
+
+ private:
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+};
+
+}  // namespace base
+
+#endif  // BASE_THREAD_TASK_RUNNER_HANDLE_H_
diff --git a/base/threading/OWNERS b/base/threading/OWNERS
new file mode 100644
index 0000000..4198e99
--- /dev/null
+++ b/base/threading/OWNERS
@@ -0,0 +1,2 @@
+# For thread_resrictions.*
+jam@chromium.org
diff --git a/base/threading/non_thread_safe.h b/base/threading/non_thread_safe.h
new file mode 100644
index 0000000..cf7a418
--- /dev/null
+++ b/base/threading/non_thread_safe.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_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
+
+#if ENABLE_NON_THREAD_SAFE
+#include "base/threading/non_thread_safe_impl.h"
+#endif
+
+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 inheritence. 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_NON_THREAD_SAFE_H_
diff --git a/base/threading/non_thread_safe_impl.cc b/base/threading/non_thread_safe_impl.cc
new file mode 100644
index 0000000..7e729d9
--- /dev/null
+++ b/base/threading/non_thread_safe_impl.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/non_thread_safe_impl.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+bool NonThreadSafeImpl::CalledOnValidThread() const {
+  return thread_checker_.CalledOnValidThread();
+}
+
+NonThreadSafeImpl::~NonThreadSafeImpl() {
+  DCHECK(CalledOnValidThread());
+}
+
+void NonThreadSafeImpl::DetachFromThread() {
+  thread_checker_.DetachFromThread();
+}
+
+}  // namespace base
diff --git a/base/threading/non_thread_safe_impl.h b/base/threading/non_thread_safe_impl.h
new file mode 100644
index 0000000..a3a356d
--- /dev/null
+++ b/base/threading/non_thread_safe_impl.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_NON_THREAD_SAFE_IMPL_H_
+#define BASE_THREADING_NON_THREAD_SAFE_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/threading/thread_checker_impl.h"
+
+namespace base {
+
+// Full implementation of NonThreadSafe, for debug mode or for occasional
+// temporary use in release mode e.g. when you need to CHECK on a thread
+// bug that only occurs in the wild.
+//
+// Note: You should almost always use the NonThreadSafe class to get
+// the right version of the class for your build configuration.
+class BASE_EXPORT NonThreadSafeImpl {
+ public:
+  bool CalledOnValidThread() const;
+
+ protected:
+  ~NonThreadSafeImpl();
+
+  // Changes the thread that is checked for in CalledOnValidThread. The next
+  // call to CalledOnValidThread will attach this class to a new thread. It is
+  // up to the NonThreadSafe derived class to decide to expose this or not.
+  // This may be useful when an object may be created on one thread and then
+  // used exclusively on another thread.
+  void DetachFromThread();
+
+ private:
+  ThreadCheckerImpl thread_checker_;
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_NON_THREAD_SAFE_IMPL_H_
diff --git a/base/threading/non_thread_safe_unittest.cc b/base/threading/non_thread_safe_unittest.cc
new file mode 100644
index 0000000..ee31701
--- /dev/null
+++ b/base/threading/non_thread_safe_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/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Duplicated from base/threading/non_thread_safe.h so that we can be
+// good citizens there and undef the macro.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_NON_THREAD_SAFE 1
+#else
+#define ENABLE_NON_THREAD_SAFE 0
+#endif
+
+namespace base {
+
+namespace {
+
+// Simple class to exersice the basics of NonThreadSafe.
+// Both the destructor and DoStuff should verify that they were
+// called on the same thread as the constructor.
+class NonThreadSafeClass : public NonThreadSafe {
+ public:
+  NonThreadSafeClass() {}
+
+  // Verifies that it was called on the same thread as the constructor.
+  void DoStuff() {
+    DCHECK(CalledOnValidThread());
+  }
+
+  void DetachFromThread() {
+    NonThreadSafe::DetachFromThread();
+  }
+
+  static void MethodOnDifferentThreadImpl();
+  static void DestructorOnDifferentThreadImpl();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass);
+};
+
+// Calls NonThreadSafeClass::DoStuff on another thread.
+class CallDoStuffOnThread : public SimpleThread {
+ public:
+  CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class)
+      : SimpleThread("call_do_stuff_on_thread"),
+        non_thread_safe_class_(non_thread_safe_class) {
+  }
+
+  virtual 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:
+  DeleteNonThreadSafeClassOnThread(NonThreadSafeClass* non_thread_safe_class)
+      : SimpleThread("delete_non_thread_safe_class_on_thread"),
+        non_thread_safe_class_(non_thread_safe_class) {
+  }
+
+  virtual void Run() OVERRIDE {
+    non_thread_safe_class_.reset();
+  }
+
+ private:
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread);
+};
+
+}  // namespace
+
+TEST(NonThreadSafeTest, CallsAllowedOnSameThread) {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that DoStuff doesn't assert.
+  non_thread_safe_class->DoStuff();
+
+  // Verify that the destructor doesn't assert.
+  non_thread_safe_class.reset();
+}
+
+TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that the destructor doesn't assert when called on a different thread
+  // after a detach.
+  non_thread_safe_class->DetachFromThread();
+  DeleteNonThreadSafeClassOnThread delete_on_thread(
+      non_thread_safe_class.release());
+
+  delete_on_thread.Start();
+  delete_on_thread.Join();
+}
+
+#if GTEST_HAS_DEATH_TEST || !ENABLE_NON_THREAD_SAFE
+
+void NonThreadSafeClass::MethodOnDifferentThreadImpl() {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that DoStuff asserts in debug builds only when called
+  // on a different thread.
+  CallDoStuffOnThread call_on_thread(non_thread_safe_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+}
+
+#if ENABLE_NON_THREAD_SAFE
+TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
+  ASSERT_DEATH({
+      NonThreadSafeClass::MethodOnDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) {
+  NonThreadSafeClass::MethodOnDifferentThreadImpl();
+}
+#endif  // ENABLE_NON_THREAD_SAFE
+
+void NonThreadSafeClass::DestructorOnDifferentThreadImpl() {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that the destructor asserts in debug builds only
+  // when called on a different thread.
+  DeleteNonThreadSafeClassOnThread delete_on_thread(
+      non_thread_safe_class.release());
+
+  delete_on_thread.Start();
+  delete_on_thread.Join();
+}
+
+#if ENABLE_NON_THREAD_SAFE
+TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) {
+  ASSERT_DEATH({
+      NonThreadSafeClass::DestructorOnDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) {
+  NonThreadSafeClass::DestructorOnDifferentThreadImpl();
+}
+#endif  // ENABLE_NON_THREAD_SAFE
+
+#endif  // GTEST_HAS_DEATH_TEST || !ENABLE_NON_THREAD_SAFE
+
+// Just in case we ever get lumped together with other compilation units.
+#undef ENABLE_NON_THREAD_SAFE
+
+}  // namespace base
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
new file mode 100644
index 0000000..576695a
--- /dev/null
+++ b/base/threading/platform_thread.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: You should *NOT* be using this class directly.  PlatformThread is
+// the low-level platform-specific abstraction to the OS's threading interface.
+// You should instead be using a message-loop driven Thread, see thread.h.
+
+#ifndef BASE_THREADING_PLATFORM_THREAD_H_
+#define BASE_THREADING_PLATFORM_THREAD_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/time.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 {
+
+// PlatformThreadHandle should not be assumed to be a numeric type, since the
+// standard intends to allow pthread_t to be a structure.  This means you
+// should not initialize it to a value, like 0.  If it's a member variable, the
+// constructor can safely "value initialize" using () in the initializer list.
+#if defined(OS_WIN)
+typedef DWORD PlatformThreadId;
+typedef void* PlatformThreadHandle;  // HANDLE
+const PlatformThreadHandle kNullThreadHandle = NULL;
+#elif defined(OS_POSIX)
+typedef pthread_t PlatformThreadHandle;
+const PlatformThreadHandle kNullThreadHandle = 0;
+typedef pid_t PlatformThreadId;
+#endif
+
+const PlatformThreadId kInvalidThreadId = 0;
+
+// Valid values for SetThreadPriority()
+enum ThreadPriority{
+  kThreadPriority_Normal,
+  // Suitable for low-latency, glitch-resistant audio.
+  kThreadPriority_RealtimeAudio
+};
+
+// 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();
+
+  // Yield the current thread so another thread can be scheduled.
+  static void YieldCurrentThread();
+
+  // Sleeps for the specified duration.
+  static void Sleep(base::TimeDelta duration);
+
+  // Sets the thread name visible to debuggers/tools. This has no effect
+  // otherwise. This name pointer is not copied internally. Thus, it must stay
+  // valid until the thread ends.
+  static void SetName(const char* name);
+
+  // Gets the thread name, if previously set by SetName.
+  static const char* GetName();
+
+  // Creates a new thread.  The |stack_size| parameter can be 0 to indicate
+  // that the default stack size should be used.  Upon success,
+  // |*thread_handle| will be assigned a handle to the newly created thread,
+  // and |delegate|'s ThreadMain method will be executed on the newly created
+  // thread.
+  // NOTE: When you are done with the thread handle, you must call Join to
+  // release system resources associated with the thread.  You must ensure that
+  // the Delegate object outlives the thread.
+  static bool Create(size_t stack_size, Delegate* delegate,
+                     PlatformThreadHandle* thread_handle);
+
+  // CreateWithPriority() does the same thing as Create() except the priority of
+  // the thread is set based on |priority|.  Can be used in place of Create()
+  // followed by SetThreadPriority().  SetThreadPriority() has not been
+  // implemented on the Linux platform yet, this is the only way to get a high
+  // priority thread on Linux.
+  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);
+
+  // Sets the priority of the thread specified in |handle| to |priority|.
+  // This does not work on Linux, use CreateWithPriority() instead.
+  static void SetThreadPriority(PlatformThreadHandle handle,
+                                ThreadPriority priority);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_PLATFORM_THREAD_H_
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
new file mode 100644
index 0000000..96c6720
--- /dev/null
+++ b/base/threading/platform_thread_mac.mm
@@ -0,0 +1,190 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <dlfcn.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach/thread_policy.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/thread_local.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+namespace {
+
+LazyInstance<ThreadLocalPointer<char> >::Leaky
+    current_thread_name = LAZY_INSTANCE_INITIALIZER;
+
+}  // 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 char* name) {
+  current_thread_name.Pointer()->Set(const_cast<char*>(name));
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+  // pthread_setname_np is only available in 10.6 or later, so test
+  // for it at runtime.
+  int (*dynamic_pthread_setname_np)(const char*);
+  *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
+      dlsym(RTLD_DEFAULT, "pthread_setname_np");
+  if (!dynamic_pthread_setname_np)
+    return;
+
+  // Mac OS X does not expose the length limit of the name, so
+  // hardcode it.
+  const int kMaxNameLength = 63;
+  std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
+  // pthread_setname() fails (harmlessly) in the sandbox, ignore when it does.
+  // See http://crbug.com/47058
+  dynamic_pthread_setname_np(shortened_name.c_str());
+}
+
+// static
+const char* PlatformThread::GetName() {
+  return current_thread_name.Pointer()->Get();
+}
+
+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,
+                                           (thread_policy_t)&policy,
+                                           THREAD_STANDARD_POLICY_COUNT);
+
+  if (result != KERN_SUCCESS)
+    DVLOG(1) << "thread_policy_set() failure: " << result;
+}
+
+// Enables time-contraint policy and priority suitable for low-latency,
+// glitch-resistant audio.
+void SetPriorityRealtimeAudio(mach_port_t mach_thread_id) {
+  kern_return_t result;
+
+  // 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.
+  result = thread_policy_set(mach_thread_id,
+                             THREAD_EXTENDED_POLICY,
+                             (thread_policy_t)&policy,
+                             THREAD_EXTENDED_POLICY_COUNT);
+  if (result != KERN_SUCCESS) {
+    DVLOG(1) << "thread_policy_set() failure: " << result;
+    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,
+                             (thread_policy_t)&precedence,
+                             THREAD_PRECEDENCE_POLICY_COUNT);
+  if (result != KERN_SUCCESS) {
+    DVLOG(1) << "thread_policy_set() failure: " << result;
+    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 =
+      ((double)tb_info.denom / (double)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,
+                             (thread_policy_t)&time_constraints,
+                             THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+  if (result != KERN_SUCCESS)
+    DVLOG(1) << "thread_policy_set() failure: " << result;
+
+  return;
+}
+
+}  // anonymous namespace
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
+                                       ThreadPriority priority) {
+  // Convert from pthread_t to mach thread identifier.
+  mach_port_t mach_thread_id = pthread_mach_thread_np(handle);
+
+  switch (priority) {
+    case kThreadPriority_Normal:
+      SetPriorityNormal(mach_thread_id);
+      break;
+    case kThreadPriority_RealtimeAudio:
+      SetPriorityRealtimeAudio(mach_thread_id);
+      break;
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
new file mode 100644
index 0000000..444edc5
--- /dev/null
+++ b/base/threading/platform_thread_posix.cc
@@ -0,0 +1,286 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#include <errno.h>
+#include <sched.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/safe_strerror_posix.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_MACOSX)
+#include <sys/resource.h>
+#include <algorithm>
+#endif
+
+#if defined(OS_LINUX)
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#endif
+
+// TODO(bbudge) Use time.h when NaCl toolchain supports _POSIX_TIMERS
+#if defined(OS_NACL)
+#include <sys/nacl_syscalls.h>
+#endif
+
+namespace base {
+
+#if defined(OS_MACOSX)
+void InitThreading();
+#endif
+
+namespace {
+
+#if !defined(OS_MACOSX)
+// Mac name code is in in platform_thread_mac.mm.
+LazyInstance<ThreadLocalPointer<char> >::Leaky
+    current_thread_name = LAZY_INSTANCE_INITIALIZER;
+#endif
+
+struct ThreadParams {
+  PlatformThread::Delegate* delegate;
+  bool joinable;
+};
+
+void* ThreadFunc(void* params) {
+  ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+  PlatformThread::Delegate* delegate = thread_params->delegate;
+  if (!thread_params->joinable)
+    base::ThreadRestrictions::SetSingletonAllowed(false);
+  delete thread_params;
+  delegate->ThreadMain();
+#if defined(OS_ANDROID)
+  base::android::DetachFromVM();
+#endif
+  return NULL;
+}
+
+bool CreateThread(size_t stack_size, bool joinable,
+                  PlatformThread::Delegate* delegate,
+                  PlatformThreadHandle* thread_handle,
+                  ThreadPriority priority) {
+#if defined(OS_MACOSX)
+  base::InitThreading();
+#endif  // OS_MACOSX
+
+  bool success = false;
+  pthread_attr_t attributes;
+  pthread_attr_init(&attributes);
+
+  // Pthreads are joinable by default, so only specify the detached attribute if
+  // the thread should be non-joinable.
+  if (!joinable) {
+    pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
+  }
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // 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.
+  if (stack_size == 0) {
+    size_t default_stack_size;
+    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) {
+      stack_size = std::max(std::max(default_stack_size,
+                                     static_cast<size_t>(PTHREAD_STACK_MIN)),
+                            static_cast<size_t>(stack_rlimit.rlim_cur));
+    }
+  }
+#endif  // OS_MACOSX && !OS_IOS
+
+  if (stack_size > 0)
+    pthread_attr_setstacksize(&attributes, stack_size);
+
+  ThreadParams* params = new ThreadParams;
+  params->delegate = delegate;
+  params->joinable = joinable;
+  success = !pthread_create(thread_handle, &attributes, ThreadFunc, params);
+
+  if (priority != kThreadPriority_Normal) {
+#if defined(OS_LINUX)
+    if (priority == kThreadPriority_RealtimeAudio) {
+      // Linux isn't posix compliant with setpriority(2), it will set a thread
+      // priority if it is passed a tid, not affecting the rest of the threads
+      // in the process.  Setting this priority will only succeed if the user
+      // has been granted permission to adjust nice values on the system.
+      const int kNiceSetting = -10;
+      if (setpriority(PRIO_PROCESS, PlatformThread::CurrentId(), kNiceSetting))
+        DVLOG(1) << "Failed to set nice value of thread to " << kNiceSetting;
+    } else {
+      NOTREACHED() << "Unknown thread priority.";
+    }
+#else
+    PlatformThread::SetThreadPriority(*thread_handle, priority);
+#endif
+  }
+
+  pthread_attr_destroy(&attributes);
+  if (!success)
+    delete params;
+  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_LINUX)
+  return syscall(__NR_gettid);
+#elif defined(OS_ANDROID)
+  return gettid();
+#elif defined(OS_SOLARIS)
+  return pthread_self();
+#elif defined(OS_NACL) && defined(__GLIBC__)
+  return pthread_self();
+#elif defined(OS_NACL) && !defined(__GLIBC__)
+  // Pointers are 32-bits in NaCl.
+  return reinterpret_cast<int32>(pthread_self());
+#elif defined(OS_POSIX)
+  return reinterpret_cast<int64>(pthread_self());
+#endif
+}
+
+// static
+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;
+}
+
+#if defined(OS_LINUX)
+// static
+void PlatformThread::SetName(const char* name) {
+  // have to cast away const because ThreadLocalPointer does not support const
+  // void*
+  current_thread_name.Pointer()->Set(const_cast<char*>(name));
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+  // 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);
+  // We expect EPERM failures in sandboxed processes, just ignore those.
+  if (err < 0 && errno != EPERM)
+    DPLOG(ERROR) << "prctl(PR_SET_NAME)";
+}
+#elif defined(OS_MACOSX)
+// Mac is implemented in platform_thread_mac.mm.
+#else
+// static
+void PlatformThread::SetName(const char* name) {
+  // have to cast away const because ThreadLocalPointer does not support const
+  // void*
+  current_thread_name.Pointer()->Set(const_cast<char*>(name));
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+  // (This should be relatively simple to implement for the BSDs; I
+  // just don't have one handy to test the code on.)
+}
+#endif  // defined(OS_LINUX)
+
+
+#if !defined(OS_MACOSX)
+// Mac is implemented in platform_thread_mac.mm.
+// static
+const char* PlatformThread::GetName() {
+  return current_thread_name.Pointer()->Get();
+}
+#endif
+
+// static
+bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
+                            PlatformThreadHandle* thread_handle) {
+  return CreateThread(stack_size, true /* joinable thread */,
+                      delegate, thread_handle, kThreadPriority_Normal);
+}
+
+// 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, kThreadPriority_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();
+  pthread_join(thread_handle, NULL);
+}
+
+#if !defined(OS_MACOSX)
+// Mac OS X uses lower-level mach APIs.
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle, ThreadPriority) {
+  // TODO(crogers): Implement, see http://crbug.com/116172
+}
+#endif
+
+}  // namespace base
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
new file mode 100644
index 0000000..e37709a
--- /dev/null
+++ b/base/threading/platform_thread_unittest.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/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Trivial tests that thread runs and doesn't crash on create and join ---------
+
+class TrivialThread : public PlatformThread::Delegate {
+ public:
+  TrivialThread() : did_run_(false) {}
+
+  virtual void ThreadMain() OVERRIDE {
+    did_run_ = true;
+  }
+
+  bool did_run() const { return did_run_; }
+
+ private:
+  bool did_run_;
+
+  DISALLOW_COPY_AND_ASSIGN(TrivialThread);
+};
+
+TEST(PlatformThreadTest, Trivial) {
+  TrivialThread thread;
+  PlatformThreadHandle handle = kNullThreadHandle;
+
+  ASSERT_FALSE(thread.did_run());
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  PlatformThread::Join(handle);
+  ASSERT_TRUE(thread.did_run());
+}
+
+TEST(PlatformThreadTest, TrivialTimesTen) {
+  TrivialThread thread[10];
+  PlatformThreadHandle handle[arraysize(thread)];
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_FALSE(thread[n].did_run());
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+  for (size_t n = 0; n < arraysize(thread); n++)
+    PlatformThread::Join(handle[n]);
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_TRUE(thread[n].did_run());
+}
+
+// Tests of basic thread functions ---------------------------------------------
+
+class FunctionTestThread : public TrivialThread {
+ public:
+  FunctionTestThread() : thread_id_(0) {}
+
+  virtual void ThreadMain() OVERRIDE {
+    thread_id_ = PlatformThread::CurrentId();
+    PlatformThread::YieldCurrentThread();
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
+
+    // Make sure that the thread ID is the same across calls.
+    EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
+
+    TrivialThread::ThreadMain();
+  }
+
+  PlatformThreadId thread_id() const { return thread_id_; }
+
+ private:
+  PlatformThreadId thread_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
+};
+
+TEST(PlatformThreadTest, Function) {
+  PlatformThreadId main_thread_id = PlatformThread::CurrentId();
+
+  FunctionTestThread thread;
+  PlatformThreadHandle handle = kNullThreadHandle;
+
+  ASSERT_FALSE(thread.did_run());
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  PlatformThread::Join(handle);
+  ASSERT_TRUE(thread.did_run());
+  EXPECT_NE(thread.thread_id(), main_thread_id);
+
+  // 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].did_run());
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+  for (size_t n = 0; n < arraysize(thread); n++)
+    PlatformThread::Join(handle[n]);
+  for (size_t n = 0; n < arraysize(thread); n++) {
+    ASSERT_TRUE(thread[n].did_run());
+    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());
+    }
+  }
+
+  // Make sure that the thread ID is the same across calls.
+  EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
new file mode 100644
index 0000000..82981ad
--- /dev/null
+++ b/base/threading/platform_thread_win.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#include "base/debug/alias.h"
+#include "base/debug/profiler.h"
+#include "base/logging.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/tracked_objects.h"
+
+#include "base/win/windows_version.h"
+
+namespace base {
+
+namespace {
+
+static ThreadLocalPointer<char> current_thread_name;
+
+// The information on how to set the thread name comes from
+// a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
+const DWORD kVCThreadNameException = 0x406D1388;
+
+typedef struct tagTHREADNAME_INFO {
+  DWORD dwType;  // Must be 0x1000.
+  LPCSTR szName;  // Pointer to name (in user addr space).
+  DWORD dwThreadID;  // Thread ID (-1=caller thread).
+  DWORD dwFlags;  // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+
+// This function has try handling, so it is separated out of its caller.
+void SetNameInternal(PlatformThreadId thread_id, const char* name) {
+  THREADNAME_INFO info;
+  info.dwType = 0x1000;
+  info.szName = name;
+  info.dwThreadID = thread_id;
+  info.dwFlags = 0;
+
+  __try {
+    RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
+                   reinterpret_cast<DWORD_PTR*>(&info));
+  } __except(EXCEPTION_CONTINUE_EXECUTION) {
+  }
+}
+
+struct ThreadParams {
+  PlatformThread::Delegate* delegate;
+  bool joinable;
+};
+
+DWORD __stdcall ThreadFunc(void* params) {
+  ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+  PlatformThread::Delegate* delegate = thread_params->delegate;
+  if (!thread_params->joinable)
+    base::ThreadRestrictions::SetSingletonAllowed(false);
+  delete thread_params;
+  delegate->ThreadMain();
+  return NULL;
+}
+
+// CreateThreadInternal() matches PlatformThread::Create(), except that
+// |out_thread_handle| may be NULL, in which case a non-joinable thread is
+// created.
+bool CreateThreadInternal(size_t stack_size,
+                          PlatformThread::Delegate* delegate,
+                          PlatformThreadHandle* out_thread_handle) {
+  PlatformThreadHandle thread_handle;
+  unsigned int flags = 0;
+  if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
+    flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
+  } else {
+    stack_size = 0;
+  }
+
+  ThreadParams* params = new ThreadParams;
+  params->delegate = delegate;
+  params->joinable = out_thread_handle != NULL;
+
+  // Using CreateThread here vs _beginthreadex makes thread creation a bit
+  // faster and doesn't require the loader lock to be available.  Our code will
+  // have to work running on CreateThread() threads anyway, since we run code
+  // on the Windows thread pool, etc.  For some background on the difference:
+  //   http://www.microsoft.com/msj/1099/win32/win321099.aspx
+  thread_handle = CreateThread(
+      NULL, stack_size, ThreadFunc, params, flags, NULL);
+  if (!thread_handle) {
+    delete params;
+    return false;
+  }
+
+  if (out_thread_handle)
+    *out_thread_handle = thread_handle;
+  else
+    CloseHandle(thread_handle);
+  return true;
+}
+
+}  // namespace
+
+// static
+PlatformThreadId PlatformThread::CurrentId() {
+  return GetCurrentThreadId();
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+  ::Sleep(0);
+}
+
+// static
+void PlatformThread::Sleep(TimeDelta duration) {
+  ::Sleep(duration.InMillisecondsRoundedUp());
+}
+
+// static
+void PlatformThread::SetName(const char* name) {
+  current_thread_name.Set(const_cast<char*>(name));
+
+  // On Windows only, we don't need to tell the profiler about the "BrokerEvent"
+  // thread, as it exists only in the chrome.exe image, and never spawns or runs
+  // tasks (items which could be profiled).  This test avoids the notification,
+  // which would also (as a side effect) initialize the profiler in this unused
+  // context, including setting up thread local storage, etc.  The performance
+  // impact is not terrible, but there is no reason to do initialize it.
+  if (0 != strcmp(name, "BrokerEvent"))
+    tracked_objects::ThreadData::InitializeThreadContext(name);
+
+  // The debugger needs to be around to catch the name in the exception.  If
+  // there isn't a debugger, we are just needlessly throwing an exception.
+  // If this image file is instrumented, we raise the exception anyway
+  // to provide the profiler with human-readable thread names.
+  if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented())
+    return;
+
+  SetNameInternal(CurrentId(), name);
+}
+
+// static
+const char* PlatformThread::GetName() {
+  return current_thread_name.Get();
+}
+
+// static
+bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
+                            PlatformThreadHandle* thread_handle) {
+  DCHECK(thread_handle);
+  return CreateThreadInternal(stack_size, delegate, thread_handle);
+}
+
+// static
+bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
+                                        PlatformThreadHandle* thread_handle,
+                                        ThreadPriority priority) {
+  bool result = Create(stack_size, delegate, thread_handle);
+  if (result)
+    SetThreadPriority(*thread_handle, priority);
+  return result;
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+  return CreateThreadInternal(stack_size, delegate, NULL);
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+  DCHECK(thread_handle);
+  // TODO(willchan): Enable this check once I can get it to work for Windows
+  // shutdown.
+  // Joining another thread may block the current thread for a long time, since
+  // the thread referred to by |thread_handle| may still be running long-lived /
+  // blocking tasks.
+#if 0
+  base::ThreadRestrictions::AssertIOAllowed();
+#endif
+
+  // Wait for the thread to exit.  It should already have terminated but make
+  // sure this assumption is valid.
+  DWORD result = WaitForSingleObject(thread_handle, INFINITE);
+  if (result != WAIT_OBJECT_0) {
+    // Debug info for bug 127931.
+    DWORD error = GetLastError();
+    debug::Alias(&error);
+    debug::Alias(&result);
+    debug::Alias(&thread_handle);
+    CHECK(false);
+  }
+
+  CloseHandle(thread_handle);
+}
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
+                                       ThreadPriority priority) {
+  switch (priority) {
+    case kThreadPriority_Normal:
+      ::SetThreadPriority(handle, THREAD_PRIORITY_NORMAL);
+      break;
+    case kThreadPriority_RealtimeAudio:
+      ::SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL);
+      break;
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc
new file mode 100644
index 0000000..192198b
--- /dev/null
+++ b/base/threading/post_task_and_reply_impl.cc
@@ -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.
+
+#include "base/threading/post_task_and_reply_impl.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/message_loop_proxy.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_loop_(MessageLoopProxy::current()) {
+    task_ = task;
+    reply_ = reply;
+  }
+
+  ~PostTaskAndReplyRelay() {
+    DCHECK(origin_loop_->BelongsToCurrentThread());
+    task_.Reset();
+    reply_.Reset();
+  }
+
+  void Run() {
+    task_.Run();
+    origin_loop_->PostTask(
+        from_here_,
+        Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
+             base::Unretained(this)));
+  }
+
+ private:
+  void RunReplyAndSelfDestruct() {
+    DCHECK(origin_loop_->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<MessageLoopProxy> origin_loop_;
+  Closure reply_;
+  Closure task_;
+};
+
+}  // namespace
+
+namespace internal {
+
+bool PostTaskAndReplyImpl::PostTaskAndReply(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    const Closure& reply) {
+  PostTaskAndReplyRelay* relay =
+      new PostTaskAndReplyRelay(from_here, task, reply);
+  if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
+                                Unretained(relay)))) {
+    delete relay;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/post_task_and_reply_impl.h b/base/threading/post_task_and_reply_impl.h
new file mode 100644
index 0000000..076a46d
--- /dev/null
+++ b/base/threading/post_task_and_reply_impl.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the implementation shared by
+// MessageLoopProxy::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::MessageLoopProxy, or you
+// may want base::WorkerPool.
+class PostTaskAndReplyImpl {
+ public:
+  // Implementation for MessageLoopProxy::PostTaskAndReply and
+  // WorkerPool::PostTaskAndReply.
+  bool PostTaskAndReply(const tracked_objects::Location& from_here,
+                        const Closure& task,
+                        const Closure& reply);
+
+ private:
+  virtual bool PostTask(const tracked_objects::Location& from_here,
+                        const Closure& task) = 0;
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc
new file mode 100644
index 0000000..2258ace
--- /dev/null
+++ b/base/threading/sequenced_worker_pool.cc
@@ -0,0 +1,1120 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/sequenced_worker_pool.h"
+
+#include <list>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/critical_closure.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/memory/linked_ptr.h"
+#include "base/message_loop_proxy.h"
+#include "base/metrics/histogram.h"
+#include "base/stl_util.h"
+#include "base/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_restrictions.h"
+#include "base/time.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace base {
+
+namespace {
+
+struct SequencedTask : public TrackingInfo  {
+  SequencedTask()
+      : sequence_token_id(0),
+        trace_id(0),
+        sequence_task_number(0),
+        shutdown_behavior(SequencedWorkerPool::BLOCK_SHUTDOWN) {}
+
+  explicit SequencedTask(const tracked_objects::Location& from_here)
+      : base::TrackingInfo(from_here, TimeTicks()),
+        sequence_token_id(0),
+        trace_id(0),
+        sequence_task_number(0),
+        shutdown_behavior(SequencedWorkerPool::BLOCK_SHUTDOWN) {}
+
+  ~SequencedTask() {}
+
+  int sequence_token_id;
+  int trace_id;
+  int64 sequence_task_number;
+  SequencedWorkerPool::WorkerShutdown shutdown_behavior;
+  tracked_objects::Location posted_from;
+  Closure task;
+
+  // Non-delayed tasks and delayed tasks are managed together by time-to-run
+  // order. We calculate the time by adding the posted time and the given delay.
+  TimeTicks time_to_run;
+};
+
+struct SequencedTaskLessThan {
+ public:
+  bool operator()(const SequencedTask& lhs, const SequencedTask& rhs) const {
+    if (lhs.time_to_run < rhs.time_to_run)
+      return true;
+
+    if (lhs.time_to_run > rhs.time_to_run)
+      return false;
+
+    // If the time happen to match, then we use the sequence number to decide.
+    return lhs.sequence_task_number < rhs.sequence_task_number;
+  }
+};
+
+// SequencedWorkerPoolTaskRunner ---------------------------------------------
+// A TaskRunner which posts tasks to a SequencedWorkerPool with a
+// fixed ShutdownBehavior.
+//
+// Note that this class is RefCountedThreadSafe (inherited from TaskRunner).
+class SequencedWorkerPoolTaskRunner : public TaskRunner {
+ public:
+  SequencedWorkerPoolTaskRunner(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      SequencedWorkerPool::WorkerShutdown shutdown_behavior);
+
+  // TaskRunner implementation
+  virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               TimeDelta delay) OVERRIDE;
+  virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
+
+ private:
+  virtual ~SequencedWorkerPoolTaskRunner();
+
+  const scoped_refptr<SequencedWorkerPool> pool_;
+
+  const SequencedWorkerPool::WorkerShutdown shutdown_behavior_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolTaskRunner);
+};
+
+SequencedWorkerPoolTaskRunner::SequencedWorkerPoolTaskRunner(
+    const scoped_refptr<SequencedWorkerPool>& pool,
+    SequencedWorkerPool::WorkerShutdown shutdown_behavior)
+    : pool_(pool),
+      shutdown_behavior_(shutdown_behavior) {
+}
+
+SequencedWorkerPoolTaskRunner::~SequencedWorkerPoolTaskRunner() {
+}
+
+bool SequencedWorkerPoolTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  if (delay == TimeDelta()) {
+    return pool_->PostWorkerTaskWithShutdownBehavior(
+        from_here, task, shutdown_behavior_);
+  }
+  return pool_->PostDelayedWorkerTask(from_here, task, delay);
+}
+
+bool SequencedWorkerPoolTaskRunner::RunsTasksOnCurrentThread() const {
+  return pool_->RunsTasksOnCurrentThread();
+}
+
+// SequencedWorkerPoolSequencedTaskRunner ------------------------------------
+// A SequencedTaskRunner which posts tasks to a SequencedWorkerPool with a
+// fixed sequence token.
+//
+// Note that this class is RefCountedThreadSafe (inherited from TaskRunner).
+class SequencedWorkerPoolSequencedTaskRunner : public SequencedTaskRunner {
+ public:
+  SequencedWorkerPoolSequencedTaskRunner(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      SequencedWorkerPool::SequenceToken token,
+      SequencedWorkerPool::WorkerShutdown shutdown_behavior);
+
+  // TaskRunner implementation
+  virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               TimeDelta delay) OVERRIDE;
+  virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
+
+  // SequencedTaskRunner implementation
+  virtual bool PostNonNestableDelayedTask(
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      TimeDelta delay) OVERRIDE;
+
+ private:
+  virtual ~SequencedWorkerPoolSequencedTaskRunner();
+
+  const scoped_refptr<SequencedWorkerPool> pool_;
+
+  const SequencedWorkerPool::SequenceToken token_;
+
+  const SequencedWorkerPool::WorkerShutdown shutdown_behavior_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolSequencedTaskRunner);
+};
+
+SequencedWorkerPoolSequencedTaskRunner::SequencedWorkerPoolSequencedTaskRunner(
+    const scoped_refptr<SequencedWorkerPool>& pool,
+    SequencedWorkerPool::SequenceToken token,
+    SequencedWorkerPool::WorkerShutdown shutdown_behavior)
+    : pool_(pool),
+      token_(token),
+      shutdown_behavior_(shutdown_behavior) {
+}
+
+SequencedWorkerPoolSequencedTaskRunner::
+~SequencedWorkerPoolSequencedTaskRunner() {
+}
+
+bool SequencedWorkerPoolSequencedTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  if (delay == TimeDelta()) {
+    return pool_->PostSequencedWorkerTaskWithShutdownBehavior(
+        token_, from_here, task, shutdown_behavior_);
+  }
+  return pool_->PostDelayedSequencedWorkerTask(token_, from_here, task, delay);
+}
+
+bool SequencedWorkerPoolSequencedTaskRunner::RunsTasksOnCurrentThread() const {
+  return pool_->IsRunningSequenceOnCurrentThread(token_);
+}
+
+bool SequencedWorkerPoolSequencedTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  return pool_->PostDelayedSequencedWorkerTask(token_, from_here, task, delay);
+}
+
+// Create a process-wide unique ID to represent this task in trace events. This
+// will be mangled with a Process ID hash to reduce the likelyhood of colliding
+// with MessageLoop pointers on other processes.
+uint64 GetTaskTraceID(const SequencedTask& task,
+                      void* pool) {
+  return (static_cast<uint64>(task.trace_id) << 32) |
+         static_cast<uint64>(reinterpret_cast<intptr_t>(pool));
+}
+
+}  // namespace
+
+// Worker ---------------------------------------------------------------------
+
+class SequencedWorkerPool::Worker : public SimpleThread {
+ public:
+  // Hold a (cyclic) ref to |worker_pool|, since we want to keep it
+  // around as long as we are running.
+  Worker(const scoped_refptr<SequencedWorkerPool>& worker_pool,
+         int thread_number,
+         const std::string& thread_name_prefix);
+  virtual ~Worker();
+
+  // SimpleThread implementation. This actually runs the background thread.
+  virtual void Run() OVERRIDE;
+
+  void set_running_sequence(SequenceToken token) {
+    running_sequence_ = token;
+  }
+
+  SequenceToken running_sequence() const {
+    return running_sequence_;
+  }
+
+ private:
+  scoped_refptr<SequencedWorkerPool> worker_pool_;
+  SequenceToken running_sequence_;
+
+  DISALLOW_COPY_AND_ASSIGN(Worker);
+};
+
+// Inner ----------------------------------------------------------------------
+
+class SequencedWorkerPool::Inner {
+ public:
+  // Take a raw pointer to |worker| to avoid cycles (since we're owned
+  // by it).
+  Inner(SequencedWorkerPool* worker_pool, size_t max_threads,
+        const std::string& thread_name_prefix,
+        TestingObserver* observer);
+
+  ~Inner();
+
+  SequenceToken GetSequenceToken();
+
+  SequenceToken GetNamedSequenceToken(const std::string& name);
+
+  // This function accepts a name and an ID. If the name is null, the
+  // token ID is used. This allows us to implement the optional name lookup
+  // from a single function without having to enter the lock a separate time.
+  bool PostTask(const std::string* optional_token_name,
+                SequenceToken sequence_token,
+                WorkerShutdown shutdown_behavior,
+                const tracked_objects::Location& from_here,
+                const Closure& task,
+                TimeDelta delay);
+
+  bool RunsTasksOnCurrentThread() const;
+
+  bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
+
+  void FlushForTesting();
+
+  void SignalHasWorkForTesting();
+
+  int GetWorkSignalCountForTesting() const;
+
+  void Shutdown();
+
+  // 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,
+  };
+
+  // Returns whether there are no more pending tasks and all threads
+  // are idle.  Must be called under lock.
+  bool IsIdle() const;
+
+  // Called from within the lock, this converts the given token name into a
+  // token ID, creating a new one if necessary.
+  int LockedGetNamedTokenID(const std::string& name);
+
+  // Called from within the lock, this returns the next sequence task number.
+  int64 LockedGetNextSequenceTaskNumber();
+
+  // Gets new task. There are 3 cases depending on the return value:
+  //
+  // 1) If the return value is |GET_WORK_FOUND|, |task| is filled in and should
+  //    be run immediately.
+  // 2) If the return value is |GET_WORK_NOT_FOUND|, there are no tasks to run,
+  //    and |task| is not filled in. In this case, the caller should wait until
+  //    a task is posted.
+  // 3) If the return value is |GET_WORK_WAIT|, there are no tasks to run
+  //    immediately, and |task| is not filled in. Likewise, |wait_time| is
+  //    filled in the time to wait until the next task to run. In this case, the
+  //    caller should wait the time.
+  //
+  // In any case, the calling code should clear the given
+  // delete_these_outside_lock vector the next time the lock is released.
+  // See the implementation for a more detailed description.
+  GetWorkStatus GetWork(SequencedTask* task,
+                        TimeDelta* wait_time,
+                        std::vector<Closure>* delete_these_outside_lock);
+
+  // 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.
+  volatile subtle::Atomic32 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
+  // FlushForTesting()) until IsIdle() goes to true.
+  ConditionVariable is_idle_cv_;
+
+  // Condition variable that is waited on by non-worker threads (in
+  // Shutdown()) until CanShutdown() goes to true.
+  ConditionVariable can_shutdown_cv_;
+
+  // The maximum number of worker threads we'll create.
+  const size_t max_threads_;
+
+  const std::string thread_name_prefix_;
+
+  // Associates all known sequence token names with their IDs.
+  std::map<std::string, int> named_sequence_tokens_;
+
+  // Owning pointers to all threads we've created so far, indexed by
+  // ID. Since we lazily create threads, this may be less than
+  // max_threads_ and will be initially empty.
+  typedef std::map<PlatformThreadId, linked_ptr<Worker> > ThreadMap;
+  ThreadMap threads_;
+
+  // Set to true when we're in the process of creating another thread.
+  // See PrepareToStartAdditionalThreadIfHelpful for more.
+  bool thread_being_created_;
+
+  // Number of threads currently waiting for work.
+  size_t waiting_thread_count_;
+
+  // Number of threads currently running tasks that have the BLOCK_SHUTDOWN
+  // or SKIP_ON_SHUTDOWN flag set.
+  size_t blocking_shutdown_thread_count_;
+
+  // A set of all pending tasks in time-to-run order. These are tasks that are
+  // either waiting for a thread to run on, waiting for their time to run,
+  // or blocked on a previous task in their sequence. We have to iterate over
+  // the tasks by time-to-run order, so we use the set instead of the
+  // traditional priority_queue.
+  typedef std::set<SequencedTask, SequencedTaskLessThan> PendingTaskSet;
+  PendingTaskSet pending_tasks_;
+
+  // The next sequence number for a new sequenced task.
+  int64 next_sequence_task_number_;
+
+  // Number of tasks in the pending_tasks_ list that are marked as blocking
+  // shutdown.
+  size_t blocking_shutdown_pending_task_count_;
+
+  // Lists all sequence tokens currently executing.
+  std::set<int> current_sequences_;
+
+  // An ID for each posted task to distinguish the task from others in traces.
+  int trace_id_;
+
+  // Set when Shutdown is called and no further tasks should be
+  // allowed, though we may still be running existing tasks.
+  bool shutdown_called_;
+
+  TestingObserver* const testing_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(Inner);
+};
+
+// Worker definitions ---------------------------------------------------------
+
+SequencedWorkerPool::Worker::Worker(
+    const scoped_refptr<SequencedWorkerPool>& worker_pool,
+    int thread_number,
+    const std::string& prefix)
+    : SimpleThread(
+          prefix + StringPrintf("Worker%d", thread_number).c_str()),
+      worker_pool_(worker_pool) {
+  Start();
+}
+
+SequencedWorkerPool::Worker::~Worker() {
+}
+
+void SequencedWorkerPool::Worker::Run() {
+  // Just jump back to the Inner object to run the thread, since it has all the
+  // tracking information and queues. It might be more natural to implement
+  // using DelegateSimpleThread and have Inner implement the Delegate to avoid
+  // having these worker objects at all, but that method lacks the ability to
+  // send thread-specific information easily to the thread loop.
+  worker_pool_->inner_->ThreadLoop(this);
+  // Release our cyclic reference once we're done.
+  worker_pool_ = NULL;
+}
+
+// Inner definitions ---------------------------------------------------------
+
+SequencedWorkerPool::Inner::Inner(
+    SequencedWorkerPool* worker_pool,
+    size_t max_threads,
+    const std::string& thread_name_prefix,
+    TestingObserver* observer)
+    : worker_pool_(worker_pool),
+      last_sequence_number_(0),
+      lock_(),
+      has_work_cv_(&lock_),
+      is_idle_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),
+      testing_observer_(observer) {}
+
+SequencedWorkerPool::Inner::~Inner() {
+  // You must call Shutdown() before destroying the pool.
+  DCHECK(shutdown_called_);
+
+  // Need to explicitly join with the threads before they're destroyed or else
+  // they will be running when our object is half torn down.
+  for (ThreadMap::iterator it = threads_.begin(); it != threads_.end(); ++it)
+    it->second->Join();
+  threads_.clear();
+
+  if (testing_observer_)
+    testing_observer_->OnDestruct();
+}
+
+SequencedWorkerPool::SequenceToken
+SequencedWorkerPool::Inner::GetSequenceToken() {
+  subtle::Atomic32 result =
+      subtle::NoBarrier_AtomicIncrement(&last_sequence_number_, 1);
+  return SequenceToken(static_cast<int>(result));
+}
+
+SequencedWorkerPool::SequenceToken
+SequencedWorkerPool::Inner::GetNamedSequenceToken(const std::string& name) {
+  AutoLock lock(lock_);
+  return SequenceToken(LockedGetNamedTokenID(name));
+}
+
+bool SequencedWorkerPool::Inner::PostTask(
+    const std::string* optional_token_name,
+    SequenceToken sequence_token,
+    WorkerShutdown shutdown_behavior,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  DCHECK(delay == TimeDelta() || shutdown_behavior == SKIP_ON_SHUTDOWN);
+  SequencedTask sequenced(from_here);
+  sequenced.sequence_token_id = sequence_token.id_;
+  sequenced.shutdown_behavior = shutdown_behavior;
+  sequenced.posted_from = from_here;
+  sequenced.task =
+      shutdown_behavior == BLOCK_SHUTDOWN ?
+      base::MakeCriticalClosure(task) : task;
+  sequenced.time_to_run = TimeTicks::Now() + delay;
+
+  int create_thread_id = 0;
+  {
+    AutoLock lock(lock_);
+    if (shutdown_called_)
+      return false;
+
+    // The trace_id is used for identifying the task in about:tracing.
+    sequenced.trace_id = trace_id_++;
+
+    TRACE_EVENT_FLOW_BEGIN0("task", "SequencedWorkerPool::PostTask",
+        TRACE_ID_MANGLE(GetTaskTraceID(sequenced, static_cast<void*>(this))));
+
+    sequenced.sequence_task_number = LockedGetNextSequenceTaskNumber();
+
+    // Now that we have the lock, apply the named token rules.
+    if (optional_token_name)
+      sequenced.sequence_token_id = LockedGetNamedTokenID(*optional_token_name);
+
+    pending_tasks_.insert(sequenced);
+    if (shutdown_behavior == BLOCK_SHUTDOWN)
+      blocking_shutdown_pending_task_count_++;
+
+    create_thread_id = PrepareToStartAdditionalThreadIfHelpful();
+  }
+
+  // Actually start the additional thread or signal an existing one now that
+  // we're outside the lock.
+  if (create_thread_id)
+    FinishStartingAdditionalThread(create_thread_id);
+  else
+    SignalHasWork();
+
+  return true;
+}
+
+bool SequencedWorkerPool::Inner::RunsTasksOnCurrentThread() const {
+  AutoLock lock(lock_);
+  return ContainsKey(threads_, PlatformThread::CurrentId());
+}
+
+bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread(
+    SequenceToken sequence_token) const {
+  AutoLock lock(lock_);
+  ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId());
+  if (found == threads_.end())
+    return false;
+  return found->second->running_sequence().Equals(sequence_token);
+}
+
+void SequencedWorkerPool::Inner::FlushForTesting() {
+  AutoLock lock(lock_);
+  while (!IsIdle())
+    is_idle_cv_.Wait();
+}
+
+void SequencedWorkerPool::Inner::SignalHasWorkForTesting() {
+  SignalHasWork();
+}
+
+void SequencedWorkerPool::Inner::Shutdown() {
+  // Mark us as terminated and go through and drop all tasks that aren't
+  // required to run on shutdown. Since no new tasks will get posted once the
+  // terminated flag is set, this ensures that all remaining tasks are required
+  // for shutdown whenever the termianted_ flag is set.
+  {
+    AutoLock lock(lock_);
+
+    if (shutdown_called_)
+      return;
+    shutdown_called_ = true;
+
+    // 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();
+
+  TimeTicks shutdown_wait_begin = TimeTicks::Now();
+
+  {
+    base::ThreadRestrictions::ScopedAllowWait allow_wait;
+    AutoLock lock(lock_);
+    while (!CanShutdown())
+      can_shutdown_cv_.Wait();
+  }
+  UMA_HISTOGRAM_TIMES("SequencedWorkerPool.ShutdownDelayTime",
+                      TimeTicks::Now() - shutdown_wait_begin);
+}
+
+void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
+  {
+    AutoLock lock(lock_);
+    DCHECK(thread_being_created_);
+    thread_being_created_ = false;
+    std::pair<ThreadMap::iterator, bool> result =
+        threads_.insert(
+            std::make_pair(this_worker->tid(), make_linked_ptr(this_worker)));
+    DCHECK(result.second);
+
+    while (true) {
+#if defined(OS_MACOSX)
+      base::mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+      // See GetWork for what delete_these_outside_lock is doing.
+      SequencedTask task;
+      TimeDelta wait_time;
+      std::vector<Closure> delete_these_outside_lock;
+      GetWorkStatus status =
+          GetWork(&task, &wait_time, &delete_these_outside_lock);
+      if (status == GET_WORK_FOUND) {
+        TRACE_EVENT_FLOW_END0("task", "SequencedWorkerPool::PostTask",
+            TRACE_ID_MANGLE(GetTaskTraceID(task, static_cast<void*>(this))));
+        TRACE_EVENT2("task", "SequencedWorkerPool::ThreadLoop",
+                     "src_file", task.posted_from.file_name(),
+                     "src_func", task.posted_from.function_name());
+        int new_thread_id = WillRunWorkerTask(task);
+        {
+          AutoUnlock unlock(lock_);
+          // There may be more work available, so wake up another
+          // worker thread. (Technically not required, since we
+          // already get a signal for each new task, but it doesn't
+          // hurt.)
+          SignalHasWork();
+          delete_these_outside_lock.clear();
+
+          // Complete thread creation outside the lock if necessary.
+          if (new_thread_id)
+            FinishStartingAdditionalThread(new_thread_id);
+
+          this_worker->set_running_sequence(
+              SequenceToken(task.sequence_token_id));
+
+          tracked_objects::TrackedTime start_time =
+              tracked_objects::ThreadData::NowForStartOfRun(task.birth_tally);
+
+          task.task.Run();
+
+          tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(task,
+              start_time, tracked_objects::ThreadData::NowForEndOfRun());
+
+          this_worker->set_running_sequence(SequenceToken());
+
+          // Make sure our task is erased outside the lock for the same reason
+          // we do this with delete_these_oustide_lock.
+          task.task = Closure();
+        }
+        DidRunWorkerTask(task);  // Must be done inside the lock.
+      } else {
+        // When we're terminating and there's no more work, we can
+        // shut down.  You can't get more tasks posted once
+        // shutdown_called_ is set. 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)
+          break;
+        waiting_thread_count_++;
+        // This is the only time that IsIdle() can go to true.
+        if (IsIdle())
+          is_idle_cv_.Signal();
+
+        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();
+}
+
+bool SequencedWorkerPool::Inner::IsIdle() const {
+  lock_.AssertAcquired();
+  return pending_tasks_.empty() && waiting_thread_count_ == threads_.size();
+}
+
+int SequencedWorkerPool::Inner::LockedGetNamedTokenID(
+    const std::string& name) {
+  lock_.AssertAcquired();
+  DCHECK(!name.empty());
+
+  std::map<std::string, int>::const_iterator found =
+      named_sequence_tokens_.find(name);
+  if (found != named_sequence_tokens_.end())
+    return found->second;  // Got an existing one.
+
+  // Create a new one for this name.
+  SequenceToken result = GetSequenceToken();
+  named_sequence_tokens_.insert(std::make_pair(name, result.id_));
+  return result.id_;
+}
+
+int64 SequencedWorkerPool::Inner::LockedGetNextSequenceTaskNumber() {
+  lock_.AssertAcquired();
+  // We assume that we never create enough tasks to wrap around.
+  return next_sequence_task_number_++;
+}
+
+SequencedWorkerPool::Inner::GetWorkStatus SequencedWorkerPool::Inner::GetWork(
+    SequencedTask* task,
+    TimeDelta* wait_time,
+    std::vector<Closure>* delete_these_outside_lock) {
+  lock_.AssertAcquired();
+
+  UMA_HISTOGRAM_COUNTS_100("SequencedWorkerPool.TaskCount",
+                           static_cast<int>(pending_tasks_.size()));
+
+  // 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 (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;
+      break;
+    }
+
+    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++);
+    } else {
+      // 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;
+    }
+  }
+
+  // Track the number of tasks we had to skip over to see if we should be
+  // making this more efficient. If this number ever becomes large or is
+  // frequently "some", we should consider the optimization above.
+  UMA_HISTOGRAM_COUNTS_100("SequencedWorkerPool.UnrunnableTaskCount",
+                           unrunnable_tasks);
+  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_ &&
+      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(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;
+}
+
+// SequencedWorkerPool --------------------------------------------------------
+
+SequencedWorkerPool::SequencedWorkerPool(
+    size_t max_threads,
+    const std::string& thread_name_prefix)
+    : constructor_message_loop_(MessageLoopProxy::current()),
+      inner_(new Inner(ALLOW_THIS_IN_INITIALIZER_LIST(this),
+                       max_threads, thread_name_prefix, NULL)) {
+}
+
+SequencedWorkerPool::SequencedWorkerPool(
+    size_t max_threads,
+    const std::string& thread_name_prefix,
+    TestingObserver* observer)
+    : constructor_message_loop_(MessageLoopProxy::current()),
+      inner_(new Inner(ALLOW_THIS_IN_INITIALIZER_LIST(this),
+                       max_threads, thread_name_prefix, observer)) {
+}
+
+SequencedWorkerPool::~SequencedWorkerPool() {}
+
+void SequencedWorkerPool::OnDestruct() const {
+  DCHECK(constructor_message_loop_.get());
+  // Avoid deleting ourselves on a worker thread (which would
+  // deadlock).
+  if (RunsTasksOnCurrentThread()) {
+    constructor_message_loop_->DeleteSoon(FROM_HERE, this);
+  } else {
+    delete this;
+  }
+}
+
+SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetSequenceToken() {
+  return inner_->GetSequenceToken();
+}
+
+SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetNamedSequenceToken(
+    const std::string& name) {
+  return inner_->GetNamedSequenceToken(name);
+}
+
+scoped_refptr<SequencedTaskRunner> SequencedWorkerPool::GetSequencedTaskRunner(
+    SequenceToken token) {
+  return GetSequencedTaskRunnerWithShutdownBehavior(token, BLOCK_SHUTDOWN);
+}
+
+scoped_refptr<SequencedTaskRunner>
+SequencedWorkerPool::GetSequencedTaskRunnerWithShutdownBehavior(
+    SequenceToken token, WorkerShutdown shutdown_behavior) {
+  return new SequencedWorkerPoolSequencedTaskRunner(
+      this, token, shutdown_behavior);
+}
+
+scoped_refptr<TaskRunner>
+SequencedWorkerPool::GetTaskRunnerWithShutdownBehavior(
+    WorkerShutdown shutdown_behavior) {
+  return new SequencedWorkerPoolTaskRunner(this, shutdown_behavior);
+}
+
+bool SequencedWorkerPool::PostWorkerTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return inner_->PostTask(NULL, SequenceToken(), BLOCK_SHUTDOWN,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostDelayedWorkerTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  WorkerShutdown shutdown_behavior =
+      delay == TimeDelta() ? BLOCK_SHUTDOWN : SKIP_ON_SHUTDOWN;
+  return inner_->PostTask(NULL, SequenceToken(), shutdown_behavior,
+                          from_here, task, delay);
+}
+
+bool SequencedWorkerPool::PostWorkerTaskWithShutdownBehavior(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    WorkerShutdown shutdown_behavior) {
+  return inner_->PostTask(NULL, SequenceToken(), shutdown_behavior,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostSequencedWorkerTask(
+    SequenceToken sequence_token,
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return inner_->PostTask(NULL, sequence_token, BLOCK_SHUTDOWN,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostDelayedSequencedWorkerTask(
+    SequenceToken sequence_token,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  WorkerShutdown shutdown_behavior =
+      delay == TimeDelta() ? BLOCK_SHUTDOWN : SKIP_ON_SHUTDOWN;
+  return inner_->PostTask(NULL, sequence_token, shutdown_behavior,
+                          from_here, task, delay);
+}
+
+bool SequencedWorkerPool::PostNamedSequencedWorkerTask(
+    const std::string& token_name,
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  DCHECK(!token_name.empty());
+  return inner_->PostTask(&token_name, SequenceToken(), BLOCK_SHUTDOWN,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostSequencedWorkerTaskWithShutdownBehavior(
+    SequenceToken sequence_token,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    WorkerShutdown shutdown_behavior) {
+  return inner_->PostTask(NULL, sequence_token, shutdown_behavior,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  return PostDelayedWorkerTask(from_here, task, delay);
+}
+
+bool SequencedWorkerPool::RunsTasksOnCurrentThread() const {
+  return inner_->RunsTasksOnCurrentThread();
+}
+
+bool SequencedWorkerPool::IsRunningSequenceOnCurrentThread(
+    SequenceToken sequence_token) const {
+  return inner_->IsRunningSequenceOnCurrentThread(sequence_token);
+}
+
+void SequencedWorkerPool::FlushForTesting() {
+  inner_->FlushForTesting();
+}
+
+void SequencedWorkerPool::SignalHasWorkForTesting() {
+  inner_->SignalHasWorkForTesting();
+}
+
+void SequencedWorkerPool::Shutdown() {
+  DCHECK(constructor_message_loop_->BelongsToCurrentThread());
+  inner_->Shutdown();
+}
+
+}  // namespace base
diff --git a/base/threading/sequenced_worker_pool.h b/base/threading/sequenced_worker_pool.h
new file mode 100644
index 0000000..72abd2b
--- /dev/null
+++ b/base/threading/sequenced_worker_pool.h
@@ -0,0 +1,323 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_SEQUENCED_WORKER_POOL_H_
+#define BASE_THREADING_SEQUENCED_WORKER_POOL_H_
+
+#include <cstddef>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/task_runner.h"
+
+namespace tracked_objects {
+class Location;
+}  // namespace tracked_objects
+
+namespace base {
+
+class MessageLoopProxy;
+
+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.
+//
+// Example:
+//   SequencedWorkerPool::SequenceToken token = pool.GetSequenceToken();
+//   pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
+//                                FROM_HERE, base::Bind(...));
+//   pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
+//                                FROM_HERE, base::Bind(...));
+//
+// You can make named sequence tokens to make it easier to share a token
+// across different components.
+//
+// You can also post tasks to the pool without ordering using PostWorkerTask.
+// These will be executed in an unspecified order. The order of execution
+// between tasks with different sequence tokens is also unspecified.
+//
+// This class is designed to be leaked on shutdown to allow the
+// CONTINUE_ON_SHUTDOWN behavior to be implemented. To enforce the
+// BLOCK_SHUTDOWN behavior, you must call Shutdown() which will wait until
+// the necessary tasks have completed.
+//
+// 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).
+class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
+ public:
+  // Defines what should happen to a task posted to the worker pool on
+  // shutdown.
+  enum WorkerShutdown {
+    // Tasks posted with this mode which have not run at shutdown will be
+    // deleted rather than run, and any tasks with this mode running at
+    // shutdown will be ignored (the worker thread will not be joined).
+    //
+    // This option provides a nice way to post stuff you don't want blocking
+    // shutdown. For example, you might be doing a slow DNS lookup and if it's
+    // blocked on the OS, you may not want to stop shutdown, since the result
+    // doesn't really matter at that point.
+    //
+    // However, you need to be very careful what you do in your callback when
+    // you use this option. Since the thread will continue to run until the OS
+    // terminates the process, the app can be in the process of tearing down
+    // when you're running. This means any singletons or global objects you
+    // use may suddenly become invalid out from under you. For this reason,
+    // it's best to use this only for slow but simple operations like the DNS
+    // example.
+    CONTINUE_ON_SHUTDOWN,
+
+    // Tasks posted with this mode that have not started executing at
+    // shutdown will be deleted rather than executed. However, any tasks that
+    // have already begun executing when shutdown is called will be allowed
+    // to continue, and will block shutdown until completion.
+    //
+    // Note: Because Shutdown() may block while these tasks are executing,
+    // care must be taken to ensure that they do not block on the thread that
+    // called Shutdown(), as this may lead to deadlock.
+    SKIP_ON_SHUTDOWN,
+
+    // Tasks posted with this mode will block shutdown until they're
+    // executed. Since this can have significant performance implications,
+    // use sparingly.
+    //
+    // Generally, this should be used only for user data, for example, a task
+    // writing a preference file.
+    //
+    // If a task is posted during shutdown, it will not get run since the
+    // workers may already be stopped. In this case, the post operation will
+    // fail (return false) and the task will be deleted.
+    BLOCK_SHUTDOWN,
+  };
+
+  // Opaque identifier that defines sequencing of tasks posted to the worker
+  // pool.
+  class SequenceToken {
+   public:
+    SequenceToken() : id_(0) {}
+    ~SequenceToken() {}
+
+    bool Equals(const SequenceToken& other) const {
+      return id_ == other.id_;
+    }
+
+   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;
+  };
+
+  // When constructing a SequencedWorkerPool, there must be a
+  // MessageLoop on the current thread unless you plan to deliberately
+  // leak it.
+
+  // Pass the maximum number of threads (they will be lazily created as needed)
+  // and a prefix for the thread name to aid in debugging.
+  SequencedWorkerPool(size_t max_threads,
+                      const std::string& thread_name_prefix);
+
+  // Like above, but with |observer| for testing.  Does not take
+  // ownership of |observer|.
+  SequencedWorkerPool(size_t max_threads,
+                      const std::string& thread_name_prefix,
+                      TestingObserver* observer);
+
+  // Returns a unique token that can be used to sequence tasks posted to
+  // PostSequencedWorkerTask(). Valid tokens are alwys nonzero.
+  SequenceToken GetSequenceToken();
+
+  // Returns the sequence token associated with the given name. Calling this
+  // function multiple times with the same string will always produce the
+  // same sequence token. If the name has not been used before, a new token
+  // will be created.
+  SequenceToken GetNamedSequenceToken(const std::string& name);
+
+  // Returns a SequencedTaskRunner wrapper which posts to this
+  // SequencedWorkerPool using the given sequence token. Tasks with nonzero
+  // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay
+  // are posted with BLOCK_SHUTDOWN behavior.
+  scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunner(
+      SequenceToken token);
+
+  // Returns a SequencedTaskRunner wrapper which posts to this
+  // SequencedWorkerPool using the given sequence token. Tasks with nonzero
+  // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay
+  // are posted with the given shutdown behavior.
+  scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunnerWithShutdownBehavior(
+      SequenceToken token,
+      WorkerShutdown shutdown_behavior);
+
+  // Returns a TaskRunner wrapper which posts to this SequencedWorkerPool using
+  // the given shutdown behavior. Tasks with nonzero delay are posted with
+  // SKIP_ON_SHUTDOWN behavior and tasks with zero delay are posted with the
+  // given shutdown behavior.
+  scoped_refptr<TaskRunner> GetTaskRunnerWithShutdownBehavior(
+      WorkerShutdown shutdown_behavior);
+
+  // Posts the given task for execution in the worker pool. Tasks posted with
+  // this function will execute in an unspecified order on a background thread.
+  // Returns true if the task was posted. If your tasks have ordering
+  // requirements, see PostSequencedWorkerTask().
+  //
+  // This class will attempt to delete tasks that aren't run
+  // (non-block-shutdown semantics) but can't guarantee that this happens. If
+  // all worker threads are busy running CONTINUE_ON_SHUTDOWN tasks, there
+  // will be no workers available to delete these tasks. And there may be
+  // tasks with the same sequence token behind those CONTINUE_ON_SHUTDOWN
+  // tasks. Deleting those tasks before the previous one has completed could
+  // cause nondeterministic crashes because the task could be keeping some
+  // objects alive which do work in their destructor, which could voilate the
+  // assumptions of the running task.
+  //
+  // The task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  //
+  // Returns true if the task was posted successfully. This may fail during
+  // shutdown regardless of the specified ShutdownBehavior.
+  bool PostWorkerTask(const tracked_objects::Location& from_here,
+                      const Closure& task);
+
+  // Same as PostWorkerTask but allows a delay to be specified (although doing
+  // so changes the shutdown behavior). The task will be run after the given
+  // delay has elapsed.
+  //
+  // If the delay is nonzero, the task won't be guaranteed to run to completion
+  // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs.
+  // If the delay is zero, this behaves exactly like PostWorkerTask, i.e. the
+  // task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  bool PostDelayedWorkerTask(const tracked_objects::Location& from_here,
+                             const Closure& task,
+                             TimeDelta delay);
+
+  // Same as PostWorkerTask but allows specification of the shutdown behavior.
+  bool PostWorkerTaskWithShutdownBehavior(
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      WorkerShutdown shutdown_behavior);
+
+  // Like PostWorkerTask above, but provides sequencing semantics. This means
+  // that tasks posted with the same sequence token (see GetSequenceToken())
+  // are guaranteed to execute in order. This is useful in cases where you're
+  // doing operations that may depend on previous ones, like appending to a
+  // file.
+  //
+  // The task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  //
+  // Returns true if the task was posted successfully. This may fail during
+  // shutdown regardless of the specified ShutdownBehavior.
+  bool PostSequencedWorkerTask(SequenceToken sequence_token,
+                               const tracked_objects::Location& from_here,
+                               const Closure& task);
+
+  // Like PostSequencedWorkerTask above, but allows you to specify a named
+  // token, which saves an extra call to GetNamedSequenceToken.
+  bool PostNamedSequencedWorkerTask(const std::string& token_name,
+                                    const tracked_objects::Location& from_here,
+                                    const Closure& task);
+
+  // Same as PostSequencedWorkerTask but allows a delay to be specified
+  // (although doing so changes the shutdown behavior). The task will be run
+  // after the given delay has elapsed.
+  //
+  // If the delay is nonzero, the task won't be guaranteed to run to completion
+  // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs.
+  // If the delay is zero, this behaves exactly like PostSequencedWorkerTask,
+  // i.e. the task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  bool PostDelayedSequencedWorkerTask(
+      SequenceToken sequence_token,
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      TimeDelta delay);
+
+  // Same as PostSequencedWorkerTask but allows specification of the shutdown
+  // behavior.
+  bool PostSequencedWorkerTaskWithShutdownBehavior(
+      SequenceToken sequence_token,
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      WorkerShutdown shutdown_behavior);
+
+  // TaskRunner implementation. Forwards to PostDelayedWorkerTask().
+  virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               TimeDelta delay) OVERRIDE;
+  virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
+
+  // Returns true if the current thread is processing a task with the given
+  // sequence_token.
+  bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
+
+  // Blocks until all pending tasks are complete. This should only be called in
+  // unit tests when you want to validate something that should have happened.
+  //
+  // 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();
+
+ protected:
+  virtual ~SequencedWorkerPool();
+
+  virtual void OnDestruct() const OVERRIDE;
+
+ private:
+  friend class RefCountedThreadSafe<SequencedWorkerPool>;
+  friend class DeleteHelper<SequencedWorkerPool>;
+
+  class Inner;
+  class Worker;
+
+  const scoped_refptr<MessageLoopProxy> constructor_message_loop_;
+
+  // Avoid pulling in too many headers by putting (almost) everything
+  // into |inner_|.
+  const scoped_ptr<Inner> inner_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPool);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SEQUENCED_WORKER_POOL_H_
diff --git a/base/threading/sequenced_worker_pool_unittest.cc b/base/threading/sequenced_worker_pool_unittest.cc
new file mode 100644
index 0000000..2dcda60
--- /dev/null
+++ b/base/threading/sequenced_worker_pool_unittest.cc
@@ -0,0 +1,752 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/sequenced_worker_pool.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/test/sequenced_task_runner_test_template.h"
+#include "base/test/task_runner_test_template.h"
+#include "base/threading/platform_thread.h"
+#include "base/tracked_objects.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// IMPORTANT NOTE:
+//
+// Many of these tests have failure modes where they'll hang forever. These
+// tests should not be flaky, and hangling indicates a type of failure. Do not
+// mark as flaky if they're hanging, it's likely an actual bug.
+
+namespace {
+
+const size_t kNumWorkerThreads = 3;
+
+// Allows a number of threads to all be blocked on the same event, and
+// provides a way to unblock a certain number of them.
+class ThreadBlocker {
+ public:
+  ThreadBlocker() : lock_(), cond_var_(&lock_), unblock_counter_(0) {}
+
+  void Block() {
+    {
+      base::AutoLock lock(lock_);
+      while (unblock_counter_ == 0)
+        cond_var_.Wait();
+      unblock_counter_--;
+    }
+    cond_var_.Signal();
+  }
+
+  void Unblock(size_t count) {
+    {
+      base::AutoLock lock(lock_);
+      DCHECK(unblock_counter_ == 0);
+      unblock_counter_ = count;
+    }
+    cond_var_.Signal();
+  }
+
+ private:
+  base::Lock lock_;
+  base::ConditionVariable cond_var_;
+
+  size_t unblock_counter_;
+};
+
+class TestTracker : public base::RefCountedThreadSafe<TestTracker> {
+ public:
+  TestTracker()
+      : lock_(),
+        cond_var_(&lock_),
+        started_events_(0) {
+  }
+
+  // Each of these tasks appends the argument to the complete sequence vector
+  // so calling code can see what order they finished in.
+  void FastTask(int id) {
+    SignalWorkerDone(id);
+  }
+
+  void SlowTask(int id) {
+    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+    SignalWorkerDone(id);
+  }
+
+  void BlockTask(int id, ThreadBlocker* blocker) {
+    // Note that this task has started and signal anybody waiting for that
+    // to happen.
+    {
+      base::AutoLock lock(lock_);
+      started_events_++;
+    }
+    cond_var_.Signal();
+
+    blocker->Block();
+    SignalWorkerDone(id);
+  }
+
+  // Waits until the given number of tasks have started executing.
+  void WaitUntilTasksBlocked(size_t count) {
+    {
+      base::AutoLock lock(lock_);
+      while (started_events_ < count)
+        cond_var_.Wait();
+    }
+    cond_var_.Signal();
+  }
+
+  // Blocks the current thread until at least the given number of tasks are in
+  // the completed vector, and then returns a copy.
+  std::vector<int> WaitUntilTasksComplete(size_t num_tasks) {
+    std::vector<int> ret;
+    {
+      base::AutoLock lock(lock_);
+      while (complete_sequence_.size() < num_tasks)
+        cond_var_.Wait();
+      ret = complete_sequence_;
+    }
+    cond_var_.Signal();
+    return ret;
+  }
+
+  void ClearCompleteSequence() {
+    base::AutoLock lock(lock_);
+    complete_sequence_.clear();
+    started_events_ = 0;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<TestTracker>;
+  ~TestTracker() {}
+
+  void SignalWorkerDone(int id) {
+    {
+      base::AutoLock lock(lock_);
+      complete_sequence_.push_back(id);
+    }
+    cond_var_.Signal();
+  }
+
+  // Protects the complete_sequence.
+  base::Lock lock_;
+
+  base::ConditionVariable cond_var_;
+
+  // Protected by lock_.
+  std::vector<int> complete_sequence_;
+
+  // Counter of the number of "block" workers that have started.
+  size_t started_events_;
+};
+
+class SequencedWorkerPoolTest : public testing::Test {
+ public:
+  SequencedWorkerPoolTest()
+      : pool_owner_(kNumWorkerThreads, "test"),
+        tracker_(new TestTracker) {
+  }
+
+  virtual ~SequencedWorkerPoolTest() {}
+
+  virtual void SetUp() OVERRIDE {}
+
+  virtual void TearDown() OVERRIDE {
+    pool()->Shutdown();
+  }
+
+  const scoped_refptr<SequencedWorkerPool>& pool() {
+    return pool_owner_.pool();
+  }
+  TestTracker* tracker() { return tracker_.get(); }
+
+  void SetWillWaitForShutdownCallback(const Closure& callback) {
+    pool_owner_.SetWillWaitForShutdownCallback(callback);
+  }
+
+  // Ensures that the given number of worker threads is created by adding
+  // tasks and waiting until they complete. Worker thread creation is
+  // serialized, can happen on background threads asynchronously, and doesn't
+  // happen any more at shutdown. This means that if a test posts a bunch of
+  // tasks and calls shutdown, fewer workers will be created than the test may
+  // expect.
+  //
+  // This function ensures that this condition can't happen so tests can make
+  // assumptions about the number of workers active. See the comment in
+  // PrepareToStartAdditionalThreadIfNecessary in the .cc file for more
+  // details.
+  //
+  // It will post tasks to the queue with id -1. It also assumes this is the
+  // first thing called in a test since it will clear the complete_sequence_.
+  void EnsureAllWorkersCreated() {
+    // Create a bunch of threads, all waiting. This will cause that may
+    // workers to be created.
+    ThreadBlocker blocker;
+    for (size_t i = 0; i < kNumWorkerThreads; i++) {
+      pool()->PostWorkerTask(FROM_HERE,
+                             base::Bind(&TestTracker::BlockTask,
+                                        tracker(), -1, &blocker));
+    }
+    tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+    // Now wake them up and wait until they're done.
+    blocker.Unblock(kNumWorkerThreads);
+    tracker()->WaitUntilTasksComplete(kNumWorkerThreads);
+
+    // Clean up the task IDs we added.
+    tracker()->ClearCompleteSequence();
+  }
+
+  int has_work_call_count() const {
+    return pool_owner_.has_work_call_count();
+  }
+
+ private:
+  MessageLoop message_loop_;
+  SequencedWorkerPoolOwner pool_owner_;
+  const scoped_refptr<TestTracker> tracker_;
+};
+
+// Checks that the given number of entries are in the tasks to complete of
+// the given tracker, and then signals the given event the given number of
+// times. This is used to wakt up blocked background threads before blocking
+// on shutdown.
+void EnsureTasksToCompleteCountAndUnblock(scoped_refptr<TestTracker> tracker,
+                                          size_t expected_tasks_to_complete,
+                                          ThreadBlocker* blocker,
+                                          size_t threads_to_awake) {
+  EXPECT_EQ(
+      expected_tasks_to_complete,
+      tracker->WaitUntilTasksComplete(expected_tasks_to_complete).size());
+
+  blocker->Unblock(threads_to_awake);
+}
+
+// Tests that same-named tokens have the same ID.
+TEST_F(SequencedWorkerPoolTest, NamedTokens) {
+  const std::string name1("hello");
+  SequencedWorkerPool::SequenceToken token1 =
+      pool()->GetNamedSequenceToken(name1);
+
+  SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
+
+  const std::string name3("goodbye");
+  SequencedWorkerPool::SequenceToken token3 =
+      pool()->GetNamedSequenceToken(name3);
+
+  // All 3 tokens should be different.
+  EXPECT_FALSE(token1.Equals(token2));
+  EXPECT_FALSE(token1.Equals(token3));
+  EXPECT_FALSE(token2.Equals(token3));
+
+  // Requesting the same name again should give the same value.
+  SequencedWorkerPool::SequenceToken token1again =
+      pool()->GetNamedSequenceToken(name1);
+  EXPECT_TRUE(token1.Equals(token1again));
+
+  SequencedWorkerPool::SequenceToken token3again =
+      pool()->GetNamedSequenceToken(name3);
+  EXPECT_TRUE(token3.Equals(token3again));
+}
+
+// Tests that posting a bunch of tasks (many more than the number of worker
+// threads) runs them all.
+TEST_F(SequencedWorkerPoolTest, LotsOfTasks) {
+  pool()->PostWorkerTask(FROM_HERE,
+                         base::Bind(&TestTracker::SlowTask, tracker(), 0));
+
+  const size_t kNumTasks = 20;
+  for (size_t i = 1; i < kNumTasks; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::FastTask, tracker(), i));
+  }
+
+  std::vector<int> result = tracker()->WaitUntilTasksComplete(kNumTasks);
+  EXPECT_EQ(kNumTasks, result.size());
+}
+
+// Tests that posting a bunch of tasks (many more than the number of
+// worker threads) to two pools simultaneously runs them all twice.
+// This test is meant to shake out any concurrency issues between
+// pools (like histograms).
+TEST_F(SequencedWorkerPoolTest, LotsOfTasksTwoPools) {
+  SequencedWorkerPoolOwner pool1(kNumWorkerThreads, "test1");
+  SequencedWorkerPoolOwner pool2(kNumWorkerThreads, "test2");
+
+  base::Closure slow_task = base::Bind(&TestTracker::SlowTask, tracker(), 0);
+  pool1.pool()->PostWorkerTask(FROM_HERE, slow_task);
+  pool2.pool()->PostWorkerTask(FROM_HERE, slow_task);
+
+  const size_t kNumTasks = 20;
+  for (size_t i = 1; i < kNumTasks; i++) {
+    base::Closure fast_task =
+        base::Bind(&TestTracker::FastTask, tracker(), i);
+    pool1.pool()->PostWorkerTask(FROM_HERE, fast_task);
+    pool2.pool()->PostWorkerTask(FROM_HERE, fast_task);
+  }
+
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(2*kNumTasks);
+  EXPECT_EQ(2 * kNumTasks, result.size());
+
+  pool2.pool()->Shutdown();
+  pool1.pool()->Shutdown();
+}
+
+// Test that tasks with the same sequence token are executed in order but don't
+// affect other tasks.
+TEST_F(SequencedWorkerPoolTest, Sequence) {
+  // Fill all the worker threads except one.
+  const size_t kNumBackgroundTasks = kNumWorkerThreads - 1;
+  ThreadBlocker background_blocker;
+  for (size_t i = 0; i < kNumBackgroundTasks; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::BlockTask,
+                                      tracker(), i, &background_blocker));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumBackgroundTasks);
+
+  // Create two tasks with the same sequence token, one that will block on the
+  // event, and one which will just complete quickly when it's run. Since there
+  // is one worker thread free, the first task will start and then block, and
+  // the second task should be waiting.
+  ThreadBlocker blocker;
+  SequencedWorkerPool::SequenceToken token1 = pool()->GetSequenceToken();
+  pool()->PostSequencedWorkerTask(
+      token1, FROM_HERE,
+      base::Bind(&TestTracker::BlockTask, tracker(), 100, &blocker));
+  pool()->PostSequencedWorkerTask(
+      token1, FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 101));
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // Create another two tasks as above with a different token. These will be
+  // blocked since there are no slots to run.
+  SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
+  pool()->PostSequencedWorkerTask(
+      token2, FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 200));
+  pool()->PostSequencedWorkerTask(
+      token2, FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 201));
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // Let one background task complete. This should then let both tasks of
+  // token2 run to completion in order. The second task of token1 should still
+  // be blocked.
+  background_blocker.Unblock(1);
+  std::vector<int> result = tracker()->WaitUntilTasksComplete(3);
+  ASSERT_EQ(3u, result.size());
+  EXPECT_EQ(200, result[1]);
+  EXPECT_EQ(201, result[2]);
+
+  // Finish the rest of the background tasks. This should leave some workers
+  // free with the second token1 task still blocked on the first.
+  background_blocker.Unblock(kNumBackgroundTasks - 1);
+  EXPECT_EQ(kNumBackgroundTasks + 2,
+            tracker()->WaitUntilTasksComplete(kNumBackgroundTasks + 2).size());
+
+  // Allow the first task of token1 to complete. This should run the second.
+  blocker.Unblock(1);
+  result = tracker()->WaitUntilTasksComplete(kNumBackgroundTasks + 4);
+  ASSERT_EQ(kNumBackgroundTasks + 4, result.size());
+  EXPECT_EQ(100, result[result.size() - 2]);
+  EXPECT_EQ(101, result[result.size() - 1]);
+}
+
+// Tests that any tasks posted after Shutdown are ignored.
+TEST_F(SequencedWorkerPoolTest, IgnoresAfterShutdown) {
+  // Start tasks to take all the threads and block them.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::BlockTask,
+                                      tracker(), i, &blocker));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Shutdown the worker pool. This should discard all non-blocking tasks.
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()), 0,
+                 &blocker, kNumWorkerThreads));
+  pool()->Shutdown();
+
+  int old_has_work_call_count = has_work_call_count();
+
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(kNumWorkerThreads);
+
+  // The kNumWorkerThread items should have completed, in no particular
+  // order.
+  ASSERT_EQ(kNumWorkerThreads, result.size());
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
+                result.end());
+  }
+
+  // No further tasks, regardless of shutdown mode, should be allowed.
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 100),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 101),
+      SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 102),
+      SequencedWorkerPool::BLOCK_SHUTDOWN));
+
+  ASSERT_EQ(old_has_work_call_count, has_work_call_count());
+}
+
+// Tests that unrun tasks are discarded properly according to their shutdown
+// mode.
+TEST_F(SequencedWorkerPoolTest, DiscardOnShutdown) {
+  // Start tasks to take all the threads and block them.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::BlockTask,
+                                      tracker(), i, &blocker));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Create some tasks with different shutdown modes.
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 100),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 101),
+      SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 102),
+      SequencedWorkerPool::BLOCK_SHUTDOWN);
+
+  // Shutdown the worker pool. This should discard all non-blocking tasks.
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()), 0,
+                 &blocker, kNumWorkerThreads));
+  pool()->Shutdown();
+
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(kNumWorkerThreads + 1);
+
+  // The kNumWorkerThread items should have completed, plus the BLOCK_SHUTDOWN
+  // one, in no particular order.
+  ASSERT_EQ(kNumWorkerThreads + 1, result.size());
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
+                result.end());
+  }
+  EXPECT_TRUE(std::find(result.begin(), result.end(), 102) != result.end());
+}
+
+// Tests that CONTINUE_ON_SHUTDOWN tasks don't block shutdown.
+TEST_F(SequencedWorkerPoolTest, ContinueOnShutdown) {
+  scoped_refptr<TaskRunner> runner(pool()->GetTaskRunnerWithShutdownBehavior(
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  scoped_refptr<SequencedTaskRunner> sequenced_runner(
+      pool()->GetSequencedTaskRunnerWithShutdownBehavior(
+          pool()->GetSequenceToken(),
+          SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 0, &blocker),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+  runner->PostTask(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 1, &blocker));
+  sequenced_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 2, &blocker));
+
+  tracker()->WaitUntilTasksBlocked(3);
+
+  // This should not block. If this test hangs, it means it failed.
+  pool()->Shutdown();
+
+  // The task should not have completed yet.
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // Posting more tasks should fail.
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  EXPECT_FALSE(runner->PostTask(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0)));
+  EXPECT_FALSE(sequenced_runner->PostTask(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0)));
+
+  // Continue the background thread and make sure the tasks can complete.
+  blocker.Unblock(3);
+  std::vector<int> result = tracker()->WaitUntilTasksComplete(3);
+  EXPECT_EQ(3u, result.size());
+}
+
+// Tests that SKIP_ON_SHUTDOWN tasks that have been started block Shutdown
+// until they stop, but tasks not yet started do not.
+TEST_F(SequencedWorkerPoolTest, SkipOnShutdown) {
+  // Start tasks to take all the threads and block them.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+
+  // Now block all the threads with SKIP_ON_SHUTDOWN. Shutdown() should not
+  // return until these tasks have completed.
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    pool()->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE,
+        base::Bind(&TestTracker::BlockTask, tracker(), i, &blocker),
+        SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Now post an additional task as SKIP_ON_SHUTDOWN, which should not be
+  // executed once Shutdown() has been called.
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 0, &blocker),
+      SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+
+  // This callback will only be invoked if SKIP_ON_SHUTDOWN tasks that have
+  // been started block shutdown.
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()), 0,
+                 &blocker, kNumWorkerThreads));
+
+  // No tasks should have completed yet.
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // This should not block. If this test hangs, it means it failed.
+  pool()->Shutdown();
+
+  // Shutdown should not return until all of the tasks have completed.
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(kNumWorkerThreads);
+
+  // Only tasks marked SKIP_ON_SHUTDOWN that were already started should be
+  // allowed to complete. No additional non-blocking tasks should have been
+  // started.
+  ASSERT_EQ(kNumWorkerThreads, result.size());
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
+                result.end());
+  }
+}
+
+// Ensure all worker threads are created, and then trigger a spurious
+// work signal. This shouldn't cause any other work signals to be
+// triggered. This is a regression test for http://crbug.com/117469.
+TEST_F(SequencedWorkerPoolTest, SpuriousWorkSignal) {
+  EnsureAllWorkersCreated();
+  int old_has_work_call_count = has_work_call_count();
+  pool()->SignalHasWorkForTesting();
+  // This is inherently racy, but can only produce false positives.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  EXPECT_EQ(old_has_work_call_count + 1, has_work_call_count());
+}
+
+void IsRunningOnCurrentThreadTask(
+    SequencedWorkerPool::SequenceToken test_positive_token,
+    SequencedWorkerPool::SequenceToken test_negative_token,
+    SequencedWorkerPool* pool,
+    SequencedWorkerPool* unused_pool) {
+  EXPECT_TRUE(pool->RunsTasksOnCurrentThread());
+  EXPECT_TRUE(pool->IsRunningSequenceOnCurrentThread(test_positive_token));
+  EXPECT_FALSE(pool->IsRunningSequenceOnCurrentThread(test_negative_token));
+  EXPECT_FALSE(unused_pool->RunsTasksOnCurrentThread());
+  EXPECT_FALSE(
+      unused_pool->IsRunningSequenceOnCurrentThread(test_positive_token));
+  EXPECT_FALSE(
+      unused_pool->IsRunningSequenceOnCurrentThread(test_negative_token));
+}
+
+// Verify correctness of the IsRunningSequenceOnCurrentThread method.
+TEST_F(SequencedWorkerPoolTest, IsRunningOnCurrentThread) {
+  SequencedWorkerPool::SequenceToken token1 = pool()->GetSequenceToken();
+  SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
+  SequencedWorkerPool::SequenceToken unsequenced_token;
+
+  scoped_refptr<SequencedWorkerPool> unused_pool =
+      new SequencedWorkerPool(2, "unused_pool");
+  EXPECT_TRUE(token1.Equals(unused_pool->GetSequenceToken()));
+  EXPECT_TRUE(token2.Equals(unused_pool->GetSequenceToken()));
+
+  EXPECT_FALSE(pool()->RunsTasksOnCurrentThread());
+  EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(token1));
+  EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(token2));
+  EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(unsequenced_token));
+  EXPECT_FALSE(unused_pool->RunsTasksOnCurrentThread());
+  EXPECT_FALSE(unused_pool->IsRunningSequenceOnCurrentThread(token1));
+  EXPECT_FALSE(unused_pool->IsRunningSequenceOnCurrentThread(token2));
+  EXPECT_FALSE(
+      unused_pool->IsRunningSequenceOnCurrentThread(unsequenced_token));
+
+  pool()->PostSequencedWorkerTask(
+      token1, FROM_HERE,
+      base::Bind(&IsRunningOnCurrentThreadTask,
+                 token1, token2, pool(), unused_pool));
+  pool()->PostSequencedWorkerTask(
+      token2, FROM_HERE,
+      base::Bind(&IsRunningOnCurrentThreadTask,
+                 token2, unsequenced_token, pool(), unused_pool));
+  pool()->PostWorkerTask(
+      FROM_HERE,
+      base::Bind(&IsRunningOnCurrentThreadTask,
+                 unsequenced_token, token1, pool(), unused_pool));
+  pool()->Shutdown();
+  unused_pool->Shutdown();
+}
+
+class SequencedWorkerPoolTaskRunnerTestDelegate {
+ public:
+  SequencedWorkerPoolTaskRunnerTestDelegate() {}
+
+  ~SequencedWorkerPoolTaskRunnerTestDelegate() {}
+
+  void StartTaskRunner() {
+    pool_owner_.reset(
+        new SequencedWorkerPoolOwner(10, "SequencedWorkerPoolTaskRunnerTest"));
+  }
+
+  scoped_refptr<SequencedWorkerPool> GetTaskRunner() {
+    return pool_owner_->pool();
+  }
+
+  void StopTaskRunner() {
+    // Make sure all tasks (including delayed ones) are run before shutting
+    // down.
+    pool_owner_->pool()->FlushForTesting();
+    pool_owner_->pool()->Shutdown();
+    // Don't reset |pool_owner_| here, as the test may still hold a
+    // reference to the pool.
+  }
+
+  bool TaskRunnerHandlesNonZeroDelays() const {
+    return true;
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPool, TaskRunnerTest,
+    SequencedWorkerPoolTaskRunnerTestDelegate);
+
+class SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate {
+ public:
+  SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate() {}
+
+  ~SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate() {
+  }
+
+  void StartTaskRunner() {
+    pool_owner_.reset(
+        new SequencedWorkerPoolOwner(10, "SequencedWorkerPoolTaskRunnerTest"));
+    task_runner_ = pool_owner_->pool()->GetTaskRunnerWithShutdownBehavior(
+        SequencedWorkerPool::BLOCK_SHUTDOWN);
+  }
+
+  scoped_refptr<TaskRunner> GetTaskRunner() {
+    return task_runner_;
+  }
+
+  void StopTaskRunner() {
+    // Make sure all tasks (including delayed ones) are run before shutting
+    // down.
+    pool_owner_->pool()->FlushForTesting();
+    pool_owner_->pool()->Shutdown();
+    // Don't reset |pool_owner_| here, as the test may still hold a
+    // reference to the pool.
+  }
+
+  bool TaskRunnerHandlesNonZeroDelays() const {
+    return true;
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+  scoped_refptr<TaskRunner> task_runner_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolTaskRunner, TaskRunnerTest,
+    SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate);
+
+class SequencedWorkerPoolSequencedTaskRunnerTestDelegate {
+ public:
+  SequencedWorkerPoolSequencedTaskRunnerTestDelegate() {}
+
+  ~SequencedWorkerPoolSequencedTaskRunnerTestDelegate() {
+  }
+
+  void StartTaskRunner() {
+    pool_owner_.reset(new SequencedWorkerPoolOwner(
+        10, "SequencedWorkerPoolSequencedTaskRunnerTest"));
+    task_runner_ = pool_owner_->pool()->GetSequencedTaskRunner(
+        pool_owner_->pool()->GetSequenceToken());
+  }
+
+  scoped_refptr<SequencedTaskRunner> GetTaskRunner() {
+    return task_runner_;
+  }
+
+  void StopTaskRunner() {
+    // Make sure all tasks (including delayed ones) are run before shutting
+    // down.
+    pool_owner_->pool()->FlushForTesting();
+    pool_owner_->pool()->Shutdown();
+    // Don't reset |pool_owner_| here, as the test may still hold a
+    // reference to the pool.
+  }
+
+  bool TaskRunnerHandlesNonZeroDelays() const {
+    return true;
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+  scoped_refptr<SequencedTaskRunner> task_runner_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolSequencedTaskRunner, TaskRunnerTest,
+    SequencedWorkerPoolSequencedTaskRunnerTestDelegate);
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolSequencedTaskRunner, SequencedTaskRunnerTest,
+    SequencedWorkerPoolSequencedTaskRunnerTestDelegate);
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
new file mode 100644
index 0000000..5419c95
--- /dev/null
+++ b/base/threading/simple_thread.cc
@@ -0,0 +1,159 @@
+// 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/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/string_number_conversions.h"
+
+namespace base {
+
+SimpleThread::SimpleThread(const std::string& name_prefix)
+    : name_prefix_(name_prefix), name_(name_prefix),
+      thread_(), event_(true, false), tid_(0), joined_(false) {
+}
+
+SimpleThread::SimpleThread(const std::string& name_prefix,
+                           const Options& options)
+    : name_prefix_(name_prefix), name_(name_prefix), options_(options),
+      thread_(), event_(true, false), tid_(0), joined_(false) {
+}
+
+SimpleThread::~SimpleThread() {
+  DCHECK(HasBeenStarted()) << "SimpleThread was never started.";
+  DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed.";
+}
+
+void SimpleThread::Start() {
+  DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times.";
+  bool success = PlatformThread::Create(options_.stack_size(), this, &thread_);
+  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_.c_str());
+
+  // We've initialized our new thread, signal that we're done to Start().
+  event_.Signal();
+
+  Run();
+}
+
+DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
+                                           const std::string& name_prefix)
+    : SimpleThread(name_prefix),
+      delegate_(delegate) {
+}
+
+DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
+                                           const std::string& name_prefix,
+                                           const Options& options)
+    : SimpleThread(name_prefix, options),
+      delegate_(delegate) {
+}
+
+DelegateSimpleThread::~DelegateSimpleThread() {
+}
+
+void DelegateSimpleThread::Run() {
+  DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)";
+  delegate_->Run();
+  delegate_ = NULL;
+}
+
+DelegateSimpleThreadPool::DelegateSimpleThreadPool(
+    const std::string& name_prefix,
+    int num_threads)
+    : name_prefix_(name_prefix),
+      num_threads_(num_threads),
+      dry_(true, false) {
+}
+
+DelegateSimpleThreadPool::~DelegateSimpleThreadPool() {
+  DCHECK(threads_.empty());
+  DCHECK(delegates_.empty());
+  DCHECK(!dry_.IsSignaled());
+}
+
+void DelegateSimpleThreadPool::Start() {
+  DCHECK(threads_.empty()) << "Start() called with outstanding threads.";
+  for (int i = 0; i < num_threads_; ++i) {
+    DelegateSimpleThread* thread = new DelegateSimpleThread(this, name_prefix_);
+    thread->Start();
+    threads_.push_back(thread);
+  }
+}
+
+void DelegateSimpleThreadPool::JoinAll() {
+  DCHECK(!threads_.empty()) << "JoinAll() called with no outstanding threads.";
+
+  // Tell all our threads to quit their worker loop.
+  AddWork(NULL, num_threads_);
+
+  // Join and destroy all the worker threads.
+  for (int i = 0; i < num_threads_; ++i) {
+    threads_[i]->Join();
+    delete threads_[i];
+  }
+  threads_.clear();
+  DCHECK(delegates_.empty());
+}
+
+void DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) {
+  AutoLock locked(lock_);
+  for (int i = 0; i < repeat_count; ++i)
+    delegates_.push(delegate);
+  // If we were empty, signal that we have work now.
+  if (!dry_.IsSignaled())
+    dry_.Signal();
+}
+
+void DelegateSimpleThreadPool::Run() {
+  Delegate* work = NULL;
+
+  while (true) {
+    dry_.Wait();
+    {
+      AutoLock locked(lock_);
+      if (!dry_.IsSignaled())
+        continue;
+
+      DCHECK(!delegates_.empty());
+      work = delegates_.front();
+      delegates_.pop();
+
+      // Signal to any other threads that we're currently out of work.
+      if (delegates_.empty())
+        dry_.Reset();
+    }
+
+    // A NULL delegate pointer signals us to quit.
+    if (!work)
+      break;
+
+    work->Run();
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
new file mode 100644
index 0000000..df03ce1
--- /dev/null
+++ b/base/threading/simple_thread.h
@@ -0,0 +1,190 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: You should probably be using Thread (thread.h) instead.  Thread is
+//          Chrome's message-loop based Thread abstraction, and if you are a
+//          thread running in the browser, there will likely be assumptions
+//          that your thread will have an associated message loop.
+//
+// This is a simple thread interface that backs to a native operating system
+// thread.  You should use this only when you want a thread that does not have
+// an associated MessageLoop.  Unittesting is the best example of this.
+//
+// The simplest interface to use is DelegateSimpleThread, which will create
+// a new thread, and execute the Delegate's virtual Run() in this new thread
+// until it has completed, exiting the thread.
+//
+// NOTE: You *MUST* call Join on the thread to clean up the underlying thread
+// resources.  You are also responsible for destructing the SimpleThread object.
+// It is invalid to destroy a SimpleThread while it is running, or without
+// Start() having been called (and a thread never created).  The Delegate
+// object should live as long as a DelegateSimpleThread.
+//
+// Thread Safety: A SimpleThread is not completely thread safe.  It is safe to
+// access it from the creating thread or from the newly created thread.  This
+// implies that the creator thread should be the thread that calls Join.
+//
+// Example:
+//   class MyThreadRunner : public DelegateSimpleThread::Delegate { ... };
+//   MyThreadRunner runner;
+//   DelegateSimpleThread thread(&runner, "good_name_here");
+//   thread.Start();
+//   // Start will return after the Thread has been successfully started and
+//   // initialized.  The newly created thread will invoke runner->Run(), and
+//   // run until it returns.
+//   thread.Join();  // Wait until the thread has exited.  You *MUST* Join!
+//   // The SimpleThread object is still valid, however you may not call Join
+//   // or Start again.
+
+#ifndef BASE_THREADING_SIMPLE_THREAD_H_
+#define BASE_THREADING_SIMPLE_THREAD_H_
+
+#include <string>
+#include <queue>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+// This is the base SimpleThread.  You can derive from it and implement the
+// virtual Run method, or you can use the DelegateSimpleThread interface.
+class BASE_EXPORT SimpleThread : public PlatformThread::Delegate {
+ public:
+  class BASE_EXPORT Options {
+   public:
+    Options() : stack_size_(0) { }
+    ~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_; }
+   private:
+    size_t stack_size_;
+  };
+
+  // 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);
+
+  virtual ~SimpleThread();
+
+  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:
+  virtual void ThreadMain() OVERRIDE;
+
+  // Only set priorities with a careful understanding of the consequences.
+  // This is meant for very limited use cases.
+  void SetThreadPriority(ThreadPriority priority) {
+    PlatformThread::SetThreadPriority(thread_, priority);
+  }
+
+ private:
+  const std::string name_prefix_;
+  std::string name_;
+  const Options options_;
+  PlatformThreadHandle thread_;  // PlatformThread handle, invalid after Join!
+  WaitableEvent event_;          // Signaled if Start() was ever called.
+  PlatformThreadId tid_;         // The backing thread's id.
+  bool joined_;                  // True if Join has been called.
+};
+
+class BASE_EXPORT DelegateSimpleThread : public SimpleThread {
+ public:
+  class BASE_EXPORT Delegate {
+   public:
+    Delegate() { }
+    virtual ~Delegate() { }
+    virtual void Run() = 0;
+  };
+
+  DelegateSimpleThread(Delegate* delegate,
+                       const std::string& name_prefix);
+  DelegateSimpleThread(Delegate* delegate,
+                       const std::string& name_prefix,
+                       const Options& options);
+
+  virtual ~DelegateSimpleThread();
+  virtual 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);
+  virtual ~DelegateSimpleThreadPool();
+
+  // 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.
+  virtual void Run() OVERRIDE;
+
+ private:
+  const std::string name_prefix_;
+  int num_threads_;
+  std::vector<DelegateSimpleThread*> threads_;
+  std::queue<Delegate*> delegates_;
+  base::Lock lock_;            // Locks delegates_
+  WaitableEvent dry_;    // Not signaled when there is no work to do.
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SIMPLE_THREAD_H_
diff --git a/base/threading/simple_thread_unittest.cc b/base/threading/simple_thread_unittest.cc
new file mode 100644
index 0000000..169e2d7
--- /dev/null
+++ b/base/threading/simple_thread_unittest.cc
@@ -0,0 +1,170 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/string_number_conversions.h"
+#include "base/threading/simple_thread.h"
+#include "base/synchronization/waitable_event.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) { }
+  virtual ~SetIntRunner() { }
+
+  virtual void Run() OVERRIDE {
+    *ptr_ = val_;
+  }
+
+ private:
+  int* ptr_;
+  int val_;
+};
+
+class WaitEventRunner : public DelegateSimpleThread::Delegate {
+ public:
+  explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
+  virtual ~WaitEventRunner() { }
+
+  virtual 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) { }
+  virtual 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) { }
+
+  virtual void Run() OVERRIDE {
+    if (seq_->GetNext() == total_) {
+      event_->Signal();
+    } else {
+      event_->Wait();
+    }
+  }
+
+ private:
+  AtomicSequenceNumber* seq_;
+  int total_;
+  WaitableEvent* event_;
+};
+
+}  // namespace
+
+TEST(SimpleThreadTest, CreateAndJoin) {
+  int stack_int = 0;
+
+  SetIntRunner runner(&stack_int, 7);
+  EXPECT_EQ(0, stack_int);
+
+  DelegateSimpleThread thread(&runner, "int_setter");
+  EXPECT_FALSE(thread.HasBeenStarted());
+  EXPECT_FALSE(thread.HasBeenJoined());
+  EXPECT_EQ(0, stack_int);
+
+  thread.Start();
+  EXPECT_TRUE(thread.HasBeenStarted());
+  EXPECT_FALSE(thread.HasBeenJoined());
+
+  thread.Join();
+  EXPECT_TRUE(thread.HasBeenStarted());
+  EXPECT_TRUE(thread.HasBeenJoined());
+  EXPECT_EQ(7, stack_int);
+}
+
+TEST(SimpleThreadTest, WaitForEvent) {
+  // Create a thread, and wait for it to signal us.
+  WaitableEvent event(true, false);
+
+  WaitEventRunner runner(&event);
+  DelegateSimpleThread thread(&runner, "event_waiter");
+
+  EXPECT_FALSE(event.IsSignaled());
+  thread.Start();
+  event.Wait();
+  EXPECT_TRUE(event.IsSignaled());
+  thread.Join();
+}
+
+TEST(SimpleThreadTest, NamedWithOptions) {
+  WaitableEvent event(true, false);
+
+  WaitEventRunner runner(&event);
+  SimpleThread::Options options;
+  DelegateSimpleThread thread(&runner, "event_waiter", options);
+  EXPECT_EQ(thread.name_prefix(), "event_waiter");
+  EXPECT_FALSE(event.IsSignaled());
+
+  thread.Start();
+  EXPECT_EQ(thread.name_prefix(), "event_waiter");
+  EXPECT_EQ(thread.name(),
+            std::string("event_waiter/") + IntToString(thread.tid()));
+  event.Wait();
+
+  EXPECT_TRUE(event.IsSignaled());
+  thread.Join();
+
+  // We keep the name and tid, even after the thread is gone.
+  EXPECT_EQ(thread.name_prefix(), "event_waiter");
+  EXPECT_EQ(thread.name(),
+            std::string("event_waiter/") + IntToString(thread.tid()));
+}
+
+TEST(SimpleThreadTest, ThreadPool) {
+  AtomicSequenceNumber seq;
+  SeqRunner runner(&seq);
+  DelegateSimpleThreadPool pool("seq_runner", 10);
+
+  // Add work before we're running.
+  pool.AddWork(&runner, 300);
+
+  EXPECT_EQ(seq.GetNext(), 0);
+  pool.Start();
+
+  // Add work while we're running.
+  pool.AddWork(&runner, 300);
+
+  pool.JoinAll();
+
+  EXPECT_EQ(seq.GetNext(), 601);
+
+  // We can reuse our pool.  Verify that all 10 threads can actually run in
+  // parallel, so this test will only pass if there are actually 10 threads.
+  AtomicSequenceNumber seq2;
+  WaitableEvent event(true, false);
+  // Changing 9 to 10, for example, would cause us JoinAll() to never return.
+  VerifyPoolRunner verifier(&seq2, 9, &event);
+  pool.Start();
+
+  pool.AddWork(&verifier, 10);
+
+  pool.JoinAll();
+  EXPECT_EQ(seq2.GetNext(), 10);
+}
+
+}  // namespace base
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
new file mode 100644
index 0000000..f4ba3ff
--- /dev/null
+++ b/base/threading/thread.cc
@@ -0,0 +1,213 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread.h"
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/synchronization/waitable_event.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::Quit() 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()->Quit();
+  Thread::SetThreadWasQuitProperly(true);
+}
+
+// Used to pass data to ThreadMain.  This structure is allocated on the stack
+// from within StartWithOptions.
+struct Thread::StartupData {
+  // We get away with a const reference here because of how we are allocated.
+  const Thread::Options& options;
+
+  // Used to synchronize thread startup.
+  WaitableEvent event;
+
+  explicit StartupData(const Options& opt)
+      : options(opt),
+        event(false, false) {}
+};
+
+Thread::Thread(const char* name)
+    :
+#if defined(OS_WIN)
+      com_status_(NONE),
+#endif
+      started_(false),
+      stopping_(false),
+      running_(false),
+      startup_data_(NULL),
+      thread_(0),
+      message_loop_(NULL),
+      thread_id_(kInvalidThreadId),
+      name_(name) {
+}
+
+Thread::~Thread() {
+  Stop();
+}
+
+bool Thread::Start() {
+  Options options;
+#if defined(OS_WIN)
+  if (com_status_ == STA)
+    options.message_loop_type = MessageLoop::TYPE_UI;
+#endif
+  return StartWithOptions(options);
+}
+
+bool Thread::StartWithOptions(const Options& options) {
+  DCHECK(!message_loop_);
+#if defined(OS_WIN)
+  DCHECK((com_status_ != STA) ||
+      (options.message_loop_type == MessageLoop::TYPE_UI));
+#endif
+
+  SetThreadWasQuitProperly(false);
+
+  StartupData startup_data(options);
+  startup_data_ = &startup_data;
+
+  if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
+    DLOG(ERROR) << "failed to create thread";
+    startup_data_ = NULL;
+    return false;
+  }
+
+  // Wait for the thread to start and initialize message_loop_
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  startup_data.event.Wait();
+
+  // set it to NULL so we don't keep a pointer to some object on the stack.
+  startup_data_ = NULL;
+  started_ = true;
+
+  DCHECK(message_loop_);
+  return true;
+}
+
+void Thread::Stop() {
+  if (!started_)
+    return;
+
+  StopSoon();
+
+  // Wait for the thread to exit.
+  //
+  // TODO(darin): Unfortunately, we need to keep message_loop_ around until
+  // the thread exits.  Some consumers are abusing the API.  Make them stop.
+  //
+  PlatformThread::Join(thread_);
+
+  // The thread should NULL message_loop_ on exit.
+  DCHECK(!message_loop_);
+
+  // The thread no longer needs to be joined.
+  started_ = false;
+
+  stopping_ = false;
+}
+
+void Thread::StopSoon() {
+  // We should only be called on the same thread that started us.
+
+  // Reading thread_id_ without a lock can lead to a benign data race
+  // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer.
+  DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId());
+
+  if (stopping_ || !message_loop_)
+    return;
+
+  stopping_ = true;
+  message_loop_->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
+}
+
+bool Thread::IsRunning() const {
+  return running_;
+}
+
+void Thread::Run(MessageLoop* message_loop) {
+  message_loop->Run();
+}
+
+void Thread::SetThreadWasQuitProperly(bool flag) {
+  lazy_tls_bool.Pointer()->Set(flag);
+}
+
+bool Thread::GetThreadWasQuitProperly() {
+  bool quit_properly = true;
+#ifndef NDEBUG
+  quit_properly = lazy_tls_bool.Pointer()->Get();
+#endif
+  return quit_properly;
+}
+
+void Thread::ThreadMain() {
+  {
+    // The message loop for this thread.
+    MessageLoop message_loop(startup_data_->options.message_loop_type);
+
+    // Complete the initialization of our Thread object.
+    thread_id_ = PlatformThread::CurrentId();
+    PlatformThread::SetName(name_.c_str());
+    ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector.
+    message_loop.set_thread_name(name_);
+    message_loop_ = &message_loop;
+
+#if defined(OS_WIN)
+    scoped_ptr<win::ScopedCOMInitializer> com_initializer;
+    if (com_status_ != NONE) {
+      com_initializer.reset((com_status_ == STA) ?
+          new win::ScopedCOMInitializer() :
+          new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
+    }
+#endif
+
+    // Let the thread do extra initialization.
+    // Let's do this before signaling we are started.
+    Init();
+
+    running_ = true;
+    startup_data_->event.Signal();
+    // startup_data_ can't be touched anymore since the starting thread is now
+    // unlocked.
+
+    Run(message_loop_);
+    running_ = false;
+
+    // Let the thread do extra cleanup.
+    CleanUp();
+
+#if defined(OS_WIN)
+    com_initializer.reset();
+#endif
+
+    // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
+    DCHECK(GetThreadWasQuitProperly());
+
+    // We can't receive messages anymore.
+    message_loop_ = NULL;
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/thread.h b/base/threading/thread.h
new file mode 100644
index 0000000..cf1a86d
--- /dev/null
+++ b/base/threading/thread.h
@@ -0,0 +1,213 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_H_
+#define BASE_THREADING_THREAD_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// 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 Options {
+    Options() : message_loop_type(MessageLoop::TYPE_DEFAULT), stack_size(0) {}
+    Options(MessageLoop::Type type, size_t size)
+        : message_loop_type(type), stack_size(size) {}
+
+    // Specifies the type of message loop that will be allocated on the thread.
+    MessageLoop::Type message_loop_type;
+
+    // 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;
+  };
+
+  // Constructor.
+  // name is a display string to identify the thread.
+  explicit Thread(const char* 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.
+  virtual ~Thread();
+
+#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(!started_);
+    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);
+
+  // Signals the thread to exit and returns once the thread has exited.  After
+  // this method returns, the Thread object is completely reset and may be used
+  // as if it were newly constructed (i.e., Start may be called again).
+  //
+  // Stop may be called multiple times and is simply ignored if the thread is
+  // already stopped.
+  //
+  // NOTE: If you are a consumer of Thread, it is not necessary to call this
+  // before deleting your Thread objects, as the destructor will do it.
+  // IF YOU ARE A SUBCLASS OF Thread, YOU MUST CALL THIS IN YOUR DESTRUCTOR.
+  void Stop();
+
+  // Signals the thread to exit in the near future.
+  //
+  // WARNING: This function is not meant to be commonly used. Use at your own
+  // risk. Calling this function will cause message_loop() to become invalid in
+  // the near future. This function was created to workaround a specific
+  // deadlock on Windows with printer worker thread. In any other case, Stop()
+  // should be used.
+  //
+  // StopSoon should not be called multiple times as it is risky to do so. It
+  // could cause a timing issue in message_loop() access. Call Stop() to reset
+  // the thread object once it is known that the thread has quit.
+  void StopSoon();
+
+  // Returns the message loop for this thread.  Use the MessageLoop's
+  // PostTask methods to execute code on the thread.  This only returns
+  // non-null after a successful call to Start.  After Stop has been called,
+  // this will return NULL.
+  //
+  // NOTE: You must not call this MessageLoop's Quit method directly.  Use
+  // the Thread's Stop method instead.
+  //
+  MessageLoop* message_loop() const { return message_loop_; }
+
+  // Returns a MessageLoopProxy for this thread.  Use the MessageLoopProxy's
+  // PostTask methods to execute code on the thread.  This only returns
+  // non-NULL after a successful call to Start. After Stop has been called,
+  // this will return NULL. Callers can hold on to this even after the thread
+  // is gone.
+  scoped_refptr<MessageLoopProxy> message_loop_proxy() const {
+    return message_loop_ ? message_loop_->message_loop_proxy() : NULL;
+  }
+
+  // Returns the name of this thread (for display in debugger too).
+  const std::string& thread_name() const { return name_; }
+
+  // The native thread handle.
+  PlatformThreadHandle thread_handle() { return thread_; }
+
+  // The thread ID.
+  PlatformThreadId thread_id() const { return thread_id_; }
+
+  // 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:
+  virtual void ThreadMain() OVERRIDE;
+
+#if defined(OS_WIN)
+  // Whether this thread needs to initialize COM, and if so, in what mode.
+  ComStatus com_status_;
+#endif
+
+  // Whether we successfully started the thread.
+  bool started_;
+
+  // If true, we're in the middle of stopping, and shouldn't access
+  // |message_loop_|. It may non-NULL and invalid.
+  bool stopping_;
+
+  // True while inside of Run().
+  bool running_;
+
+  // Used to pass data to ThreadMain.
+  struct StartupData;
+  StartupData* startup_data_;
+
+  // The thread's handle.
+  PlatformThreadHandle thread_;
+
+  // The thread's message loop.  Valid only while the thread is alive.  Set
+  // by the created thread.
+  MessageLoop* message_loop_;
+
+  // Our thread's ID.
+  PlatformThreadId thread_id_;
+
+  // The name of the thread.  Used for debugging purposes.
+  std::string name_;
+
+  friend void ThreadQuitHelper();
+
+  DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_H_
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
new file mode 100644
index 0000000..5a8ef22
--- /dev/null
+++ b/base/threading/thread_checker.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_THREADING_THREAD_CHECKER_H_
+#define BASE_THREADING_THREAD_CHECKER_H_
+
+// Apart from debug builds, we also enable the thread checker in
+// builds with DCHECK_ALWAYS_ON so that trybots and waterfall bots
+// with this define will get the same level of thread checking as
+// debug bots.
+//
+// Note that this does not perfectly match situations where DCHECK is
+// enabled.  For example a non-official release build may have
+// DCHECK_ALWAYS_ON undefined (and therefore ThreadChecker would be
+// disabled) but have DCHECKs enabled at runtime.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+#if ENABLE_THREAD_CHECKER
+#include "base/threading/thread_checker_impl.h"
+#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 {
+    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 inheritence. The choice between having a
+// ThreadChecker member and inheriting from base::NonThreadSafe should be based
+// on whether:
+//  - Derived classes need to know the thread they belong to, as opposed to
+//    having that functionality fully encapsulated in the base class.
+//  - Derived classes should be able to reassign the base class to another
+//    thread, via DetachFromThread.
+//
+// If neither of these are true, then having a ThreadChecker member and calling
+// CalledOnValidThread is the preferable solution.
+//
+// Example:
+// class MyClass {
+//  public:
+//   void Foo() {
+//     DCHECK(thread_checker_.CalledOnValidThread());
+//     ... (do stuff) ...
+//   }
+//
+//  private:
+//   ThreadChecker thread_checker_;
+// }
+//
+// In Release mode, CalledOnValidThread will always return true.
+#if ENABLE_THREAD_CHECKER
+class ThreadChecker : public ThreadCheckerImpl {
+};
+#else
+class ThreadChecker : public ThreadCheckerDoNothing {
+};
+#endif  // ENABLE_THREAD_CHECKER
+
+#undef ENABLE_THREAD_CHECKER
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_CHECKER_H_
diff --git a/base/threading/thread_checker_impl.cc b/base/threading/thread_checker_impl.cc
new file mode 100644
index 0000000..985433e
--- /dev/null
+++ b/base/threading/thread_checker_impl.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_checker_impl.h"
+
+namespace base {
+
+ThreadCheckerImpl::ThreadCheckerImpl()
+    : valid_thread_id_(kInvalidThreadId) {
+  EnsureThreadIdAssigned();
+}
+
+ThreadCheckerImpl::~ThreadCheckerImpl() {}
+
+bool ThreadCheckerImpl::CalledOnValidThread() const {
+  EnsureThreadIdAssigned();
+  AutoLock auto_lock(lock_);
+  return valid_thread_id_ == PlatformThread::CurrentId();
+}
+
+void ThreadCheckerImpl::DetachFromThread() {
+  AutoLock auto_lock(lock_);
+  valid_thread_id_ = kInvalidThreadId;
+}
+
+void ThreadCheckerImpl::EnsureThreadIdAssigned() const {
+  AutoLock auto_lock(lock_);
+  if (valid_thread_id_ != kInvalidThreadId)
+    return;
+  valid_thread_id_ = PlatformThread::CurrentId();
+}
+
+}  // namespace base
diff --git a/base/threading/thread_checker_impl.h b/base/threading/thread_checker_impl.h
new file mode 100644
index 0000000..24361c8
--- /dev/null
+++ b/base/threading/thread_checker_impl.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_THREADING_THREAD_CHECKER_IMPL_H_
+#define BASE_THREADING_THREAD_CHECKER_IMPL_H_
+
+#include "base/base_export.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;
+
+  // 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 PlatformThreadId valid_thread_id_;
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_CHECKER_IMPL_H_
diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc
new file mode 100644
index 0000000..026cfd9
--- /dev/null
+++ b/base/threading/thread_checker_unittest.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Duplicated from base/threading/thread_checker.h so that we can be
+// good citizens there and undef the macro.
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+namespace base {
+
+namespace {
+
+// Simple class to exercise the basics of ThreadChecker.
+// Both the destructor and DoStuff should verify that they were
+// called on the same thread as the constructor.
+class ThreadCheckerClass : public ThreadChecker {
+ public:
+  ThreadCheckerClass() {}
+
+  // Verifies that it was called on the same thread as the constructor.
+  void DoStuff() {
+    DCHECK(CalledOnValidThread());
+  }
+
+  void DetachFromThread() {
+    ThreadChecker::DetachFromThread();
+  }
+
+  static void MethodOnDifferentThreadImpl();
+  static void DetachThenCallFromDifferentThreadImpl();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
+};
+
+// Calls ThreadCheckerClass::DoStuff on another thread.
+class CallDoStuffOnThread : public base::SimpleThread {
+ public:
+  CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
+      : SimpleThread("call_do_stuff_on_thread"),
+        thread_checker_class_(thread_checker_class) {
+  }
+
+  virtual 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:
+  DeleteThreadCheckerClassOnThread(ThreadCheckerClass* thread_checker_class)
+      : SimpleThread("delete_thread_checker_class_on_thread"),
+        thread_checker_class_(thread_checker_class) {
+  }
+
+  virtual void Run() OVERRIDE {
+    thread_checker_class_.reset();
+  }
+
+ private:
+  scoped_ptr<ThreadCheckerClass> thread_checker_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
+};
+
+}  // namespace
+
+TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // Verify that DoStuff doesn't assert.
+  thread_checker_class->DoStuff();
+
+  // Verify that the destructor doesn't assert.
+  thread_checker_class.reset();
+}
+
+TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // Verify that the destructor doesn't assert
+  // when called on a different thread.
+  DeleteThreadCheckerClassOnThread delete_on_thread(
+      thread_checker_class.release());
+
+  delete_on_thread.Start();
+  delete_on_thread.Join();
+}
+
+TEST(ThreadCheckerTest, DetachFromThread) {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // Verify that DoStuff doesn't assert when called on a different thread after
+  // a call to DetachFromThread.
+  thread_checker_class->DetachFromThread();
+  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+}
+
+#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
+
+void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // DoStuff should assert in debug builds only when called on a
+  // different thread.
+  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+}
+
+#if ENABLE_THREAD_CHECKER
+TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
+  ASSERT_DEATH({
+      ThreadCheckerClass::MethodOnDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
+  ThreadCheckerClass::MethodOnDifferentThreadImpl();
+}
+#endif  // ENABLE_THREAD_CHECKER
+
+void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // DoStuff doesn't assert when called on a different thread
+  // after a call to DetachFromThread.
+  thread_checker_class->DetachFromThread();
+  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+
+  // DoStuff should assert in debug builds only after moving to
+  // another thread.
+  thread_checker_class->DoStuff();
+}
+
+#if ENABLE_THREAD_CHECKER
+TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
+  ASSERT_DEATH({
+    ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
+  ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
+}
+#endif  // ENABLE_THREAD_CHECKER
+
+#endif  // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
+
+// Just in case we ever get lumped together with other compilation units.
+#undef ENABLE_THREAD_CHECKER
+
+}  // namespace base
diff --git a/base/threading/thread_collision_warner.cc b/base/threading/thread_collision_warner.cc
new file mode 100644
index 0000000..547e11c
--- /dev/null
+++ b/base/threading/thread_collision_warner.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_collision_warner.h"
+
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+void DCheckAsserter::warn() {
+  NOTREACHED() << "Thread Collision";
+}
+
+static subtle::Atomic32 CurrentThread() {
+  const PlatformThreadId current_thread_id = PlatformThread::CurrentId();
+  // We need to get the thread id into an atomic data type. This might be a
+  // truncating conversion, but any loss-of-information just increases the
+  // chance of a fault negative, not a false positive.
+  const subtle::Atomic32 atomic_thread_id =
+      static_cast<subtle::Atomic32>(current_thread_id);
+
+  return atomic_thread_id;
+}
+
+void ThreadCollisionWarner::EnterSelf() {
+  // If the active thread is 0 then I'll write the current thread ID
+  // if two or more threads arrive here only one will succeed to
+  // write on valid_thread_id_ the current thread ID.
+  subtle::Atomic32 current_thread_id = CurrentThread();
+
+  int previous_value = subtle::NoBarrier_CompareAndSwap(&valid_thread_id_,
+                                                        0,
+                                                        current_thread_id);
+  if (previous_value != 0 && previous_value != current_thread_id) {
+    // gotcha! a thread is trying to use the same class and that is
+    // not current thread.
+    asserter_->warn();
+  }
+
+  subtle::NoBarrier_AtomicIncrement(&counter_, 1);
+}
+
+void ThreadCollisionWarner::Enter() {
+  subtle::Atomic32 current_thread_id = CurrentThread();
+
+  if (subtle::NoBarrier_CompareAndSwap(&valid_thread_id_,
+                                       0,
+                                       current_thread_id) != 0) {
+    // gotcha! another thread is trying to use the same class.
+    asserter_->warn();
+  }
+
+  subtle::NoBarrier_AtomicIncrement(&counter_, 1);
+}
+
+void ThreadCollisionWarner::Leave() {
+  if (subtle::Barrier_AtomicIncrement(&counter_, -1) == 0) {
+    subtle::NoBarrier_Store(&valid_thread_id_, 0);
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/thread_collision_warner.h b/base/threading/thread_collision_warner.h
new file mode 100644
index 0000000..2181cbd
--- /dev/null
+++ b/base/threading/thread_collision_warner.h
@@ -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.
+
+#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"
+
+// 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 {
+  virtual ~DCheckAsserter() {}
+  virtual void warn() OVERRIDE;
+};
+
+class BASE_EXPORT ThreadCollisionWarner {
+ public:
+  // The parameter asserter is there only for test purpose
+  ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
+      : valid_thread_id_(0),
+        counter_(0),
+        asserter_(asserter) {}
+
+  ~ThreadCollisionWarner() {
+    delete asserter_;
+  }
+
+  // This class is meant to be used through the macro
+  // DFAKE_SCOPED_LOCK_THREAD_LOCKED
+  // it doesn't leave the critical section, as opposed to ScopedCheck,
+  // because the critical section being pinned is allowed to be used only
+  // from one thread
+  class BASE_EXPORT Check {
+   public:
+    explicit Check(ThreadCollisionWarner* warner)
+        : warner_(warner) {
+      warner_->EnterSelf();
+    }
+
+    ~Check() {}
+
+   private:
+    ThreadCollisionWarner* warner_;
+
+    DISALLOW_COPY_AND_ASSIGN(Check);
+  };
+
+  // This class is meant to be used through the macro
+  // DFAKE_SCOPED_LOCK
+  class BASE_EXPORT ScopedCheck {
+   public:
+    explicit ScopedCheck(ThreadCollisionWarner* warner)
+        : warner_(warner) {
+      warner_->Enter();
+    }
+
+    ~ScopedCheck() {
+      warner_->Leave();
+    }
+
+   private:
+    ThreadCollisionWarner* warner_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
+  };
+
+  // This class is meant to be used through the macro
+  // DFAKE_SCOPED_RECURSIVE_LOCK
+  class BASE_EXPORT ScopedRecursiveCheck {
+   public:
+    explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
+        : warner_(warner) {
+      warner_->EnterSelf();
+    }
+
+    ~ScopedRecursiveCheck() {
+      warner_->Leave();
+    }
+
+   private:
+    ThreadCollisionWarner* warner_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
+  };
+
+ private:
+  // This method stores the current thread identifier and does a DCHECK
+  // if a another thread has already done it, it is safe if same thread
+  // calls this multiple time (recursion allowed).
+  void EnterSelf();
+
+  // Same as EnterSelf but recursion is not allowed.
+  void Enter();
+
+  // Removes the thread_id stored in order to allow other threads to
+  // call EnterSelf or Enter.
+  void Leave();
+
+  // This stores the thread id that is inside the critical section, if the
+  // value is 0 then no thread is inside.
+  volatile subtle::Atomic32 valid_thread_id_;
+
+  // Counter to trace how many time a critical section was "pinned"
+  // (when allowed) in order to unpin it when counter_ reaches 0.
+  volatile subtle::Atomic32 counter_;
+
+  // Here only for class unit tests purpose, during the test I need to not
+  // DCHECK but notify the collision with something else.
+  AsserterBase* asserter_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_COLLISION_WARNER_H_
diff --git a/base/threading/thread_collision_warner_unittest.cc b/base/threading/thread_collision_warner_unittest.cc
new file mode 100644
index 0000000..48710a7
--- /dev/null
+++ b/base/threading/thread_collision_warner_unittest.cc
@@ -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.
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_collision_warner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// '' : local class member function does not have a body
+MSVC_PUSH_DISABLE_WARNING(4822)
+
+
+#if defined(NDEBUG)
+
+// Would cause a memory leak otherwise.
+#undef DFAKE_MUTEX
+#define DFAKE_MUTEX(obj) scoped_ptr<base::AsserterBase> obj
+
+// In Release, we expect the AsserterBase::warn() to not happen.
+#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_FALSE
+
+#else
+
+// In Debug, we expect the AsserterBase::warn() to happen.
+#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_TRUE
+
+#endif
+
+
+namespace {
+
+// This is the asserter used with ThreadCollisionWarner instead of the default
+// DCheckAsserter. The method fail_state is used to know if a collision took
+// place.
+class AssertReporter : public base::AsserterBase {
+ public:
+  AssertReporter()
+      : failed_(false) {}
+
+  virtual void warn() OVERRIDE {
+    failed_ = true;
+  }
+
+  virtual ~AssertReporter() {}
+
+  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) {}
+
+    virtual 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) {}
+
+    virtual 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) {}
+
+    virtual 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) {}
+
+    virtual void Run() OVERRIDE {
+      {
+        base::AutoLock auto_lock(lock_);
+        queue_.push(0);
+      }
+      {
+        base::AutoLock auto_lock(lock_);
+        queue_.bar();
+      }
+      {
+        base::AutoLock auto_lock(lock_);
+        queue_.pop();
+      }
+    }
+   private:
+    NonThreadSafeQueue& queue_;
+    base::Lock& lock_;
+  };
+
+  AssertReporter* local_reporter = new AssertReporter();
+
+  NonThreadSafeQueue queue(local_reporter);
+
+  base::Lock lock;
+
+  QueueUser queue_user_a(queue, lock);
+  QueueUser queue_user_b(queue, lock);
+
+  base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
+  base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
+
+  thread_a.Start();
+  thread_b.Start();
+
+  thread_a.Join();
+  thread_b.Join();
+
+  EXPECT_FALSE(local_reporter->fail_state());
+}
diff --git a/base/threading/thread_local.h b/base/threading/thread_local.h
new file mode 100644
index 0000000..6561420
--- /dev/null
+++ b/base/threading/thread_local.h
@@ -0,0 +1,128 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// 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.
+//
+// Example usage:
+//   // My class is logically attached to a single thread.  We cache a pointer
+//   // on the thread it was created on, so we can implement current().
+//   MyClass::MyClass() {
+//     DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() == NULL);
+//     Singleton<ThreadLocalPointer<MyClass> >::get()->Set(this);
+//   }
+//
+//   MyClass::~MyClass() {
+//     DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() != NULL);
+//     Singleton<ThreadLocalPointer<MyClass> >::get()->Set(NULL);
+//   }
+//
+//   // Return the current MyClass associated with the calling thread, can be
+//   // NULL if there isn't a MyClass associated.
+//   MyClass* MyClass::current() {
+//     return Singleton<ThreadLocalPointer<MyClass> >::get()->Get();
+//   }
+
+#ifndef BASE_THREADING_THREAD_LOCAL_H_
+#define BASE_THREADING_THREAD_LOCAL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#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_POSIX)
+  typedef pthread_key_t SlotType;
+#endif
+
+  static void AllocateSlot(SlotType& slot);
+  static void FreeSlot(SlotType& slot);
+  static void* GetValueFromSlot(SlotType& slot);
+  static void SetValueInSlot(SlotType& slot, void* value);
+};
+
+}  // namespace internal
+
+template <typename Type>
+class ThreadLocalPointer {
+ public:
+  ThreadLocalPointer() : slot_() {
+    internal::ThreadLocalPlatform::AllocateSlot(slot_);
+  }
+
+  ~ThreadLocalPointer() {
+    internal::ThreadLocalPlatform::FreeSlot(slot_);
+  }
+
+  Type* Get() {
+    return static_cast<Type*>(
+        internal::ThreadLocalPlatform::GetValueFromSlot(slot_));
+  }
+
+  void Set(Type* ptr) {
+    internal::ThreadLocalPlatform::SetValueInSlot(
+        slot_, const_cast<void*>(static_cast<const void*>(ptr)));
+  }
+
+ private:
+  typedef internal::ThreadLocalPlatform::SlotType SlotType;
+
+  SlotType slot_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer<Type>);
+};
+
+class ThreadLocalBoolean {
+ public:
+  ThreadLocalBoolean() { }
+  ~ThreadLocalBoolean() { }
+
+  bool Get() {
+    return tlp_.Get() != NULL;
+  }
+
+  void Set(bool val) {
+    tlp_.Set(val ? this : NULL);
+  }
+
+ private:
+  ThreadLocalPointer<void> tlp_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalBoolean);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_LOCAL_H_
diff --git a/base/threading/thread_local_posix.cc b/base/threading/thread_local_posix.cc
new file mode 100644
index 0000000..4951006
--- /dev/null
+++ b/base/threading/thread_local_posix.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local.h"
+
+#include <pthread.h>
+
+#include "base/logging.h"
+
+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
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
new file mode 100644
index 0000000..eb5648f
--- /dev/null
+++ b/base/threading/thread_local_storage.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_LOCAL_STORAGE_H_
+#define BASE_THREADING_THREAD_LOCAL_STORAGE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+namespace base {
+
+// Wrapper for thread local storage.  This class doesn't do much except provide
+// an API for portability.
+class BASE_EXPORT ThreadLocalStorage {
+ public:
+
+  // Prototype for the TLS destructor function, which can be optionally used to
+  // cleanup thread local storage on thread exit.  'value' is the data that is
+  // stored in thread local storage.
+  typedef void (*TLSDestructorFunc)(void* value);
+
+  // StaticSlot uses its own struct initializer-list style static
+  // initialization, as base's LINKER_INITIALIZED requires a constructor and on
+  // some compilers (notably gcc 4.4) this still ends up needing runtime
+  // initialization.
+  #define TLS_INITIALIZER {0}
+
+  // A key representing one value stored in TLS.
+  // Initialize like
+  //   ThreadLocalStorage::StaticSlot my_slot = TLS_INITIALIZER;
+  // If you're not using a static variable, use the convenience class
+  // ThreadLocalStorage::Slot (below) instead.
+  struct BASE_EXPORT StaticSlot {
+    // Set up the TLS slot.  Called by the constructor.
+    // 'destructor' is a pointer to a function to perform per-thread cleanup of
+    // this object.  If set to NULL, no cleanup is done for this TLS slot.
+    // Returns false on error.
+    bool Initialize(TLSDestructorFunc destructor);
+
+    // Free a previously allocated TLS 'slot'.
+    // If a destructor was set for this slot, removes
+    // the destructor so that remaining threads exiting
+    // will not free data.
+    void Free();
+
+    // Get the thread-local value stored in slot 'slot'.
+    // Values are guaranteed to initially be zero.
+    void* Get() const;
+
+    // Set the thread-local value stored in slot 'slot' to
+    // value 'value'.
+    void Set(void* value);
+
+    bool initialized() const { return initialized_; }
+
+    // The internals of this struct should be considered private.
+    bool initialized_;
+#if defined(OS_WIN)
+    int slot_;
+#elif defined(OS_POSIX)
+    pthread_key_t key_;
+#endif
+
+  };
+
+  // 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_;
+#if defined(OS_WIN)
+    using StaticSlot::slot_;
+#elif defined(OS_POSIX)
+    using StaticSlot::key_;
+#endif
+    DISALLOW_COPY_AND_ASSIGN(Slot);
+  };
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_LOCAL_STORAGE_H_
diff --git a/base/threading/thread_local_storage_posix.cc b/base/threading/thread_local_storage_posix.cc
new file mode 100644
index 0000000..75da5a7
--- /dev/null
+++ b/base/threading/thread_local_storage_posix.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local_storage.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) {
+  initialized_ = false;
+  key_ = 0;
+  Initialize(destructor);
+}
+
+bool ThreadLocalStorage::StaticSlot::Initialize(TLSDestructorFunc destructor) {
+  DCHECK(!initialized_);
+  int error = pthread_key_create(&key_, destructor);
+  if (error) {
+    NOTREACHED();
+    return false;
+  }
+
+  initialized_ = true;
+  return true;
+}
+
+void ThreadLocalStorage::StaticSlot::Free() {
+  DCHECK(initialized_);
+  int error = pthread_key_delete(key_);
+  if (error)
+    NOTREACHED();
+  initialized_ = false;
+}
+
+void* ThreadLocalStorage::StaticSlot::Get() const {
+  DCHECK(initialized_);
+  return pthread_getspecific(key_);
+}
+
+void ThreadLocalStorage::StaticSlot::Set(void* value) {
+  DCHECK(initialized_);
+  int error = pthread_setspecific(key_, value);
+  if (error)
+    NOTREACHED();
+}
+
+}  // namespace base
diff --git a/base/threading/thread_local_storage_unittest.cc b/base/threading/thread_local_storage_unittest.cc
new file mode 100644
index 0000000..8e222ee
--- /dev/null
+++ b/base/threading/thread_local_storage_unittest.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.
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <process.h>
+#endif
+
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_local_storage.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+// Ignore warnings about ptr->int conversions that we use when
+// storing ints into ThreadLocalStorage.
+#pragma warning(disable : 4311 4312)
+#endif
+
+namespace base {
+
+namespace {
+
+const int kInitialTlsValue = 0x5555;
+const int kFinalTlsValue = 0x7777;
+// How many times must a destructor be called before we really are done.
+const int kNumberDestructorCallRepetitions = 3;
+
+static ThreadLocalStorage::StaticSlot tls_slot = TLS_INITIALIZER;
+
+class ThreadLocalStorageRunner : public DelegateSimpleThread::Delegate {
+ public:
+  explicit ThreadLocalStorageRunner(int* tls_value_ptr)
+      : tls_value_ptr_(tls_value_ptr) {}
+
+  virtual ~ThreadLocalStorageRunner() {}
+
+  virtual 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);
+}
+
+TEST(ThreadLocalStorageTest, TLSDestructors) {
+  // Create a TLS index with a destructor.  Create a set of
+  // threads that set the TLS, while the destructor cleans it up.
+  // After the threads finish, verify that the value is cleaned up.
+  const int kNumThreads = 5;
+  int values[kNumThreads];
+  ThreadLocalStorageRunner* thread_delegates[kNumThreads];
+  DelegateSimpleThread* threads[kNumThreads];
+
+  tls_slot.Initialize(ThreadLocalStorageCleanup);
+
+  // Spawn the threads.
+  for (int index = 0; index < kNumThreads; index++) {
+    values[index] = kInitialTlsValue;
+    thread_delegates[index] = new ThreadLocalStorageRunner(&values[index]);
+    threads[index] = new DelegateSimpleThread(thread_delegates[index],
+                                              "tls thread");
+    threads[index]->Start();
+  }
+
+  // Wait for the threads to finish.
+  for (int index = 0; index < kNumThreads; index++) {
+    threads[index]->Join();
+    delete threads[index];
+    delete thread_delegates[index];
+
+    // Verify that the destructor was called and that we reset.
+    EXPECT_EQ(values[index], kFinalTlsValue);
+  }
+  tls_slot.Free();  // Stop doing callbacks to cleanup threads.
+}
+
+}  // namespace base
diff --git a/base/threading/thread_local_storage_win.cc b/base/threading/thread_local_storage_win.cc
new file mode 100644
index 0000000..0ae3cb4
--- /dev/null
+++ b/base/threading/thread_local_storage_win.cc
@@ -0,0 +1,277 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local_storage.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+
+namespace {
+// In order to make TLS destructors work, we need to keep function
+// pointers to the destructor for each TLS that we allocate.
+// We make this work by allocating a single OS-level TLS, which
+// contains an array of slots for the application to use.  In
+// parallel, we also allocate an array of destructors, which we
+// keep track of and call when threads terminate.
+
+// g_native_tls_key is the one native TLS that we use.  It stores our table.
+long g_native_tls_key = TLS_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.
+long g_last_used_tls_key = 0;
+
+// The maximum number of 'slots' in our thread local storage stack.
+const int kThreadLocalStorageSize = 64;
+
+// 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];
+
+void** ConstructTlsVector() {
+  if (g_native_tls_key == TLS_OUT_OF_INDEXES) {
+    long value = TlsAlloc();
+    DCHECK(value != TLS_OUT_OF_INDEXES);
+
+    // Atomically test-and-set the tls_key.  If the key is TLS_OUT_OF_INDEXES,
+    // go ahead and set it.  Otherwise, do nothing, as another
+    // thread already did our dirty work.
+    if (TLS_OUT_OF_INDEXES != InterlockedCompareExchange(
+            &g_native_tls_key, value, TLS_OUT_OF_INDEXES)) {
+      // 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.
+      TlsFree(value);
+    }
+  }
+  DCHECK(!TlsGetValue(g_native_tls_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.
+  TlsSetValue(g_native_tls_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));
+  TlsSetValue(g_native_tls_key, tls_data);
+  return tls_data;
+}
+
+// Called when we terminate a thread, this function calls any TLS destructors
+// that are pending for this thread.
+void WinThreadExit() {
+  if (g_native_tls_key == TLS_OUT_OF_INDEXES)
+    return;
+
+  void** tls_data = static_cast<void**>(TlsGetValue(g_native_tls_key));
+  // Maybe we have never initialized TLS for this thread.
+  if (!tls_data)
+    return;
+
+  // 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.
+  TlsSetValue(g_native_tls_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).
+    for (int slot = g_last_used_tls_key; slot > 0; --slot) {
+      void* value = stack_allocated_tls_data[slot];
+      if (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(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.
+  TlsSetValue(g_native_tls_key, NULL);
+}
+
+}  // namespace
+
+namespace base {
+
+ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) {
+  initialized_ = false;
+  slot_ = 0;
+  Initialize(destructor);
+}
+
+bool ThreadLocalStorage::StaticSlot::Initialize(TLSDestructorFunc destructor) {
+  if (g_native_tls_key == TLS_OUT_OF_INDEXES || !TlsGetValue(g_native_tls_key))
+    ConstructTlsVector();
+
+  // Grab a new slot.
+  slot_ = InterlockedIncrement(&g_last_used_tls_key);
+  DCHECK_GT(slot_, 0);
+  if (slot_ >= kThreadLocalStorageSize) {
+    NOTREACHED();
+    return false;
+  }
+
+  // Setup our destructor.
+  g_tls_destructors[slot_] = destructor;
+  initialized_ = true;
+  return true;
+}
+
+void ThreadLocalStorage::StaticSlot::Free() {
+  // At this time, we don't reclaim old indices for TLS slots.
+  // So all we need to do is wipe the destructor.
+  DCHECK_GT(slot_, 0);
+  DCHECK_LT(slot_, kThreadLocalStorageSize);
+  g_tls_destructors[slot_] = NULL;
+  slot_ = 0;
+  initialized_ = false;
+}
+
+void* ThreadLocalStorage::StaticSlot::Get() const {
+  void** tls_data = static_cast<void**>(TlsGetValue(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**>(TlsGetValue(g_native_tls_key));
+  if (!tls_data)
+    tls_data = ConstructTlsVector();
+  DCHECK_GT(slot_, 0);
+  DCHECK_LT(slot_, kThreadLocalStorageSize);
+  tls_data[slot_] = value;
+}
+
+}  // namespace base
+
+// Thread Termination Callbacks.
+// Windows doesn't support a per-thread destructor with its
+// TLS primitives.  So, we build it manually by inserting a
+// function to be called on each thread's exit.
+// This magic is from http://www.codeproject.com/threads/tls.asp
+// and it works for VC++ 7.0 and later.
+
+// Force a reference to _tls_used to make the linker create the TLS directory
+// if it's not already there.  (e.g. if __declspec(thread) is not used).
+// Force a reference to p_thread_callback_base to prevent whole program
+// optimization from discarding the variable.
+#ifdef _WIN64
+
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:p_thread_callback_base")
+
+#else  // _WIN64
+
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_p_thread_callback_base")
+
+#endif  // _WIN64
+
+// Static callback function to call with each thread termination.
+void NTAPI OnThreadExit(PVOID module, DWORD reason, PVOID reserved) {
+  // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+
+  // and on W2K and W2K3. So don't assume it is sent.
+  if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason)
+    WinThreadExit();
+}
+
+// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
+// called automatically by the OS loader code (not the CRT) when the module is
+// loaded and on thread creation. They are NOT called if the module has been
+// loaded by a LoadLibrary() call. It must have implicitly been loaded at
+// process startup.
+// By implicitly loaded, I mean that it is directly referenced by the main EXE
+// or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being
+// implicitly loaded.
+//
+// See VC\crt\src\tlssup.c for reference.
+
+// extern "C" suppresses C++ name mangling so we know the symbol name for the
+// linker /INCLUDE:symbol pragma above.
+extern "C" {
+// The linker must not discard p_thread_callback_base.  (We force a reference
+// to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If
+// this variable is discarded, the OnThreadExit function will never be called.
+#ifdef _WIN64
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma const_seg(".CRT$XLB")
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK p_thread_callback_base;
+const PIMAGE_TLS_CALLBACK p_thread_callback_base = OnThreadExit;
+
+// Reset the default section.
+#pragma const_seg()
+
+#else  // _WIN64
+
+#pragma data_seg(".CRT$XLB")
+PIMAGE_TLS_CALLBACK p_thread_callback_base = OnThreadExit;
+
+// Reset the default section.
+#pragma data_seg()
+
+#endif  // _WIN64
+}  // extern "C"
diff --git a/base/threading/thread_local_unittest.cc b/base/threading/thread_local_unittest.cc
new file mode 100644
index 0000000..b125a48
--- /dev/null
+++ b/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<ThreadLocalTesterBase> TLPType;
+
+  ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
+      : tlp_(tlp),
+        done_(done) {
+  }
+  virtual ~ThreadLocalTesterBase() {}
+
+ protected:
+  TLPType* tlp_;
+  base::WaitableEvent* done_;
+};
+
+class SetThreadLocal : public ThreadLocalTesterBase {
+ public:
+  SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
+      : ThreadLocalTesterBase(tlp, done),
+        val_(NULL) {
+  }
+  virtual ~SetThreadLocal() {}
+
+  void set_value(ThreadLocalTesterBase* val) { val_ = val; }
+
+  virtual void Run() OVERRIDE {
+    DCHECK(!done_->IsSignaled());
+    tlp_->Set(val_);
+    done_->Signal();
+  }
+
+ private:
+  ThreadLocalTesterBase* val_;
+};
+
+class GetThreadLocal : public ThreadLocalTesterBase {
+ public:
+  GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
+      : ThreadLocalTesterBase(tlp, done),
+        ptr_(NULL) {
+  }
+  virtual ~GetThreadLocal() {}
+
+  void set_ptr(ThreadLocalTesterBase** ptr) { ptr_ = ptr; }
+
+  virtual void Run() OVERRIDE {
+    DCHECK(!done_->IsSignaled());
+    *ptr_ = tlp_->Get();
+    done_->Signal();
+  }
+
+ private:
+  ThreadLocalTesterBase** 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<ThreadLocalTesterBase> tlp;
+
+  static ThreadLocalTesterBase* const kBogusPointer =
+      reinterpret_cast<ThreadLocalTesterBase*>(0x1234);
+
+  ThreadLocalTesterBase* tls_val;
+  base::WaitableEvent done(true, false);
+
+  GetThreadLocal getter(&tlp, &done);
+  getter.set_ptr(&tls_val);
+
+  // Check that both threads defaulted to NULL.
+  tls_val = kBogusPointer;
+  done.Reset();
+  tp1.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
+
+  tls_val = kBogusPointer;
+  done.Reset();
+  tp2.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(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<ThreadLocalTesterBase*>(NULL), tls_val);
+
+  // Set thread 2 to kBogusPointer + 1.
+  setter.set_value(kBogusPointer + 1);
+
+  done.Reset();
+  tp2.AddWork(&setter);
+  done.Wait();
+
+  tls_val = NULL;
+  done.Reset();
+  tp2.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(kBogusPointer + 1, tls_val);
+
+  // Make sure thread 1 is still kBogusPointer.
+  tls_val = NULL;
+  done.Reset();
+  tp1.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(kBogusPointer, tls_val);
+
+  tp1.JoinAll();
+  tp2.JoinAll();
+}
+
+TEST(ThreadLocalTest, Boolean) {
+  {
+    base::ThreadLocalBoolean tlb;
+    EXPECT_FALSE(tlb.Get());
+
+    tlb.Set(false);
+    EXPECT_FALSE(tlb.Get());
+
+    tlb.Set(true);
+    EXPECT_TRUE(tlb.Get());
+  }
+
+  // Our slot should have been freed, we're all reset.
+  {
+    base::ThreadLocalBoolean tlb;
+    EXPECT_FALSE(tlb.Get());
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/thread_local_win.cc b/base/threading/thread_local_win.cc
new file mode 100644
index 0000000..56d3a3a
--- /dev/null
+++ b/base/threading/thread_local_win.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType& slot) {
+  slot = TlsAlloc();
+  CHECK_NE(slot, TLS_OUT_OF_INDEXES);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType& slot) {
+  if (!TlsFree(slot)) {
+    NOTREACHED() << "Failed to deallocate tls slot with TlsFree().";
+  }
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType& slot) {
+  return TlsGetValue(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType& slot, void* value) {
+  if (!TlsSetValue(slot, value)) {
+    LOG(FATAL) << "Failed to TlsSetValue().";
+  }
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/thread_restrictions.cc b/base/threading/thread_restrictions.cc
new file mode 100644
index 0000000..871f2dc
--- /dev/null
+++ b/base/threading/thread_restrictions.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_restrictions.h"
+
+#if ENABLE_THREAD_RESTRICTIONS
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/thread_local.h"
+
+namespace base {
+
+namespace {
+
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_io_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_singleton_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_wait_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+}  // anonymous namespace
+
+// static
+bool ThreadRestrictions::SetIOAllowed(bool allowed) {
+  bool previous_disallowed = g_io_disallowed.Get().Get();
+  g_io_disallowed.Get().Set(!allowed);
+  return !previous_disallowed;
+}
+
+// static
+void ThreadRestrictions::AssertIOAllowed() {
+  if (g_io_disallowed.Get().Get()) {
+    LOG(FATAL) <<
+        "Function marked as IO-only was called from a thread that "
+        "disallows IO!  If this thread really should be allowed to "
+        "make IO calls, adjust the call to "
+        "base::ThreadRestrictions::SetIOAllowed() in this thread's "
+        "startup.";
+  }
+}
+
+// static
+bool ThreadRestrictions::SetSingletonAllowed(bool allowed) {
+  bool previous_disallowed = g_singleton_disallowed.Get().Get();
+  g_singleton_disallowed.Get().Set(!allowed);
+  return !previous_disallowed;
+}
+
+// static
+void ThreadRestrictions::AssertSingletonAllowed() {
+  if (g_singleton_disallowed.Get().Get()) {
+    LOG(FATAL) << "LazyInstance/Singleton is not allowed to be used on this "
+               << "thread.  Most likely it's because this thread is not "
+               << "joinable, so AtExitManager may have deleted the object "
+               << "on shutdown, leading to a potential shutdown crash.";
+  }
+}
+
+// static
+void ThreadRestrictions::DisallowWaiting() {
+  g_wait_disallowed.Get().Set(true);
+}
+
+// static
+void ThreadRestrictions::AssertWaitAllowed() {
+  if (g_wait_disallowed.Get().Get()) {
+    LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent"
+               << "jank and deadlock.";
+  }
+}
+
+bool ThreadRestrictions::SetWaitAllowed(bool allowed) {
+  bool previous_disallowed = g_wait_disallowed.Get().Get();
+  g_wait_disallowed.Get().Set(!allowed);
+  return !previous_disallowed;
+}
+
+}  // namespace base
+
+#endif  // ENABLE_THREAD_RESTRICTIONS
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
new file mode 100644
index 0000000..c762926
--- /dev/null
+++ b/base/threading/thread_restrictions.h
@@ -0,0 +1,234 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_RESTRICTIONS_H_
+#define BASE_THREADING_THREAD_RESTRICTIONS_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+// See comment at top of thread_checker.h
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_THREAD_RESTRICTIONS 1
+#else
+#define ENABLE_THREAD_RESTRICTIONS 0
+#endif
+
+class AcceleratedPresenter;
+class BrowserProcessImpl;
+class HistogramSynchronizer;
+class MetricsService;
+class NativeBackendKWallet;
+class ScopedAllowWaitForLegacyWebViewApi;
+class TestingAutomationProvider;
+
+namespace browser_sync {
+class NonFrontendDataTypeController;
+class UIModelWorker;
+}
+namespace cc {
+class CompletionEvent;
+}
+namespace chromeos {
+class AudioMixerAlsa;
+class BlockingMethodCaller;
+namespace system {
+class StatisticsProviderImpl;
+}
+}
+namespace chrome_browser_net {
+class Predictor;
+}
+namespace content {
+class BrowserGpuChannelHostFactory;
+class GLHelper;
+class GpuChannelHost;
+class RenderWidgetHelper;
+class TextInputClientMac;
+}
+namespace dbus {
+class Bus;
+}
+namespace disk_cache {
+class BackendImpl;
+class InFlightIO;
+}
+namespace media {
+class AudioOutputController;
+}
+namespace net {
+class FileStreamPosix;
+class FileStreamWin;
+class NetworkManagerApi;
+}
+
+namespace remoting {
+class AutoThread;
+}
+
+namespace base {
+
+class SequencedWorkerPool;
+class SimpleThread;
+class Thread;
+class ThreadTestHelper;
+
+// Certain behavior is disallowed on certain threads.  ThreadRestrictions helps
+// enforce these rules.  Examples of such rules:
+//
+// * Do not do blocking IO (makes the thread janky)
+// * Do not access Singleton/LazyInstance (may lead to shutdown crashes)
+//
+// Here's more about how the protection works:
+//
+// 1) If a thread should not be allowed to make IO calls, mark it:
+//      base::ThreadRestrictions::SetIOAllowed(false);
+//    By default, threads *are* allowed to make IO calls.
+//    In Chrome browser code, IO calls should be proxied to the File thread.
+//
+// 2) If a function makes a call that will go out to disk, check whether the
+//    current thread is allowed:
+//      base::ThreadRestrictions::AssertIOAllowed();
+//
+//
+// Style tip: where should you put AssertIOAllowed checks?  It's best
+// if you put them as close to the disk access as possible, at the
+// lowest level.  This rule is simple to follow and helps catch all
+// callers.  For example, if your function GoDoSomeBlockingDiskCall()
+// only calls other functions in Chrome and not fopen(), you should go
+// add the AssertIOAllowed checks in the helper functions.
+
+class BASE_EXPORT ThreadRestrictions {
+ public:
+  // Constructing a ScopedAllowIO temporarily allows IO for the current
+  // thread.  Doing this is almost certainly always incorrect.
+  class BASE_EXPORT ScopedAllowIO {
+   public:
+    ScopedAllowIO() { previous_value_ = SetIOAllowed(true); }
+    ~ScopedAllowIO() { SetIOAllowed(previous_value_); }
+   private:
+    // Whether IO is allowed when the ScopedAllowIO was constructed.
+    bool previous_value_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO);
+  };
+
+  // Constructing a ScopedAllowSingleton temporarily allows accessing for the
+  // current thread.  Doing this is almost always incorrect.
+  class BASE_EXPORT ScopedAllowSingleton {
+   public:
+    ScopedAllowSingleton() { previous_value_ = SetSingletonAllowed(true); }
+    ~ScopedAllowSingleton() { SetSingletonAllowed(previous_value_); }
+   private:
+    // Whether singleton use is allowed when the ScopedAllowSingleton was
+    // constructed.
+    bool previous_value_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedAllowSingleton);
+  };
+
+#if ENABLE_THREAD_RESTRICTIONS
+  // Set whether the current thread to make IO calls.
+  // Threads start out in the *allowed* state.
+  // Returns the previous value.
+  static bool SetIOAllowed(bool allowed);
+
+  // Check whether the current thread is allowed to make IO calls,
+  // and DCHECK if not.  See the block comment above the class for
+  // a discussion of where to add these checks.
+  static void AssertIOAllowed();
+
+  // Set whether the current thread can use singletons.  Returns the previous
+  // value.
+  static bool SetSingletonAllowed(bool allowed);
+
+  // Check whether the current thread is allowed to use singletons (Singleton /
+  // LazyInstance).  DCHECKs if not.
+  static void AssertSingletonAllowed();
+
+  // Disable waiting on the current thread. Threads start out in the *allowed*
+  // state. Returns the previous value.
+  static void DisallowWaiting();
+
+  // Check whether the current thread is allowed to wait, and DCHECK if not.
+  static void AssertWaitAllowed();
+#else
+  // Inline the empty definitions of these functions so that they can be
+  // compiled out.
+  static bool SetIOAllowed(bool allowed) { return true; }
+  static void AssertIOAllowed() {}
+  static bool SetSingletonAllowed(bool allowed) { return true; }
+  static void AssertSingletonAllowed() {}
+  static void DisallowWaiting() {}
+  static void AssertWaitAllowed() {}
+#endif
+
+ private:
+  // DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to jam or brettw first.
+  // BEGIN ALLOWED USAGE.
+  friend class content::RenderWidgetHelper;
+  friend class ::HistogramSynchronizer;
+  friend class ::ScopedAllowWaitForLegacyWebViewApi;
+  friend class ::TestingAutomationProvider;
+  friend class cc::CompletionEvent;
+  friend class remoting::AutoThread;
+  friend class SequencedWorkerPool;
+  friend class SimpleThread;
+  friend class Thread;
+  friend class ThreadTestHelper;
+
+  // END ALLOWED USAGE.
+  // BEGIN USAGE THAT NEEDS TO BE FIXED.
+  friend class ::chromeos::AudioMixerAlsa;        // http://crbug.com/125206
+  friend class ::chromeos::BlockingMethodCaller;  // http://crbug.com/125360
+  friend class ::chromeos::system::StatisticsProviderImpl;  // http://crbug.com/125385
+  friend class browser_sync::NonFrontendDataTypeController;  // http://crbug.com/19757
+  friend class browser_sync::UIModelWorker;       // http://crbug.com/19757
+  friend class chrome_browser_net::Predictor;     // http://crbug.com/78451
+  friend class
+      content::BrowserGpuChannelHostFactory;      // http://crbug.com/125248
+  friend class content::GLHelper;                 // http://crbug.com/125415
+  friend class content::GpuChannelHost;           // http://crbug.com/125264
+  friend class content::TextInputClientMac;       // http://crbug.com/121917
+  friend class dbus::Bus;                         // http://crbug.com/125222
+  friend class disk_cache::BackendImpl;           // http://crbug.com/74623
+  friend class disk_cache::InFlightIO;            // http://crbug.com/74623
+  friend class media::AudioOutputController;      // http://crbug.com/120973
+  friend class net::FileStreamPosix;              // http://crbug.com/115067
+  friend class net::FileStreamWin;                // http://crbug.com/115067
+  friend class net::NetworkManagerApi;            // http://crbug.com/125097
+  friend class ::AcceleratedPresenter;            // http://crbug.com/125391
+  friend class ::BrowserProcessImpl;              // http://crbug.com/125207
+  friend class ::MetricsService;                  // http://crbug.com/124954
+  friend class ::NativeBackendKWallet;            // http://crbug.com/125331
+  // END USAGE THAT NEEDS TO BE FIXED.
+
+#if ENABLE_THREAD_RESTRICTIONS
+  static bool SetWaitAllowed(bool allowed);
+#else
+  static bool SetWaitAllowed(bool allowed) { return true; }
+#endif
+
+  // Constructing a ScopedAllowWait temporarily allows waiting on the current
+  // thread.  Doing this is almost always incorrect, which is why we limit who
+  // can use this through friend. If you find yourself needing to use this, find
+  // another way. Talk to jam or brettw.
+  class BASE_EXPORT ScopedAllowWait {
+   public:
+    ScopedAllowWait() { previous_value_ = SetWaitAllowed(true); }
+    ~ScopedAllowWait() { SetWaitAllowed(previous_value_); }
+   private:
+    // Whether singleton use is allowed when the ScopedAllowWait was
+    // constructed.
+    bool previous_value_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait);
+  };
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_RESTRICTIONS_H_
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
new file mode 100644
index 0000000..28696d9
--- /dev/null
+++ b/base/threading/thread_unittest.cc
@@ -0,0 +1,237 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+using base::Thread;
+
+typedef PlatformTest ThreadTest;
+
+namespace {
+
+void ToggleValue(bool* value) {
+  ANNOTATE_BENIGN_RACE(value, "Test-only data race on boolean "
+                       "in base/thread_unittest");
+  *value = !*value;
+}
+
+class SleepInsideInitThread : public Thread {
+ public:
+  SleepInsideInitThread() : Thread("none") {
+    init_called_ = false;
+    ANNOTATE_BENIGN_RACE(
+        this, "Benign test-only data race on vptr - http://crbug.com/98219");
+  }
+  virtual ~SleepInsideInitThread() {
+    Stop();
+  }
+
+  virtual 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) {
+  }
+
+  virtual ~CaptureToEventList() {
+    Stop();
+  }
+
+  virtual void Init() OVERRIDE {
+    event_list_->push_back(THREAD_EVENT_INIT);
+  }
+
+  virtual 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 MessageLoop::DestructionObserver {
+ public:
+  // |event_list| must remain valid throughout the observer's lifetime.
+  explicit CapturingDestructionObserver(EventList* event_list)
+      : event_list_(event_list) {
+  }
+
+  // DestructionObserver implementation:
+  virtual 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(MessageLoop::DestructionObserver* observer) {
+  MessageLoop::current()->AddDestructionObserver(observer);
+}
+
+}  // namespace
+
+TEST_F(ThreadTest, Restart) {
+  Thread a("Restart");
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+  EXPECT_TRUE(a.Start());
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+  EXPECT_TRUE(a.Start());
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+}
+
+TEST_F(ThreadTest, StartWithOptions_StackSize) {
+  Thread a("StartWithStackSize");
+  // Ensure that the thread can work with only 12 kb and still process a
+  // message.
+  Thread::Options options;
+  options.stack_size = 12*1024;
+  EXPECT_TRUE(a.StartWithOptions(options));
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+
+  bool was_invoked = false;
+  a.message_loop()->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.message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(
+            static_cast<void (*)(base::TimeDelta)>(
+                &base::PlatformThread::Sleep),
+            base::TimeDelta::FromMilliseconds(20)));
+    a.message_loop()->PostTask(FROM_HERE, base::Bind(&ToggleValue,
+                                                     &was_invoked));
+  }
+  EXPECT_TRUE(was_invoked);
+}
+
+TEST_F(ThreadTest, StopSoon) {
+  Thread a("StopSoon");
+  EXPECT_TRUE(a.Start());
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+  a.StopSoon();
+  a.StopSoon();
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+}
+
+TEST_F(ThreadTest, ThreadName) {
+  Thread a("ThreadName");
+  EXPECT_TRUE(a.Start());
+  EXPECT_EQ("ThreadName", a.thread_name());
+}
+
+// Make sure we can't use a thread between Start() and Init().
+TEST_F(ThreadTest, SleepInsideInit) {
+  SleepInsideInitThread t;
+  EXPECT_FALSE(t.InitCalled());
+  t.Start();
+  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.message_loop()->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]);
+}
diff --git a/base/threading/watchdog.cc b/base/threading/watchdog.cc
new file mode 100644
index 0000000..d060655
--- /dev/null
+++ b/base/threading/watchdog.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/watchdog.h"
+
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace {
+
+// When the debugger breaks (when we alarm), all the other alarms that are
+// armed will expire (also alarm).  To diminish this effect, we track any
+// delay due to debugger breaks, and we *try* to adjust the effective start
+// time of other alarms to step past the debugging break.
+// Without this safety net, any alarm will typically trigger a host of follow
+// on alarms from callers that specify old times.
+
+// Lock for access of static data...
+LazyInstance<Lock>::Leaky g_static_lock = LAZY_INSTANCE_INITIALIZER;
+
+// When did we last alarm and get stuck (for a while) in a debugger?
+TimeTicks g_last_debugged_alarm_time;
+
+// How long did we sit on a break in the debugger?
+TimeDelta g_last_debugged_alarm_delay;
+
+}  // namespace
+
+// Start thread running in a Disarmed state.
+Watchdog::Watchdog(const TimeDelta& duration,
+                   const std::string& thread_watched_name,
+                   bool enabled)
+  : enabled_(enabled),
+    lock_(),
+    condition_variable_(&lock_),
+    state_(DISARMED),
+    duration_(duration),
+    thread_watched_name_(thread_watched_name),
+    ALLOW_THIS_IN_INITIALIZER_LIST(delegate_(this)) {
+  if (!enabled_)
+    return;  // Don't start thread, or doing anything really.
+  enabled_ = PlatformThread::Create(0,  // Default stack size.
+                                    &delegate_,
+                                    &handle_);
+  DCHECK(enabled_);
+}
+
+// Notify watchdog thread, and wait for it to finish up.
+Watchdog::~Watchdog() {
+  if (!enabled_)
+    return;
+  if (!IsJoinable())
+    Cleanup();
+  condition_variable_.Signal();
+  PlatformThread::Join(handle_);
+}
+
+void Watchdog::Cleanup() {
+  if (!enabled_)
+    return;
+  {
+    AutoLock lock(lock_);
+    state_ = SHUTDOWN;
+  }
+  condition_variable_.Signal();
+}
+
+bool Watchdog::IsJoinable() {
+  if (!enabled_)
+    return true;
+  AutoLock lock(lock_);
+  return (state_ == JOINABLE);
+}
+
+void Watchdog::Arm() {
+  ArmAtStartTime(TimeTicks::Now());
+}
+
+void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta& time_delta) {
+  ArmAtStartTime(TimeTicks::Now() - time_delta);
+}
+
+// Start clock for watchdog.
+void Watchdog::ArmAtStartTime(const TimeTicks start_time) {
+  {
+    AutoLock lock(lock_);
+    start_time_ = start_time;
+    state_ = ARMED;
+  }
+  // Force watchdog to wake up, and go to sleep with the timer ticking with the
+  // proper duration.
+  condition_variable_.Signal();
+}
+
+// Disable watchdog so that it won't do anything when time expires.
+void Watchdog::Disarm() {
+  AutoLock lock(lock_);
+  state_ = DISARMED;
+  // We don't need to signal, as the watchdog will eventually wake up, and it
+  // will check its state and time, and act accordingly.
+}
+
+void Watchdog::Alarm() {
+  DVLOG(1) << "Watchdog alarmed for " << thread_watched_name_;
+}
+
+//------------------------------------------------------------------------------
+// Internal private methods that the watchdog thread uses.
+
+void Watchdog::ThreadDelegate::ThreadMain() {
+  SetThreadName();
+  TimeDelta remaining_duration;
+  while (1) {
+    AutoLock lock(watchdog_->lock_);
+    while (DISARMED == watchdog_->state_)
+      watchdog_->condition_variable_.Wait();
+    if (SHUTDOWN == watchdog_->state_) {
+      watchdog_->state_ = JOINABLE;
+      return;
+    }
+    DCHECK(ARMED == watchdog_->state_);
+    remaining_duration = watchdog_->duration_ -
+        (TimeTicks::Now() - watchdog_->start_time_);
+    if (remaining_duration.InMilliseconds() > 0) {
+      // Spurios wake?  Timer drifts?  Go back to sleep for remaining time.
+      watchdog_->condition_variable_.TimedWait(remaining_duration);
+      continue;
+    }
+    // We overslept, so this seems like a real alarm.
+    // Watch out for a user that stopped the debugger on a different alarm!
+    {
+      AutoLock static_lock(*g_static_lock.Pointer());
+      if (g_last_debugged_alarm_time > watchdog_->start_time_) {
+        // False alarm: we started our clock before the debugger break (last
+        // alarm time).
+        watchdog_->start_time_ += g_last_debugged_alarm_delay;
+        if (g_last_debugged_alarm_time > watchdog_->start_time_)
+          // Too many alarms must have taken place.
+          watchdog_->state_ = DISARMED;
+        continue;
+      }
+    }
+    watchdog_->state_ = DISARMED;  // Only alarm at most once.
+    TimeTicks last_alarm_time = TimeTicks::Now();
+    {
+      AutoUnlock lock(watchdog_->lock_);
+      watchdog_->Alarm();  // Set a break point here to debug on alarms.
+    }
+    TimeDelta last_alarm_delay = TimeTicks::Now() - last_alarm_time;
+    if (last_alarm_delay <= TimeDelta::FromMilliseconds(2))
+      continue;
+    // Ignore race of two alarms/breaks going off at roughly the same time.
+    AutoLock static_lock(*g_static_lock.Pointer());
+    // This was a real debugger break.
+    g_last_debugged_alarm_time = last_alarm_time;
+    g_last_debugged_alarm_delay = last_alarm_delay;
+  }
+}
+
+void Watchdog::ThreadDelegate::SetThreadName() const {
+  std::string name = watchdog_->thread_watched_name_ + " Watchdog";
+  PlatformThread::SetName(name.c_str());
+  DVLOG(1) << "Watchdog active: " << name;
+}
+
+// static
+void Watchdog::ResetStaticData() {
+  AutoLock lock(*g_static_lock.Pointer());
+  g_last_debugged_alarm_time = TimeTicks();
+  g_last_debugged_alarm_delay = TimeDelta();
+}
+
+}  // namespace base
diff --git a/base/threading/watchdog.h b/base/threading/watchdog.h
new file mode 100644
index 0000000..5b0b210
--- /dev/null
+++ b/base/threading/watchdog.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.
+
+// The Watchdog class creates a second thread that can Alarm if a specific
+// duration of time passes without proper attention.  The duration of time is
+// specified at construction time.  The Watchdog may be used many times by
+// simply calling Arm() (to start timing) and Disarm() (to reset the timer).
+// The Watchdog is typically used under a debugger, where the stack traces on
+// other threads can be examined if/when the Watchdog alarms.
+
+// Some watchdogs will be enabled or disabled via command line switches. To
+// facilitate such code, an "enabled" argument for the constuctor can be used
+// to permanently disable the watchdog.  Disabled watchdogs don't even spawn
+// a second thread, and their methods call (Arm() and Disarm()) return very
+// quickly.
+
+#ifndef BASE_THREADING_WATCHDOG_H_
+#define BASE_THREADING_WATCHDOG_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/time.h"
+
+namespace base {
+
+class BASE_EXPORT Watchdog {
+ public:
+  // Constructor specifies how long the Watchdog will wait before alarming.
+  Watchdog(const TimeDelta& duration,
+           const std::string& thread_watched_name,
+           bool enabled);
+  virtual ~Watchdog();
+
+  // Notify watchdog thread to finish up. Sets the state_ to SHUTDOWN.
+  void Cleanup();
+
+  // Returns true if we state_ is JOINABLE (which indicates that Watchdog has
+  // exited).
+  bool IsJoinable();
+
+  // Start timing, and alarm when time expires (unless we're disarm()ed.)
+  void Arm();  // Arm  starting now.
+  void ArmSomeTimeDeltaAgo(const TimeDelta& time_delta);
+  void ArmAtStartTime(const TimeTicks start_time);
+
+  // Reset time, and do not set off the alarm.
+  void Disarm();
+
+  // Alarm is called if the time expires after an Arm() without someone calling
+  // Disarm().  This method can be overridden to create testable classes.
+  virtual void Alarm();
+
+  // Reset static data to initial state. Useful for tests, to ensure
+  // they are independent.
+  static void ResetStaticData();
+
+ private:
+  class ThreadDelegate : public PlatformThread::Delegate {
+   public:
+    explicit ThreadDelegate(Watchdog* watchdog) : watchdog_(watchdog) {
+    }
+    virtual void ThreadMain() OVERRIDE;
+   private:
+    void SetThreadName() const;
+
+    Watchdog* watchdog_;
+  };
+
+  enum State {ARMED, DISARMED, SHUTDOWN, JOINABLE };
+
+  bool enabled_;
+
+  Lock lock_;  // Mutex for state_.
+  ConditionVariable condition_variable_;
+  State state_;
+  const TimeDelta duration_;  // How long after start_time_ do we alarm?
+  const std::string thread_watched_name_;
+  PlatformThreadHandle handle_;
+  ThreadDelegate delegate_;  // Store it, because it must outlive the thread.
+
+  TimeTicks start_time_;  // Start of epoch, and alarm after duration_.
+
+  DISALLOW_COPY_AND_ASSIGN(Watchdog);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_WATCHDOG_H_
diff --git a/base/threading/watchdog_unittest.cc b/base/threading/watchdog_unittest.cc
new file mode 100644
index 0000000..92ab02c
--- /dev/null
+++ b/base/threading/watchdog_unittest.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/watchdog.h"
+
+#include "base/logging.h"
+#include "base/synchronization/spin_wait.h"
+#include "base/threading/platform_thread.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+//------------------------------------------------------------------------------
+// Provide a derived class to facilitate testing.
+
+class WatchdogCounter : public Watchdog {
+ public:
+  WatchdogCounter(const TimeDelta& duration,
+                  const std::string& thread_watched_name,
+                  bool enabled)
+      : Watchdog(duration, thread_watched_name, enabled),
+        alarm_counter_(0) {
+  }
+
+  virtual ~WatchdogCounter() {}
+
+  virtual void Alarm() OVERRIDE {
+    alarm_counter_++;
+    Watchdog::Alarm();
+  }
+
+  int alarm_counter() { return alarm_counter_; }
+
+ private:
+  int alarm_counter_;
+
+  DISALLOW_COPY_AND_ASSIGN(WatchdogCounter);
+};
+
+class WatchdogTest : public testing::Test {
+ public:
+  virtual void SetUp() OVERRIDE {
+    Watchdog::ResetStaticData();
+  }
+};
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+// Actual tests
+
+// Minimal constructor/destructor test.
+TEST_F(WatchdogTest, StartupShutdownTest) {
+  Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
+  Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
+}
+
+// Test ability to call Arm and Disarm repeatedly.
+TEST_F(WatchdogTest, ArmDisarmTest) {
+  Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
+  watchdog1.Arm();
+  watchdog1.Disarm();
+  watchdog1.Arm();
+  watchdog1.Disarm();
+
+  Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
+  watchdog2.Arm();
+  watchdog2.Disarm();
+  watchdog2.Arm();
+  watchdog2.Disarm();
+}
+
+// Make sure a basic alarm fires when the time has expired.
+TEST_F(WatchdogTest, AlarmTest) {
+  WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Enabled", true);
+  watchdog.Arm();
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
+                                   watchdog.alarm_counter() > 0);
+  EXPECT_EQ(1, watchdog.alarm_counter());
+}
+
+// Make sure a basic alarm fires when the time has expired.
+TEST_F(WatchdogTest, AlarmPriorTimeTest) {
+  WatchdogCounter watchdog(TimeDelta(), "Enabled2", true);
+  // Set a time in the past.
+  watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(2));
+  // It should instantly go off, but certainly in less than 5 minutes.
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
+                                   watchdog.alarm_counter() > 0);
+
+  EXPECT_EQ(1, watchdog.alarm_counter());
+}
+
+// Make sure a disable alarm does nothing, even if we arm it.
+TEST_F(WatchdogTest, ConstructorDisabledTest) {
+  WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Disabled", false);
+  watchdog.Arm();
+  // Alarm should not fire, as it was disabled.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
+  EXPECT_EQ(0, watchdog.alarm_counter());
+}
+
+// Make sure Disarming will prevent firing, even after Arming.
+TEST_F(WatchdogTest, DisarmTest) {
+  WatchdogCounter watchdog(TimeDelta::FromSeconds(1), "Enabled3", true);
+
+  TimeTicks start = TimeTicks::Now();
+  watchdog.Arm();
+  // Sleep a bit, but not past the alarm point.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  watchdog.Disarm();
+  TimeTicks end = TimeTicks::Now();
+
+  if (end - start > TimeDelta::FromMilliseconds(500)) {
+    LOG(WARNING) << "100ms sleep took over 500ms, making the results of this "
+                 << "timing-sensitive test suspicious.  Aborting now.";
+    return;
+  }
+
+  // Alarm should not have fired before it was disarmed.
+  EXPECT_EQ(0, watchdog.alarm_counter());
+
+  // Sleep past the point where it would have fired if it wasn't disarmed,
+  // and verify that it didn't fire.
+  PlatformThread::Sleep(TimeDelta::FromSeconds(1));
+  EXPECT_EQ(0, watchdog.alarm_counter());
+
+  // ...but even after disarming, we can still use the alarm...
+  // Set a time greater than the timeout into the past.
+  watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(10));
+  // It should almost instantly go off, but certainly in less than 5 minutes.
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
+                                   watchdog.alarm_counter() > 0);
+
+  EXPECT_EQ(1, watchdog.alarm_counter());
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool.cc b/base/threading/worker_pool.cc
new file mode 100644
index 0000000..16cc061
--- /dev/null
+++ b/base/threading/worker_pool.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/worker_pool.h"
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "base/task_runner.h"
+#include "base/threading/post_task_and_reply_impl.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+namespace {
+
+class PostTaskAndReplyWorkerPool : public internal::PostTaskAndReplyImpl {
+ public:
+  PostTaskAndReplyWorkerPool(bool task_is_slow) : task_is_slow_(task_is_slow) {
+  }
+
+ private:
+  virtual 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:
+  WorkerPoolTaskRunner(bool tasks_are_slow);
+
+  // TaskRunner implementation
+  virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               TimeDelta delay) OVERRIDE;
+  virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
+
+ private:
+  virtual ~WorkerPoolTaskRunner();
+
+  // 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) {
+  return PostTaskAndReplyWorkerPool(task_is_slow).PostTaskAndReply(
+      from_here, task, reply);
+}
+
+// static
+const scoped_refptr<TaskRunner>&
+WorkerPool::GetTaskRunner(bool tasks_are_slow) {
+  return g_taskrunners.Get().taskrunners_[tasks_are_slow];
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool.h b/base/threading/worker_pool.h
new file mode 100644
index 0000000..333b495
--- /dev/null
+++ b/base/threading/worker_pool.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_WORKER_POOL_H_
+#define BASE_THREADING_WORKER_POOL_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+
+class Task;
+
+namespace tracked_objects {
+class Location;
+}  // namespace tracked_objects
+
+namespace base {
+
+class TaskRunner;
+
+// This is a facility that runs tasks that don't require a specific thread or
+// a message loop.
+//
+// WARNING: This shouldn't be used unless absolutely necessary. We don't wait
+// for the worker pool threads to finish on shutdown, so the tasks running
+// inside the pool must be extremely careful about other objects they access
+// (MessageLoops, Singletons, etc). During shutdown these object may no longer
+// exist.
+class BASE_EXPORT WorkerPool {
+ public:
+  // This function posts |task| to run on a worker thread.  |task_is_slow|
+  // should be used for tasks that will take a long time to execute.  Returns
+  // false if |task| could not be posted to a worker thread.  Regardless of
+  // return value, ownership of |task| is transferred to the worker pool.
+  static bool PostTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task, bool task_is_slow);
+
+  // Just like MessageLoopProxy::PostTaskAndReply, except the destination
+  // for |task| is a worker thread and you can specify |task_is_slow| just
+  // like you can for PostTask above.
+  static bool PostTaskAndReply(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               const Closure& reply,
+                               bool task_is_slow);
+
+  // Return true if the current thread is one that this WorkerPool runs tasks
+  // on.  (Note that if the Windows worker pool is used without going through
+  // this WorkerPool interface, RunsTasksOnCurrentThread would return false on
+  // those threads.)
+  static bool RunsTasksOnCurrentThread();
+
+  // Get a TaskRunner wrapper which posts to the WorkerPool using the given
+  // |task_is_slow| behavior.
+  static const scoped_refptr<TaskRunner>& GetTaskRunner(bool task_is_slow);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_WORKER_POOL_H_
diff --git a/base/threading/worker_pool_posix.cc b/base/threading/worker_pool_posix.cc
new file mode 100644
index 0000000..2ad3925
--- /dev/null
+++ b/base/threading/worker_pool_posix.cc
@@ -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.
+
+#include "base/threading/worker_pool_posix.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/stringprintf.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/worker_pool.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;
+
+#ifdef ADDRESS_SANITIZER
+const int kWorkerThreadStackSize = 256 * 1024;
+#else
+// A stack size of 64 KB is too small for the CERT_PKIXVerifyCert
+// function of NSS because of NSS bug 439169.
+const int kWorkerThreadStackSize = 128 * 1024;
+#endif
+
+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) {}
+
+  virtual 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.c_str());
+
+  for (;;) {
+    PendingTask pending_task = pool_->WaitForTask();
+    if (pending_task.task.is_null())
+      break;
+    TRACE_EVENT2("task", "WorkerThread::ThreadMain::Run",
+        "src_file", pending_task.posted_from.file_name(),
+        "src_func", pending_task.posted_from.function_name());
+
+    TrackedTime start_time =
+        tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally);
+
+    pending_task.task.Run();
+
+    tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking(
+        pending_task.birth_tally, TrackedTime(pending_task.time_posted),
+        start_time, tracked_objects::ThreadData::NowForEndOfRun());
+  }
+
+  // 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),
+      num_idle_threads_cv_(NULL) {}
+
+PosixDynamicThreadPool::~PosixDynamicThreadPool() {
+  while (!pending_tasks_.empty())
+    pending_tasks_.pop();
+}
+
+void PosixDynamicThreadPool::Terminate() {
+  {
+    AutoLock locked(lock_);
+    DCHECK(!terminated_) << "Thread pool is already terminated.";
+    terminated_ = true;
+  }
+  pending_tasks_available_cv_.Broadcast();
+}
+
+void PosixDynamicThreadPool::PostTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task) {
+  PendingTask pending_task(from_here, task);
+  AddTask(&pending_task);
+}
+
+void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
+  AutoLock locked(lock_);
+  DCHECK(!terminated_) <<
+      "This thread pool is already terminated.  Do not post new tasks.";
+
+  pending_tasks_.push(*pending_task);
+  pending_task->task.Reset();
+
+  // We have enough worker threads.
+  if (static_cast<size_t>(num_idle_threads_) >= pending_tasks_.size()) {
+    pending_tasks_available_cv_.Signal();
+  } else {
+    // The new PlatformThread will take ownership of the WorkerThread object,
+    // which will delete itself on exit.
+    WorkerThread* worker =
+        new WorkerThread(name_prefix_, this);
+    PlatformThread::CreateNonJoinable(kWorkerThreadStackSize, worker);
+  }
+}
+
+PendingTask PosixDynamicThreadPool::WaitForTask() {
+  AutoLock locked(lock_);
+
+  if (terminated_)
+    return PendingTask(FROM_HERE, base::Closure());
+
+  if (pending_tasks_.empty()) {  // No work available, wait for work.
+    num_idle_threads_++;
+    if (num_idle_threads_cv_.get())
+      num_idle_threads_cv_->Signal();
+    pending_tasks_available_cv_.TimedWait(
+        TimeDelta::FromSeconds(idle_seconds_before_exit_));
+    num_idle_threads_--;
+    if (num_idle_threads_cv_.get())
+      num_idle_threads_cv_->Signal();
+    if (pending_tasks_.empty()) {
+      // We waited for work, but there's still no work.  Return NULL to signal
+      // the thread to terminate.
+      return PendingTask(FROM_HERE, base::Closure());
+    }
+  }
+
+  PendingTask pending_task = pending_tasks_.front();
+  pending_tasks_.pop();
+  return pending_task;
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool_posix.h b/base/threading/worker_pool_posix.h
new file mode 100644
index 0000000..dd0ffb6
--- /dev/null
+++ b/base/threading/worker_pool_posix.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The thread pool used in the POSIX implementation of WorkerPool dynamically
+// adds threads as necessary to handle all tasks.  It keeps old threads around
+// for a period of time to allow them to be reused.  After this waiting period,
+// the threads exit.  This thread pool uses non-joinable threads, therefore
+// worker threads are not joined during process shutdown.  This means that
+// potentially long running tasks (such as DNS lookup) do not block process
+// shutdown, but also means that process shutdown may "leak" objects.  Note that
+// although PosixDynamicThreadPool spawns the worker threads and manages the
+// task queue, it does not own the worker threads.  The worker threads ask the
+// PosixDynamicThreadPool for work and eventually clean themselves up.  The
+// worker threads all maintain scoped_refptrs to the PosixDynamicThreadPool
+// instance, which prevents PosixDynamicThreadPool from disappearing before all
+// worker threads exit.  The owner of PosixDynamicThreadPool should likewise
+// maintain a scoped_refptr to the PosixDynamicThreadPool instance.
+//
+// NOTE: The classes defined in this file are only meant for use by the POSIX
+// implementation of WorkerPool.  No one else should be using these classes.
+// These symbols are exported in a header purely for testing purposes.
+
+#ifndef BASE_THREADING_WORKER_POOL_POSIX_H_
+#define BASE_THREADING_WORKER_POOL_POSIX_H_
+
+#include <queue>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/pending_task.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/tracked_objects.h"
+
+class Task;
+
+namespace base {
+
+class BASE_EXPORT PosixDynamicThreadPool
+    : public RefCountedThreadSafe<PosixDynamicThreadPool> {
+ public:
+  class PosixDynamicThreadPoolPeer;
+
+  // All worker threads will share the same |name_prefix|.  They will exit after
+  // |idle_seconds_before_exit|.
+  PosixDynamicThreadPool(const std::string& name_prefix,
+                         int idle_seconds_before_exit);
+
+  // Indicates that the thread pool is going away.  Stops handing out tasks to
+  // worker threads.  Wakes up all the idle threads to let them exit.
+  void Terminate();
+
+  // Adds |task| to the thread pool.
+  void PostTask(const tracked_objects::Location& from_here,
+                const Closure& task);
+
+  // Worker thread method to wait for up to |idle_seconds_before_exit| for more
+  // work from the thread pool.  Returns NULL if no work is available.
+  PendingTask WaitForTask();
+
+ private:
+  friend class RefCountedThreadSafe<PosixDynamicThreadPool>;
+  friend class PosixDynamicThreadPoolPeer;
+
+  ~PosixDynamicThreadPool();
+
+  // Adds pending_task to the thread pool.  This function will clear
+  // |pending_task->task|.
+  void AddTask(PendingTask* pending_task);
+
+  const std::string name_prefix_;
+  const int idle_seconds_before_exit_;
+
+  Lock lock_;  // Protects all the variables below.
+
+  // Signal()s worker threads to let them know more tasks are available.
+  // Also used for Broadcast()'ing to worker threads to let them know the pool
+  // is being deleted and they can exit.
+  ConditionVariable pending_tasks_available_cv_;
+  int num_idle_threads_;
+  TaskQueue pending_tasks_;
+  bool terminated_;
+  // Only used for tests to ensure correct thread ordering.  It will always be
+  // NULL in non-test code.
+  scoped_ptr<ConditionVariable> num_idle_threads_cv_;
+
+  DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPool);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_WORKER_POOL_POSIX_H_
diff --git a/base/threading/worker_pool_posix_unittest.cc b/base/threading/worker_pool_posix_unittest.cc
new file mode 100644
index 0000000..49f6570
--- /dev/null
+++ b/base/threading/worker_pool_posix_unittest.cc
@@ -0,0 +1,254 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/worker_pool_posix.h"
+
+#include <set>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/synchronization/waitable_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Peer class to provide passthrough access to PosixDynamicThreadPool internals.
+class PosixDynamicThreadPool::PosixDynamicThreadPoolPeer {
+ public:
+  explicit PosixDynamicThreadPoolPeer(PosixDynamicThreadPool* pool)
+      : pool_(pool) {}
+
+  Lock* lock() { return &pool_->lock_; }
+  ConditionVariable* pending_tasks_available_cv() {
+    return &pool_->pending_tasks_available_cv_;
+  }
+  const std::queue<PendingTask>& pending_tasks() const {
+    return pool_->pending_tasks_;
+  }
+  int num_idle_threads() const { return pool_->num_idle_threads_; }
+  ConditionVariable* num_idle_threads_cv() {
+    return pool_->num_idle_threads_cv_.get();
+  }
+  void set_num_idle_threads_cv(ConditionVariable* cv) {
+    pool_->num_idle_threads_cv_.reset(cv);
+  }
+
+ private:
+  PosixDynamicThreadPool* pool_;
+
+  DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPoolPeer);
+};
+
+namespace {
+
+// IncrementingTask's main purpose is to increment a counter.  It also updates a
+// set of unique thread ids, and signals a ConditionVariable on completion.
+// Note that since it does not block, there is no way to control the number of
+// threads used if more than one IncrementingTask is consecutively posted to the
+// thread pool, since the first one might finish executing before the subsequent
+// PostTask() calls get invoked.
+void IncrementingTask(Lock* counter_lock,
+                      int* counter,
+                      Lock* unique_threads_lock,
+                      std::set<PlatformThreadId>* unique_threads) {
+  {
+    base::AutoLock locked(*unique_threads_lock);
+    unique_threads->insert(PlatformThread::CurrentId());
+  }
+  base::AutoLock locked(*counter_lock);
+  (*counter)++;
+}
+
+// BlockingIncrementingTask is a simple wrapper around IncrementingTask that
+// allows for waiting at the start of Run() for a WaitableEvent to be signalled.
+struct BlockingIncrementingTaskArgs {
+  Lock* counter_lock;
+  int* counter;
+  Lock* unique_threads_lock;
+  std::set<PlatformThreadId>* unique_threads;
+  Lock* num_waiting_to_start_lock;
+  int* num_waiting_to_start;
+  ConditionVariable* num_waiting_to_start_cv;
+  base::WaitableEvent* start;
+};
+
+void BlockingIncrementingTask(const BlockingIncrementingTaskArgs& args) {
+  {
+    base::AutoLock num_waiting_to_start_locked(*args.num_waiting_to_start_lock);
+    (*args.num_waiting_to_start)++;
+  }
+  args.num_waiting_to_start_cv->Signal();
+  args.start->Wait();
+  IncrementingTask(args.counter_lock, args.counter, args.unique_threads_lock,
+                   args.unique_threads);
+}
+
+class PosixDynamicThreadPoolTest : public testing::Test {
+ protected:
+  PosixDynamicThreadPoolTest()
+      : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60*60)),
+        peer_(pool_.get()),
+        counter_(0),
+        num_waiting_to_start_(0),
+        num_waiting_to_start_cv_(&num_waiting_to_start_lock_),
+        start_(true, false) {}
+
+  virtual void SetUp() OVERRIDE {
+    peer_.set_num_idle_threads_cv(new ConditionVariable(peer_.lock()));
+  }
+
+  virtual 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, peer_.num_idle_threads());
+  EXPECT_EQ(1, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, ReuseIdle) {
+  // Add one task and wait for it to be completed.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+
+  WaitForIdleThreads(1);
+
+  // Add another 2 tasks.  One should reuse the existing worker thread.
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+
+  WaitForTasksToStart(2);
+  start_.Signal();
+  WaitForIdleThreads(2);
+
+  EXPECT_EQ(2U, unique_threads_.size());
+  EXPECT_EQ(2, peer_.num_idle_threads());
+  EXPECT_EQ(3, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, TwoActiveTasks) {
+  // Add two blocking tasks.
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+
+  EXPECT_EQ(0, counter_) << "Blocking tasks should not have started yet.";
+
+  WaitForTasksToStart(2);
+  start_.Signal();
+  WaitForIdleThreads(2);
+
+  EXPECT_EQ(2U, unique_threads_.size());
+  EXPECT_EQ(2, peer_.num_idle_threads()) << "Existing threads are now idle.";
+  EXPECT_EQ(2, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, Complex) {
+  // Add two non blocking tasks and wait for them to finish.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+
+  WaitForIdleThreads(1);
+
+  // Add two blocking tasks, start them simultaneously, and wait for them to
+  // finish.
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+
+  WaitForTasksToStart(2);
+  start_.Signal();
+  WaitForIdleThreads(2);
+
+  EXPECT_EQ(3, counter_);
+  EXPECT_EQ(2, peer_.num_idle_threads());
+  EXPECT_EQ(2U, unique_threads_.size());
+
+  // Wake up all idle threads so they can exit.
+  {
+    base::AutoLock locked(*peer_.lock());
+    while (peer_.num_idle_threads() > 0) {
+      peer_.pending_tasks_available_cv()->Signal();
+      peer_.num_idle_threads_cv()->Wait();
+    }
+  }
+
+  // Add another non blocking task.  There are no threads to reuse.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+  WaitForIdleThreads(1);
+
+  // The POSIX implementation of PlatformThread::CurrentId() uses pthread_self()
+  // which is not guaranteed to be unique after a thread joins. The OS X
+  // implemntation of pthread_self() returns the address of the pthread_t, which
+  // is merely a malloc()ed pointer stored in the first TLS slot. When a thread
+  // joins and that structure is freed, the block of memory can be put on the
+  // OS free list, meaning the same address could be reused in a subsequent
+  // allocation. This in fact happens when allocating in a loop as this test
+  // does.
+  //
+  // Because there are two concurrent threads, there's at least the guarantee
+  // of having two unique thread IDs in the set. But after those two threads are
+  // joined, the next-created thread can get a re-used ID if the allocation of
+  // the pthread_t structure is taken from the free list. Therefore, there can
+  // be either 2 or 3 unique thread IDs in the set at this stage in the test.
+  EXPECT_TRUE(unique_threads_.size() >= 2 && unique_threads_.size() <= 3)
+      << "unique_threads_.size() = " << unique_threads_.size();
+  EXPECT_EQ(1, peer_.num_idle_threads());
+  EXPECT_EQ(4, counter_);
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool_unittest.cc b/base/threading/worker_pool_unittest.cc
new file mode 100644
index 0000000..107588b
--- /dev/null
+++ b/base/threading/worker_pool_unittest.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/worker_pool.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/message_loop.h"
+#include "base/test/test_timeouts.h"
+#include "base/time.h"
+#include "base/threading/thread_checker_impl.h"
+#include "base/synchronization/waitable_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest WorkerPoolTest;
+
+namespace base {
+
+namespace {
+
+class PostTaskAndReplyTester
+    : public base::RefCountedThreadSafe<PostTaskAndReplyTester> {
+ public:
+  PostTaskAndReplyTester() : finished_(false), test_event_(false, false) {}
+
+  void RunTest() {
+    ASSERT_TRUE(thread_checker_.CalledOnValidThread());
+    WorkerPool::PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&PostTaskAndReplyTester::OnWorkerThread, this),
+      base::Bind(&PostTaskAndReplyTester::OnOriginalThread, this),
+      false);
+
+    test_event_.Wait();
+  }
+
+  void OnWorkerThread() {
+    // We're not on the original thread.
+    EXPECT_FALSE(thread_checker_.CalledOnValidThread());
+
+    test_event_.Signal();
+  }
+
+  void OnOriginalThread() {
+    EXPECT_TRUE(thread_checker_.CalledOnValidThread());
+    finished_ = true;
+  }
+
+  bool finished() const {
+    return finished_;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<PostTaskAndReplyTester>;
+  ~PostTaskAndReplyTester() {}
+
+  bool finished_;
+  WaitableEvent test_event_;
+
+  // The Impl version performs its checks even in release builds.
+  ThreadCheckerImpl thread_checker_;
+};
+
+}  // namespace
+
+TEST_F(WorkerPoolTest, PostTask) {
+  WaitableEvent test_event(false, false);
+  WaitableEvent long_test_event(false, false);
+
+  WorkerPool::PostTask(FROM_HERE,
+                       base::Bind(&WaitableEvent::Signal,
+                                  base::Unretained(&test_event)),
+                       false);
+  WorkerPool::PostTask(FROM_HERE,
+                       base::Bind(&WaitableEvent::Signal,
+                                  base::Unretained(&long_test_event)),
+                       true);
+
+  test_event.Wait();
+  long_test_event.Wait();
+}
+
+#if defined(OS_WIN) || defined(OS_LINUX)
+// Flaky on Windows and Linux (http://crbug.com/130337)
+#define MAYBE_PostTaskAndReply DISABLED_PostTaskAndReply
+#else
+#define MAYBE_PostTaskAndReply PostTaskAndReply
+#endif
+
+TEST_F(WorkerPoolTest, MAYBE_PostTaskAndReply) {
+  MessageLoop message_loop;
+  scoped_refptr<PostTaskAndReplyTester> tester(new PostTaskAndReplyTester());
+  tester->RunTest();
+
+  const TimeDelta kMaxDuration = TestTimeouts::tiny_timeout();
+  TimeTicks start = TimeTicks::Now();
+  while (!tester->finished() && TimeTicks::Now() - start < kMaxDuration) {
+#if defined(OS_IOS)
+    // Ensure that the other thread has a chance to run even on a single-core
+    // device.
+    pthread_yield_np();
+#endif
+    MessageLoop::current()->RunUntilIdle();
+  }
+  EXPECT_TRUE(tester->finished());
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool_win.cc b/base/threading/worker_pool_win.cc
new file mode 100644
index 0000000..1e8be26
--- /dev/null
+++ b/base/threading/worker_pool_win.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/worker_pool.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/pending_task.h"
+#include "base/threading/thread_local.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+namespace {
+
+base::LazyInstance<ThreadLocalBoolean>::Leaky
+    g_worker_pool_running_on_this_thread = LAZY_INSTANCE_INITIALIZER;
+
+DWORD CALLBACK WorkItemCallback(void* param) {
+  PendingTask* pending_task = static_cast<PendingTask*>(param);
+  TRACE_EVENT2("task", "WorkItemCallback::Run",
+               "src_file", pending_task->posted_from.file_name(),
+               "src_func", pending_task->posted_from.function_name());
+
+  tracked_objects::TrackedTime start_time =
+      tracked_objects::ThreadData::NowForStartOfRun(pending_task->birth_tally);
+
+  g_worker_pool_running_on_this_thread.Get().Set(true);
+  pending_task->task.Run();
+  g_worker_pool_running_on_this_thread.Get().Set(false);
+
+  tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking(
+      pending_task->birth_tally,
+      tracked_objects::TrackedTime(pending_task->time_posted), start_time,
+      tracked_objects::ThreadData::NowForEndOfRun());
+
+  delete pending_task;
+  return 0;
+}
+
+// Takes ownership of |pending_task|
+bool PostTaskInternal(PendingTask* pending_task, bool task_is_slow) {
+  ULONG flags = 0;
+  if (task_is_slow)
+    flags |= WT_EXECUTELONGFUNCTION;
+
+  if (!QueueUserWorkItem(WorkItemCallback, pending_task, flags)) {
+    DLOG(ERROR) << "QueueUserWorkItem failed: " << GetLastError();
+    delete pending_task;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+// static
+bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
+                          const base::Closure& task, bool task_is_slow) {
+  PendingTask* pending_task = new PendingTask(from_here, task);
+  return PostTaskInternal(pending_task, task_is_slow);
+}
+
+// static
+bool WorkerPool::RunsTasksOnCurrentThread() {
+  return g_worker_pool_running_on_this_thread.Get().Get();
+}
+
+}  // namespace base
diff --git a/base/time.cc b/base/time.cc
new file mode 100644
index 0000000..e5afa12
--- /dev/null
+++ b/base/time.cc
@@ -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.
+
+#include "base/time.h"
+
+#include <math.h>
+#if defined(OS_WIN)
+#include <float.h>
+#endif
+
+#include <limits>
+
+#include "base/sys_string_conversions.h"
+#include "base/third_party/nspr/prtime.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace {
+#if defined(OS_WIN)
+inline bool isnan(double num) { return !!_isnan(num); }
+#endif
+}
+
+// TimeDelta ------------------------------------------------------------------
+
+int TimeDelta::InDays() const {
+  return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
+}
+
+int TimeDelta::InHours() const {
+  return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
+}
+
+int TimeDelta::InMinutes() const {
+  return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
+}
+
+double TimeDelta::InSecondsF() const {
+  return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
+}
+
+int64 TimeDelta::InSeconds() const {
+  return delta_ / Time::kMicrosecondsPerSecond;
+}
+
+double TimeDelta::InMillisecondsF() const {
+  return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
+}
+
+int64 TimeDelta::InMilliseconds() const {
+  return delta_ / Time::kMicrosecondsPerMillisecond;
+}
+
+int64 TimeDelta::InMillisecondsRoundedUp() const {
+  return (delta_ + Time::kMicrosecondsPerMillisecond - 1) /
+      Time::kMicrosecondsPerMillisecond;
+}
+
+int64 TimeDelta::InMicroseconds() const {
+  return delta_;
+}
+
+// Time -----------------------------------------------------------------------
+
+// static
+Time Time::Max() {
+  return Time(std::numeric_limits<int64>::max());
+}
+
+// static
+Time Time::FromTimeT(time_t tt) {
+  if (tt == 0)
+    return Time();  // Preserve 0 so we can tell it doesn't exist.
+  if (tt == std::numeric_limits<time_t>::max())
+    return Max();
+  return Time((tt * kMicrosecondsPerSecond) + kTimeTToMicrosecondsOffset);
+}
+
+time_t Time::ToTimeT() const {
+  if (is_null())
+    return 0;  // Preserve 0 so we can tell it doesn't exist.
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<time_t>::max();
+  }
+  if (std::numeric_limits<int64>::max() - kTimeTToMicrosecondsOffset <= us_) {
+    DLOG(WARNING) << "Overflow when converting base::Time with internal " <<
+                     "value " << us_ << " to time_t.";
+    return std::numeric_limits<time_t>::max();
+  }
+  return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond;
+}
+
+// static
+Time Time::FromDoubleT(double dt) {
+  if (dt == 0 || isnan(dt))
+    return Time();  // Preserve 0 so we can tell it doesn't exist.
+  if (dt == std::numeric_limits<double>::max())
+    return Max();
+  return Time(static_cast<int64>((dt *
+                                  static_cast<double>(kMicrosecondsPerSecond)) +
+                                 kTimeTToMicrosecondsOffset));
+}
+
+double Time::ToDoubleT() const {
+  if (is_null())
+    return 0;  // Preserve 0 so we can tell it doesn't exist.
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<double>::max();
+  }
+  return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
+          static_cast<double>(kMicrosecondsPerSecond));
+}
+
+// static
+Time Time::FromJsTime(double ms_since_epoch) {
+  // The epoch is a valid time, so this constructor doesn't interpret
+  // 0 as the null time.
+  if (ms_since_epoch == std::numeric_limits<double>::max())
+    return Max();
+  return Time(static_cast<int64>(ms_since_epoch * kMicrosecondsPerMillisecond) +
+              kTimeTToMicrosecondsOffset);
+}
+
+double Time::ToJsTime() const {
+  if (is_null()) {
+    // Preserve 0 so the invalid result doesn't depend on the platform.
+    return 0;
+  }
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<double>::max();
+  }
+  return (static_cast<double>(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;
+}
+
+// Time::Exploded -------------------------------------------------------------
+
+inline bool is_in_range(int value, int lo, int hi) {
+  return lo <= value && value <= hi;
+}
+
+bool Time::Exploded::HasValidValues() const {
+  return is_in_range(month, 1, 12) &&
+         is_in_range(day_of_week, 0, 6) &&
+         is_in_range(day_of_month, 1, 31) &&
+         is_in_range(hour, 0, 23) &&
+         is_in_range(minute, 0, 59) &&
+         is_in_range(second, 0, 60) &&
+         is_in_range(millisecond, 0, 999);
+}
+
+}  // namespace base
diff --git a/base/time.h b/base/time.h
new file mode 100644
index 0000000..78d7456
--- /dev/null
+++ b/base/time.h
@@ -0,0 +1,643 @@
+// Copyright (c) 2012 The Chromium 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 time, internally represented as
+// microseconds (s/1,000,000) since the Windows epoch (1601-01-01 00:00:00 UTC)
+// (See http://crbug.com/14734).  System-dependent clock interface routines are
+// defined in time_PLATFORM.cc.
+//
+// TimeDelta represents a duration of time, internally represented in
+// microseconds.
+//
+// TimeTicks represents an abstract time that is most of the time incrementing
+// for use in measuring time durations. It is internally represented in
+// microseconds.  It can not be converted to a human-readable time, but is
+// guaranteed not to decrease (if the user changes the computer clock,
+// Time::Now() may actually decrease or jump).  But note that TimeTicks may
+// "stand still", for example if the computer suspended.
+//
+// These classes are represented as only a 64-bit value, so they can be
+// efficiently passed by value.
+
+#ifndef BASE_TIME_H_
+#define BASE_TIME_H_
+
+#include <time.h>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+// Avoid Mac system header macro leak.
+#undef TYPE_BOOL
+#endif
+
+#if defined(OS_POSIX)
+// For struct timeval.
+#include <sys/time.h>
+#endif
+
+#if defined(OS_WIN)
+// For FILETIME in FromFileTime, until it moves to a new converter class.
+// See TODO(iyengar) below.
+#include <windows.h>
+#endif
+
+#include <limits>
+
+namespace base {
+
+class Time;
+class TimeTicks;
+
+// TimeDelta ------------------------------------------------------------------
+
+class BASE_EXPORT TimeDelta {
+ public:
+  TimeDelta() : delta_(0) {
+  }
+
+  // Converts units of time to TimeDeltas.
+  static TimeDelta FromDays(int64 days);
+  static TimeDelta FromHours(int64 hours);
+  static TimeDelta FromMinutes(int64 minutes);
+  static TimeDelta FromSeconds(int64 secs);
+  static TimeDelta FromMilliseconds(int64 ms);
+  static TimeDelta FromMicroseconds(int64 us);
+#if defined(OS_WIN)
+  static TimeDelta FromQPCValue(LONGLONG qpc_value);
+#endif
+
+  // Converts an integer value representing TimeDelta to a class. This is used
+  // when deserializing a |TimeDelta| structure, using a value known to be
+  // compatible. It is not provided as a constructor because the integer type
+  // may be unclear from the perspective of a caller.
+  static TimeDelta FromInternalValue(int64 delta) {
+    return TimeDelta(delta);
+  }
+
+  // Returns the internal numeric value of the TimeDelta object. Please don't
+  // use this and do arithmetic on it, as it is more error prone than using the
+  // provided operators.
+  // For serializing, use FromInternalValue to reconstitute.
+  int64 ToInternalValue() const {
+    return delta_;
+  }
+
+#if defined(OS_POSIX)
+  struct timespec ToTimeSpec() const;
+#endif
+
+  // Returns the time delta in some unit. The F versions return a floating
+  // point value, the "regular" versions return a rounded-down value.
+  //
+  // InMillisecondsRoundedUp() instead returns an integer that is rounded up
+  // to the next full millisecond.
+  int InDays() const;
+  int InHours() const;
+  int InMinutes() const;
+  double InSecondsF() const;
+  int64 InSeconds() const;
+  double InMillisecondsF() const;
+  int64 InMilliseconds() const;
+  int64 InMillisecondsRoundedUp() const;
+  int64 InMicroseconds() const;
+
+  TimeDelta& operator=(TimeDelta other) {
+    delta_ = other.delta_;
+    return *this;
+  }
+
+  // Computations with other deltas.
+  TimeDelta operator+(TimeDelta other) const {
+    return TimeDelta(delta_ + other.delta_);
+  }
+  TimeDelta operator-(TimeDelta other) const {
+    return TimeDelta(delta_ - other.delta_);
+  }
+
+  TimeDelta& operator+=(TimeDelta other) {
+    delta_ += other.delta_;
+    return *this;
+  }
+  TimeDelta& operator-=(TimeDelta other) {
+    delta_ -= other.delta_;
+    return *this;
+  }
+  TimeDelta operator-() const {
+    return TimeDelta(-delta_);
+  }
+
+  // Computations with ints, note that we only allow multiplicative operations
+  // with ints, and additive operations with other deltas.
+  TimeDelta operator*(int64 a) const {
+    return TimeDelta(delta_ * a);
+  }
+  TimeDelta operator/(int64 a) const {
+    return TimeDelta(delta_ / a);
+  }
+  TimeDelta& operator*=(int64 a) {
+    delta_ *= a;
+    return *this;
+  }
+  TimeDelta& operator/=(int64 a) {
+    delta_ /= a;
+    return *this;
+  }
+  int64 operator/(TimeDelta a) const {
+    return delta_ / a.delta_;
+  }
+
+  // Defined below because it depends on the definition of the other classes.
+  Time operator+(Time t) const;
+  TimeTicks operator+(TimeTicks t) const;
+
+  // Comparison operators.
+  bool operator==(TimeDelta other) const {
+    return delta_ == other.delta_;
+  }
+  bool operator!=(TimeDelta other) const {
+    return delta_ != other.delta_;
+  }
+  bool operator<(TimeDelta other) const {
+    return delta_ < other.delta_;
+  }
+  bool operator<=(TimeDelta other) const {
+    return delta_ <= other.delta_;
+  }
+  bool operator>(TimeDelta other) const {
+    return delta_ > other.delta_;
+  }
+  bool operator>=(TimeDelta other) const {
+    return delta_ >= other.delta_;
+  }
+
+ private:
+  friend class Time;
+  friend class TimeTicks;
+  friend TimeDelta operator*(int64 a, TimeDelta td);
+
+  // Constructs a delta given the duration in microseconds. This is private
+  // to avoid confusion by callers with an integer constructor. Use
+  // FromSeconds, FromMilliseconds, etc. instead.
+  explicit TimeDelta(int64 delta_us) : delta_(delta_us) {
+  }
+
+  // Delta in microseconds.
+  int64 delta_;
+};
+
+inline TimeDelta operator*(int64 a, TimeDelta td) {
+  return TimeDelta(a * td.delta_);
+}
+
+// Time -----------------------------------------------------------------------
+
+// Represents a wall clock time.
+class BASE_EXPORT Time {
+ public:
+  static const int64 kMillisecondsPerSecond = 1000;
+  static const int64 kMicrosecondsPerMillisecond = 1000;
+  static const int64 kMicrosecondsPerSecond = kMicrosecondsPerMillisecond *
+                                              kMillisecondsPerSecond;
+  static const int64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
+  static const int64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
+  static const int64 kMicrosecondsPerDay = kMicrosecondsPerHour * 24;
+  static const int64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
+  static const int64 kNanosecondsPerMicrosecond = 1000;
+  static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
+                                             kMicrosecondsPerSecond;
+
+#if !defined(OS_WIN)
+  // On Mac & Linux, this value is the delta from the Windows epoch of 1601 to
+  // the Posix delta of 1970. This is used for migrating between the old
+  // 1970-based epochs to the new 1601-based ones. It should be removed from
+  // this global header and put in the platform-specific ones when we remove the
+  // migration code.
+  static const int64 kWindowsEpochDeltaMicroseconds;
+#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.
+  explicit Time() : us_(0) {
+  }
+
+  // Returns true if the time object has not been initialized.
+  bool is_null() const {
+    return us_ == 0;
+  }
+
+  // Returns true if the time object is the maximum time.
+  bool is_max() const {
+    return us_ == std::numeric_limits<int64>::max();
+  }
+
+  // Returns the time for epoch in Unix-like system (Jan 1, 1970).
+  static Time UnixEpoch();
+
+  // Returns the current time. Watch out, the system might adjust its clock
+  // in which case time will actually go backwards. We don't guarantee that
+  // times are increasing, or that two calls to Now() won't be the same.
+  static Time Now();
+
+  // Returns the maximum time, which should be greater than any reasonable time
+  // with which we might compare it.
+  static Time Max();
+
+  // Returns the current time. Same as Now() except that this function always
+  // uses system time so that there are no discrepancies between the returned
+  // time and system time even on virtual environments including our test bot.
+  // For timing sensitive unittests, this function should be used.
+  static Time NowFromSystemTime();
+
+  // Converts to/from time_t in UTC and a Time class.
+  // TODO(brettw) this should be removed once everybody starts using the |Time|
+  // class.
+  static Time FromTimeT(time_t tt);
+  time_t ToTimeT() const;
+
+  // Converts time to/from a double which is the number of seconds since epoch
+  // (Jan 1, 1970).  Webkit uses this format to represent time.
+  // Because WebKit initializes double time value to 0 to indicate "not
+  // initialized", we map it to empty Time object that also means "not
+  // initialized".
+  static Time FromDoubleT(double dt);
+  double ToDoubleT() const;
+
+  // 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;
+
+#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. If the high resolution
+  // timer is not enabled, calls to ActivateHighResolutionTimer will fail.
+  // When disabling the high resolution timer, this function will not cause
+  // the high resolution timer to be deactivated, but will prevent future
+  // activations.
+  // Must be called from the main thread.
+  // For more details see comments in time_win.cc.
+  static void EnableHighResolutionTimer(bool enable);
+
+  // Activates or deactivates the high resolution timer based on the |activate|
+  // flag.  If the HighResolutionTimer is not Enabled (see
+  // EnableHighResolutionTimer), this function will return false.  Otherwise
+  // returns true.  Each successful activate call must be paired with a
+  // subsequent deactivate call.
+  // All callers to activate the high resolution timer must eventually call
+  // this function to deactivate the high resolution timer.
+  static bool ActivateHighResolutionTimer(bool activate);
+
+  // Returns true if the high resolution timer is both enabled and activated.
+  // This is provided for testing only, and is not tracked in a thread-safe
+  // way.
+  static bool IsHighResolutionTimerInUse();
+#endif
+
+  // Converts an exploded structure representing either the local time or UTC
+  // into a Time class.
+  static Time FromUTCExploded(const Exploded& exploded) {
+    return FromExploded(false, exploded);
+  }
+  static Time FromLocalExploded(const Exploded& exploded) {
+    return FromExploded(true, exploded);
+  }
+
+  // Converts an integer value representing Time to a class. This is used
+  // when deserializing a |Time| 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 Time FromInternalValue(int64 us) {
+    return Time(us);
+  }
+
+  // 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);
+  }
+
+  // For serializing, use FromInternalValue to reconstitute. Please don't use
+  // this and do arithmetic on it, as it is more error prone than using the
+  // provided operators.
+  int64 ToInternalValue() const {
+    return us_;
+  }
+
+  // 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;
+
+  Time& operator=(Time other) {
+    us_ = other.us_;
+    return *this;
+  }
+
+  // Compute the difference between two times.
+  TimeDelta operator-(Time other) const {
+    return TimeDelta(us_ - other.us_);
+  }
+
+  // Modify by some time delta.
+  Time& operator+=(TimeDelta delta) {
+    us_ += delta.delta_;
+    return *this;
+  }
+  Time& operator-=(TimeDelta delta) {
+    us_ -= delta.delta_;
+    return *this;
+  }
+
+  // Return a new time modified by some delta.
+  Time operator+(TimeDelta delta) const {
+    return Time(us_ + delta.delta_);
+  }
+  Time operator-(TimeDelta delta) const {
+    return Time(us_ - delta.delta_);
+  }
+
+  // Comparison operators
+  bool operator==(Time other) const {
+    return us_ == other.us_;
+  }
+  bool operator!=(Time other) const {
+    return us_ != other.us_;
+  }
+  bool operator<(Time other) const {
+    return us_ < other.us_;
+  }
+  bool operator<=(Time other) const {
+    return us_ <= other.us_;
+  }
+  bool operator>(Time other) const {
+    return us_ > other.us_;
+  }
+  bool operator>=(Time other) const {
+    return us_ >= other.us_;
+  }
+
+ private:
+  friend class TimeDelta;
+
+  explicit Time(int64 us) : us_(us) {
+  }
+
+  // Explodes the given time to either local time |is_local = true| or UTC
+  // |is_local = false|.
+  void Explode(bool is_local, Exploded* exploded) const;
+
+  // Unexplodes a given time assuming the source is either local time
+  // |is_local = true| or UTC |is_local = false|.
+  static Time FromExploded(bool is_local, const Exploded& exploded);
+
+  // Converts a string representation of time to a Time object.
+  // An example of a time string which is converted is as below:-
+  // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified
+  // in the input string, local time |is_local = true| or
+  // UTC |is_local = false| is assumed. A timezone that cannot be parsed
+  // (e.g. "UTC" which is not specified in RFC822) is treated as if the
+  // timezone is not specified.
+  static bool FromStringInternal(const char* time_string,
+                                 bool is_local,
+                                 Time* parsed_time);
+
+  // The representation of Jan 1, 1970 UTC in microseconds since the
+  // platform-dependent epoch.
+  static const int64 kTimeTToMicrosecondsOffset;
+
+#if defined(OS_WIN)
+  // Indicates whether fast timers are usable right now.  For instance,
+  // when using battery power, we might elect to prevent high speed timers
+  // which would draw more power.
+  static bool high_resolution_timer_enabled_;
+  // Count of activations on the high resolution timer.  Only use in tests
+  // which are single threaded.
+  static int high_resolution_timer_activated_;
+#endif
+
+  // Time in microseconds in UTC.
+  int64 us_;
+};
+
+// Inline the TimeDelta factory methods, for fast TimeDelta construction.
+
+// static
+inline TimeDelta TimeDelta::FromDays(int64 days) {
+  return TimeDelta(days * Time::kMicrosecondsPerDay);
+}
+
+// static
+inline TimeDelta TimeDelta::FromHours(int64 hours) {
+  return TimeDelta(hours * Time::kMicrosecondsPerHour);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMinutes(int64 minutes) {
+  return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
+}
+
+// static
+inline TimeDelta TimeDelta::FromSeconds(int64 secs) {
+  return TimeDelta(secs * Time::kMicrosecondsPerSecond);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMilliseconds(int64 ms) {
+  return TimeDelta(ms * Time::kMicrosecondsPerMillisecond);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMicroseconds(int64 us) {
+  return TimeDelta(us);
+}
+
+inline Time TimeDelta::operator+(Time t) const {
+  return Time(t.us_ + delta_);
+}
+
+// TimeTicks ------------------------------------------------------------------
+
+class BASE_EXPORT TimeTicks {
+ public:
+  TimeTicks() : ticks_(0) {
+  }
+
+  // Platform-dependent tick count representing "right now."
+  // The resolution of this clock is ~1-15ms.  Resolution varies depending
+  // on hardware/operating system configuration.
+  static TimeTicks Now();
+
+  // Returns a platform-dependent high-resolution tick count. Implementation
+  // is hardware dependent and may or may not return sub-millisecond
+  // resolution.  THIS CALL IS GENERALLY MUCH MORE EXPENSIVE THAN Now() AND
+  // SHOULD ONLY BE USED WHEN IT IS REALLY NEEDED.
+  static TimeTicks HighResNow();
+
+  // Returns the current system trace time or, if none is defined, the current
+  // high-res time (i.e. HighResNow()). On systems where a global trace clock
+  // is defined, timestamping TraceEvents's with this value guarantees
+  // synchronization between events collected inside chrome and events
+  // collected outside (e.g. kernel, X server).
+  static TimeTicks NowFromSystemTraceTime();
+
+#if defined(OS_WIN)
+  // Get the absolute value of QPC time drift. For testing.
+  static int64 GetQPCDriftMicroseconds();
+
+  static TimeTicks FromQPCValue(LONGLONG qpc_value);
+
+  // Returns true if the high resolution clock is working on this system.
+  // This is only for testing.
+  static bool IsHighResClockWorking();
+#endif
+
+  // Returns true if this object has not been initialized.
+  bool is_null() const {
+    return ticks_ == 0;
+  }
+
+  // Converts an integer value representing TimeTicks to a class. This is used
+  // when deserializing a |TimeTicks| 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 TimeTicks FromInternalValue(int64 ticks) {
+    return TimeTicks(ticks);
+  }
+
+  // Returns the internal numeric value of the TimeTicks object.
+  // For serializing, use FromInternalValue to reconstitute.
+  int64 ToInternalValue() const {
+    return ticks_;
+  }
+
+  TimeTicks& operator=(TimeTicks other) {
+    ticks_ = other.ticks_;
+    return *this;
+  }
+
+  // Compute the difference between two times.
+  TimeDelta operator-(TimeTicks other) const {
+    return TimeDelta(ticks_ - other.ticks_);
+  }
+
+  // Modify by some time delta.
+  TimeTicks& operator+=(TimeDelta delta) {
+    ticks_ += delta.delta_;
+    return *this;
+  }
+  TimeTicks& operator-=(TimeDelta delta) {
+    ticks_ -= delta.delta_;
+    return *this;
+  }
+
+  // Return a new TimeTicks modified by some delta.
+  TimeTicks operator+(TimeDelta delta) const {
+    return TimeTicks(ticks_ + delta.delta_);
+  }
+  TimeTicks operator-(TimeDelta delta) const {
+    return TimeTicks(ticks_ - delta.delta_);
+  }
+
+  // Comparison operators
+  bool operator==(TimeTicks other) const {
+    return ticks_ == other.ticks_;
+  }
+  bool operator!=(TimeTicks other) const {
+    return ticks_ != other.ticks_;
+  }
+  bool operator<(TimeTicks other) const {
+    return ticks_ < other.ticks_;
+  }
+  bool operator<=(TimeTicks other) const {
+    return ticks_ <= other.ticks_;
+  }
+  bool operator>(TimeTicks other) const {
+    return ticks_ > other.ticks_;
+  }
+  bool operator>=(TimeTicks other) const {
+    return ticks_ >= other.ticks_;
+  }
+
+ protected:
+  friend class TimeDelta;
+
+  // Please use Now() to create a new object. This is for internal use
+  // and testing. Ticks is in microseconds.
+  explicit TimeTicks(int64 ticks) : ticks_(ticks) {
+  }
+
+  // Tick count in microseconds.
+  int64 ticks_;
+
+#if defined(OS_WIN)
+  typedef DWORD (*TickFunctionType)(void);
+  static TickFunctionType SetMockTickFunction(TickFunctionType ticker);
+#endif
+};
+
+inline TimeTicks TimeDelta::operator+(TimeTicks t) const {
+  return TimeTicks(t.ticks_ + delta_);
+}
+
+}  // namespace base
+
+#endif  // BASE_TIME_H_
diff --git a/base/time_mac.cc b/base/time_mac.cc
new file mode 100644
index 0000000..ca10bc8
--- /dev/null
+++ b/base/time_mac.cc
@@ -0,0 +1,173 @@
+// Copyright (c) 2012 The Chromium Authors. All 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.h"
+
+#include <CoreFoundation/CFDate.h>
+#include <CoreFoundation/CFTimeZone.h>
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+
+namespace base {
+
+// The Time routines in this file use Mach and CoreFoundation APIs, since the
+// POSIX definition of time_t in Mac OS X wraps around after 2038--and
+// there are already cookie expiration dates, etc., past that time out in
+// the field.  Using CFDate prevents that problem, and using mach_absolute_time
+// for TimeTicks gives us nice high-resolution interval timing.
+
+// Time -----------------------------------------------------------------------
+
+// Core Foundation uses a double second count since 2001-01-01 00:00:00 UTC.
+// The UNIX epoch is 1970-01-01 00:00:00 UTC.
+// Windows uses a Gregorian epoch of 1601.  We need to match this internally
+// so that our time representations match across all platforms.  See bug 14734.
+//   irb(main):010:0> Time.at(0).getutc()
+//   => Thu Jan 01 00:00:00 UTC 1970
+//   irb(main):011:0> Time.at(-11644473600).getutc()
+//   => Mon Jan 01 00:00:00 UTC 1601
+static const int64 kWindowsEpochDeltaSeconds = GG_INT64_C(11644473600);
+static const int64 kWindowsEpochDeltaMilliseconds =
+    kWindowsEpochDeltaSeconds * Time::kMillisecondsPerSecond;
+
+// static
+const int64 Time::kWindowsEpochDeltaMicroseconds =
+    kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
+
+// Some functions in time.cc use time_t directly, so we provide an offset
+// to convert from time_t (Unix epoch) and internal (Windows epoch).
+// static
+const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+
+// static
+Time Time::Now() {
+  return FromCFAbsoluteTime(CFAbsoluteTimeGetCurrent());
+}
+
+// static
+Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
+  if (t == 0)
+    return Time();  // Consider 0 as a null Time.
+  if (t == std::numeric_limits<CFAbsoluteTime>::max())
+    return Max();
+  return Time(static_cast<int64>(
+      (t + kCFAbsoluteTimeIntervalSince1970) * kMicrosecondsPerSecond) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+CFAbsoluteTime Time::ToCFAbsoluteTime() const {
+  if (is_null())
+    return 0;  // Consider 0 as a null Time.
+  if (is_max())
+    return std::numeric_limits<CFAbsoluteTime>::max();
+  return (static_cast<CFAbsoluteTime>(us_ - kWindowsEpochDeltaMicroseconds) /
+      kMicrosecondsPerSecond) - kCFAbsoluteTimeIntervalSince1970;
+}
+
+// static
+Time Time::NowFromSystemTime() {
+  // Just use Now() because Now() returns the system time.
+  return Now();
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+  CFGregorianDate date;
+  date.second = exploded.second +
+      exploded.millisecond / static_cast<double>(kMillisecondsPerSecond);
+  date.minute = exploded.minute;
+  date.hour = exploded.hour;
+  date.day = exploded.day_of_month;
+  date.month = exploded.month;
+  date.year = exploded.year;
+
+  base::mac::ScopedCFTypeRef<CFTimeZoneRef>
+      time_zone(is_local ? CFTimeZoneCopySystem() : NULL);
+  CFAbsoluteTime seconds = CFGregorianDateGetAbsoluteTime(date, time_zone) +
+      kCFAbsoluteTimeIntervalSince1970;
+  return Time(static_cast<int64>(seconds * kMicrosecondsPerSecond) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+  // Avoid rounding issues, by only putting the integral number of seconds
+  // (rounded towards -infinity) into a |CFAbsoluteTime| (which is a |double|).
+  int64 microsecond = us_ % kMicrosecondsPerSecond;
+  if (microsecond < 0)
+    microsecond += kMicrosecondsPerSecond;
+  CFAbsoluteTime seconds = ((us_ - microsecond) / kMicrosecondsPerSecond) -
+                           kWindowsEpochDeltaSeconds -
+                           kCFAbsoluteTimeIntervalSince1970;
+
+  base::mac::ScopedCFTypeRef<CFTimeZoneRef>
+      time_zone(is_local ? CFTimeZoneCopySystem() : NULL);
+  CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(seconds, time_zone);
+  // 1 = Monday, ..., 7 = Sunday.
+  int cf_day_of_week = CFAbsoluteTimeGetDayOfWeek(seconds, time_zone);
+
+  exploded->year = date.year;
+  exploded->month = date.month;
+  exploded->day_of_week = cf_day_of_week % 7;
+  exploded->day_of_month = date.day;
+  exploded->hour = date.hour;
+  exploded->minute = date.minute;
+  // Make sure seconds are rounded down towards -infinity.
+  exploded->second = floor(date.second);
+  // Calculate milliseconds ourselves, since we rounded the |seconds|, making
+  // sure to round towards -infinity.
+  exploded->millisecond =
+      (microsecond >= 0) ? microsecond / kMicrosecondsPerMillisecond :
+                           (microsecond - kMicrosecondsPerMillisecond + 1) /
+                               kMicrosecondsPerMillisecond;
+}
+
+// TimeTicks ------------------------------------------------------------------
+
+// static
+TimeTicks TimeTicks::Now() {
+  uint64_t absolute_micro;
+
+  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);
+    DCHECK_EQ(KERN_SUCCESS, kr);
+  }
+
+  // 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.
+  absolute_micro = mach_absolute_time() / Time::kNanosecondsPerMicrosecond *
+                   timebase_info.numer / 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 TimeTicks(absolute_micro);
+}
+
+// static
+TimeTicks TimeTicks::HighResNow() {
+  return Now();
+}
+
+// static
+TimeTicks TimeTicks::NowFromSystemTraceTime() {
+  return HighResNow();
+}
+
+}  // namespace base
diff --git a/base/time_posix.cc b/base/time_posix.cc
new file mode 100644
index 0000000..8b295bd
--- /dev/null
+++ b/base/time_posix.cc
@@ -0,0 +1,292 @@
+// Copyright (c) 2012 The Chromium Authors. All 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.h"
+
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <limits>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#elif defined(OS_NACL)
+#include "base/os_compat_nacl.h"
+#endif
+
+namespace base {
+
+#if defined(OS_ANDROID)
+#define _POSIX_MONOTONIC_CLOCK 1
+#endif
+
+struct timespec TimeDelta::ToTimeSpec() const {
+  int64 microseconds = InMicroseconds();
+  time_t seconds = 0;
+  if (microseconds >= Time::kMicrosecondsPerSecond) {
+    seconds = InSeconds();
+    microseconds -= seconds * Time::kMicrosecondsPerSecond;
+  }
+  struct timespec result =
+      {seconds,
+       static_cast<long>(microseconds * Time::kNanosecondsPerMicrosecond)};
+  return result;
+}
+
+#if !defined(OS_MACOSX)
+// The Time routines in this file use standard POSIX routines, or almost-
+// standard routines in the case of timegm.  We need to use a Mach-specific
+// function for TimeTicks::Now() on Mac OS X.
+
+// Time -----------------------------------------------------------------------
+
+// Windows uses a Gregorian epoch of 1601.  We need to match this internally
+// so that our time representations match across all platforms.  See bug 14734.
+//   irb(main):010:0> Time.at(0).getutc()
+//   => Thu Jan 01 00:00:00 UTC 1970
+//   irb(main):011:0> Time.at(-11644473600).getutc()
+//   => Mon Jan 01 00:00:00 UTC 1601
+static const int64 kWindowsEpochDeltaSeconds = GG_INT64_C(11644473600);
+static const int64 kWindowsEpochDeltaMilliseconds =
+    kWindowsEpochDeltaSeconds * Time::kMillisecondsPerSecond;
+
+// static
+const int64 Time::kWindowsEpochDeltaMicroseconds =
+    kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
+
+// Some functions in time.cc use time_t directly, so we provide an offset
+// to convert from time_t (Unix epoch) and internal (Windows epoch).
+// static
+const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+
+// static
+Time Time::Now() {
+  struct timeval tv;
+  struct timezone tz = { 0, 0 };  // UTC
+  if (gettimeofday(&tv, &tz) != 0) {
+    DCHECK(0) << "Could not determine time of day";
+    LOG_ERRNO(ERROR) << "Call to gettimeofday failed.";
+    // Return null instead of uninitialized |tv| value, which contains random
+    // garbage data. This may result in the crash seen in crbug.com/147570.
+    return Time();
+  }
+  // Combine seconds and microseconds in a 64-bit field containing microseconds
+  // since the epoch.  That's enough for nearly 600 centuries.  Adjust from
+  // Unix (1970) to Windows (1601) epoch.
+  return Time((tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+// static
+Time Time::NowFromSystemTime() {
+  // Just use Now() because Now() returns the system time.
+  return Now();
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+  // Time stores times with microsecond resolution, but Exploded only carries
+  // millisecond resolution, so begin by being lossy.  Adjust from Windows
+  // epoch (1601) to Unix epoch (1970);
+  int64 microseconds = us_ - kWindowsEpochDeltaMicroseconds;
+  // The following values are all rounded towards -infinity.
+  int64 milliseconds;  // Milliseconds since epoch.
+  time_t 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;
+  if (is_local)
+    localtime_r(&seconds, &timestruct);
+  else
+    gmtime_r(&seconds, &timestruct);
+
+  exploded->year         = timestruct.tm_year + 1900;
+  exploded->month        = timestruct.tm_mon + 1;
+  exploded->day_of_week  = timestruct.tm_wday;
+  exploded->day_of_month = timestruct.tm_mday;
+  exploded->hour         = timestruct.tm_hour;
+  exploded->minute       = timestruct.tm_min;
+  exploded->second       = timestruct.tm_sec;
+  exploded->millisecond  = millisecond;
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+  struct tm timestruct;
+  timestruct.tm_sec    = exploded.second;
+  timestruct.tm_min    = exploded.minute;
+  timestruct.tm_hour   = exploded.hour;
+  timestruct.tm_mday   = exploded.day_of_month;
+  timestruct.tm_mon    = exploded.month - 1;
+  timestruct.tm_year   = exploded.year - 1900;
+  timestruct.tm_wday   = exploded.day_of_week;  // mktime/timegm ignore this
+  timestruct.tm_yday   = 0;     // mktime/timegm ignore this
+  timestruct.tm_isdst  = -1;    // attempt to figure it out
+#if !defined(OS_NACL) && !defined(OS_SOLARIS)
+  timestruct.tm_gmtoff = 0;     // not a POSIX field, so mktime/timegm ignore
+  timestruct.tm_zone   = NULL;  // not a POSIX field, so mktime/timegm ignore
+#endif
+
+  time_t seconds;
+  if (is_local)
+    seconds = mktime(&timestruct);
+  else
+    seconds = timegm(&timestruct);
+
+  int64 milliseconds;
+  // 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.
+    if (exploded.year < 1969) {
+      milliseconds = std::numeric_limits<time_t>::min() *
+                     kMillisecondsPerSecond;
+    } else {
+      milliseconds = (std::numeric_limits<time_t>::max() *
+                      kMillisecondsPerSecond) +
+                     kMillisecondsPerSecond - 1;
+    }
+  } else {
+    milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond;
+  }
+
+  // Adjust from Unix (1970) to Windows (1601) epoch.
+  return Time((milliseconds * kMicrosecondsPerMillisecond) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+// TimeTicks ------------------------------------------------------------------
+// FreeBSD 6 has CLOCK_MONOLITHIC 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)
+
+// static
+TimeTicks TimeTicks::Now() {
+  uint64_t absolute_micro;
+
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
+    NOTREACHED() << "clock_gettime(CLOCK_MONOTONIC) failed.";
+    return TimeTicks();
+  }
+
+  absolute_micro =
+      (static_cast<int64>(ts.tv_sec) * Time::kMicrosecondsPerSecond) +
+      (static_cast<int64>(ts.tv_nsec) / Time::kNanosecondsPerMicrosecond);
+
+  return TimeTicks(absolute_micro);
+}
+#else  // _POSIX_MONOTONIC_CLOCK
+#error No usable tick clock function on this platform.
+#endif  // _POSIX_MONOTONIC_CLOCK
+
+// static
+TimeTicks TimeTicks::HighResNow() {
+  return Now();
+}
+
+#if defined(OS_CHROMEOS)
+// Force definition of the system trace clock; it is a chromeos-only api
+// at the moment and surfacing it in the right place requires mucking
+// with glibc et al.
+#define CLOCK_SYSTEM_TRACE 11
+
+// static
+TimeTicks TimeTicks::NowFromSystemTraceTime() {
+  uint64_t absolute_micro;
+
+  struct timespec ts;
+  if (clock_gettime(CLOCK_SYSTEM_TRACE, &ts) != 0) {
+    // NB: fall-back for a chrome os build running on linux
+    return HighResNow();
+  }
+
+  absolute_micro =
+      (static_cast<int64>(ts.tv_sec) * Time::kMicrosecondsPerSecond) +
+      (static_cast<int64>(ts.tv_nsec) / Time::kNanosecondsPerMicrosecond);
+
+  return TimeTicks(absolute_micro);
+}
+
+#else // !defined(OS_CHROMEOS)
+
+// static
+TimeTicks TimeTicks::NowFromSystemTraceTime() {
+  return HighResNow();
+}
+
+#endif // defined(OS_CHROMEOS)
+
+#endif  // !OS_MACOSX
+
+// static
+Time Time::FromTimeVal(struct timeval t) {
+  DCHECK_LT(t.tv_usec, static_cast<int>(Time::kMicrosecondsPerSecond));
+  DCHECK_GE(t.tv_usec, 0);
+  if (t.tv_usec == 0 && t.tv_sec == 0)
+    return Time();
+  if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 &&
+      t.tv_sec == std::numeric_limits<time_t>::max())
+    return Max();
+  return Time(
+      (static_cast<int64>(t.tv_sec) * Time::kMicrosecondsPerSecond) +
+      t.tv_usec +
+      kTimeTToMicrosecondsOffset);
+}
+
+struct timeval Time::ToTimeVal() const {
+  struct timeval result;
+  if (is_null()) {
+    result.tv_sec = 0;
+    result.tv_usec = 0;
+    return result;
+  }
+  if (is_max()) {
+    result.tv_sec = std::numeric_limits<time_t>::max();
+    result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
+    return result;
+  }
+  int64 us = us_ - kTimeTToMicrosecondsOffset;
+  result.tv_sec = us / Time::kMicrosecondsPerSecond;
+  result.tv_usec = us % Time::kMicrosecondsPerSecond;
+  return result;
+}
+
+}  // namespace base
diff --git a/base/time_unittest.cc b/base/time_unittest.cc
new file mode 100644
index 0000000..dd6d26b
--- /dev/null
+++ b/base/time_unittest.cc
@@ -0,0 +1,676 @@
+// Copyright (c) 2012 The Chromium Authors. All 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.h"
+
+#include <time.h>
+
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+
+// 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:
+  virtual void SetUp() OVERRIDE {
+    // Use mktime to get a time_t, and turn it into a PRTime by converting
+    // seconds to microseconds.  Use 15th Oct 2007 12:45:00 local.  This
+    // must be a time guaranteed to be outside of a DST fallback hour in
+    // any timezone.
+    struct tm local_comparison_tm = {
+      0,            // second
+      45,           // minute
+      12,           // hour
+      15,           // day of month
+      10 - 1,       // month
+      2007 - 1900,  // year
+      0,            // day of week (ignored, output only)
+      0,            // day of year (ignored, output only)
+      -1            // DST in effect, -1 tells mktime to figure it out
+    };
+
+    time_t converted_time = mktime(&local_comparison_tm);
+    ASSERT_GT(converted_time, 0);
+    comparison_time_local_ = Time::FromTimeT(converted_time);
+
+    // time_t representation of 15th Oct 2007 12:45:00 PDT
+    comparison_time_pdt_ = Time::FromTimeT(1192477500);
+  }
+
+  Time comparison_time_local_;
+  Time comparison_time_pdt_;
+};
+
+// Test conversions to/from time_t and exploding/unexploding.
+TEST_F(TimeTest, TimeT) {
+  // C library time and exploded time.
+  time_t now_t_1 = time(NULL);
+  struct tm tms;
+#if defined(OS_WIN)
+  localtime_s(&tms, &now_t_1);
+#elif defined(OS_POSIX)
+  localtime_r(&now_t_1, &tms);
+#endif
+
+  // Convert to ours.
+  Time our_time_1 = Time::FromTimeT(now_t_1);
+  Time::Exploded exploded;
+  our_time_1.LocalExplode(&exploded);
+
+  // This will test both our exploding and our time_t -> Time conversion.
+  EXPECT_EQ(tms.tm_year + 1900, exploded.year);
+  EXPECT_EQ(tms.tm_mon + 1, exploded.month);
+  EXPECT_EQ(tms.tm_mday, exploded.day_of_month);
+  EXPECT_EQ(tms.tm_hour, exploded.hour);
+  EXPECT_EQ(tms.tm_min, exploded.minute);
+  EXPECT_EQ(tms.tm_sec, exploded.second);
+
+  // Convert exploded back to the time struct.
+  Time our_time_2 = Time::FromLocalExploded(exploded);
+  EXPECT_TRUE(our_time_1 == our_time_2);
+
+  time_t now_t_2 = our_time_2.ToTimeT();
+  EXPECT_EQ(now_t_1, now_t_2);
+
+  EXPECT_EQ(10, Time().FromTimeT(10).ToTimeT());
+  EXPECT_EQ(10.0, Time().FromTimeT(10).ToDoubleT());
+
+  // Conversions of 0 should stay 0.
+  EXPECT_EQ(0, Time().ToTimeT());
+  EXPECT_EQ(0, Time::FromTimeT(0).ToInternalValue());
+}
+
+// Test conversions to/from javascript time.
+TEST_F(TimeTest, JsTime) {
+  Time epoch = Time::FromJsTime(0.0);
+  EXPECT_EQ(epoch, Time::UnixEpoch());
+  Time t = Time::FromJsTime(700000.3);
+  EXPECT_EQ(700.0003, t.ToDoubleT());
+  t = Time::FromDoubleT(800.73);
+  EXPECT_EQ(800730.0, t.ToJsTime());
+}
+
+#if defined(OS_POSIX)
+TEST_F(TimeTest, FromTimeVal) {
+  Time now = Time::Now();
+  Time also_now = Time::FromTimeVal(now.ToTimeVal());
+  EXPECT_EQ(now, also_now);
+}
+#endif  // OS_POSIX
+
+TEST_F(TimeTest, FromExplodedWithMilliseconds) {
+  // Some platform implementations of FromExploded are liable to drop
+  // milliseconds if we aren't careful.
+  Time now = Time::NowFromSystemTime();
+  Time::Exploded exploded1 = {0};
+  now.UTCExplode(&exploded1);
+  exploded1.millisecond = 500;
+  Time time = Time::FromUTCExploded(exploded1);
+  Time::Exploded exploded2 = {0};
+  time.UTCExplode(&exploded2);
+  EXPECT_EQ(exploded1.millisecond, exploded2.millisecond);
+}
+
+TEST_F(TimeTest, ZeroIsSymmetric) {
+  Time zero_time(Time::FromTimeT(0));
+  EXPECT_EQ(0, zero_time.ToTimeT());
+
+  EXPECT_EQ(0.0, zero_time.ToDoubleT());
+}
+
+TEST_F(TimeTest, LocalExplode) {
+  Time a = Time::Now();
+  Time::Exploded exploded;
+  a.LocalExplode(&exploded);
+
+  Time b = Time::FromLocalExploded(exploded);
+
+  // The exploded structure doesn't have microseconds, and on Mac & Linux, the
+  // internal OS conversion uses seconds, which will cause truncation. So we
+  // can only make sure that the delta is within one second.
+  EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1));
+}
+
+TEST_F(TimeTest, UTCExplode) {
+  Time a = Time::Now();
+  Time::Exploded exploded;
+  a.UTCExplode(&exploded);
+
+  Time b = Time::FromUTCExploded(exploded);
+  EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1));
+}
+
+TEST_F(TimeTest, LocalMidnight) {
+  Time::Exploded exploded;
+  Time::Now().LocalMidnight().LocalExplode(&exploded);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+}
+
+TEST_F(TimeTest, ParseTimeTest1) {
+  time_t current_time = 0;
+  time(&current_time);
+
+  const int BUFFER_SIZE = 64;
+  struct tm local_time = {0};
+  char time_buf[BUFFER_SIZE] = {0};
+#if defined(OS_WIN)
+  localtime_s(&local_time, &current_time);
+  asctime_s(time_buf, arraysize(time_buf), &local_time);
+#elif defined(OS_POSIX)
+  localtime_r(&current_time, &local_time);
+  asctime_r(&local_time, time_buf);
+#endif
+
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString(time_buf, &parsed_time));
+  EXPECT_EQ(current_time, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, DayOfWeekSunday) {
+  Time time;
+  EXPECT_TRUE(Time::FromString("Sun, 06 May 2012 12:00:00 GMT", &time));
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  EXPECT_EQ(0, exploded.day_of_week);
+}
+
+TEST_F(TimeTest, DayOfWeekWednesday) {
+  Time time;
+  EXPECT_TRUE(Time::FromString("Wed, 09 May 2012 12:00:00 GMT", &time));
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  EXPECT_EQ(3, exploded.day_of_week);
+}
+
+TEST_F(TimeTest, DayOfWeekSaturday) {
+  Time time;
+  EXPECT_TRUE(Time::FromString("Sat, 12 May 2012 12:00:00 GMT", &time));
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  EXPECT_EQ(6, exploded.day_of_week);
+}
+
+TEST_F(TimeTest, ParseTimeTest2) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("Mon, 15 Oct 2007 19:45:00 GMT", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest3) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15 Oct 07 12:45:00", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest4) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15 Oct 07 19:45 GMT", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest5) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("Mon Oct 15 12:45 PDT 2007", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest6) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("Monday, Oct 15, 2007 12:45 PM", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest7) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("10/15/07 12:45:00 PM", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest8) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15-OCT-2007 12:45pm", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest9) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("16 Oct 2007 4:45-JST (Tuesday)", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest10) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15/10/07 12:45", &parsed_time));
+  EXPECT_EQ(parsed_time, comparison_time_local_);
+}
+
+// Test some of edge cases around epoch, etc.
+TEST_F(TimeTest, ParseTimeTestEpoch0) {
+  Time parsed_time;
+
+  // time_t == epoch == 0
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:00 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(0, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:00 GMT 1970",
+                               &parsed_time));
+  EXPECT_EQ(0, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpoch1) {
+  Time parsed_time;
+
+  // time_t == 1 second after epoch == 1
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:01 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(1, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:01 GMT 1970",
+                               &parsed_time));
+  EXPECT_EQ(1, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpoch2) {
+  Time parsed_time;
+
+  // time_t == 2 seconds after epoch == 2
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:02 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(2, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:02 GMT 1970",
+                               &parsed_time));
+  EXPECT_EQ(2, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpochNeg1) {
+  Time parsed_time;
+
+  // time_t == 1 second before epoch == -1
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:59:59 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(-1, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:59 GMT 1969",
+                               &parsed_time));
+  EXPECT_EQ(-1, parsed_time.ToTimeT());
+}
+
+// If time_t is 32 bits, a date after year 2038 will overflow time_t and
+// cause timegm() to return -1.  The parsed time should not be 1 second
+// before epoch.
+TEST_F(TimeTest, ParseTimeTestEpochNotNeg1) {
+  Time parsed_time;
+
+  EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:59 GMT 2100",
+                               &parsed_time));
+  EXPECT_NE(-1, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpochNeg2) {
+  Time parsed_time;
+
+  // time_t == 2 seconds before epoch == -2
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:59:58 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(-2, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:58 GMT 1969",
+                               &parsed_time));
+  EXPECT_EQ(-2, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpoch1960) {
+  Time parsed_time;
+
+  // time_t before Epoch, in 1960
+  EXPECT_TRUE(Time::FromString("Wed Jun 29 19:40:01 +0100 1960",
+                               &parsed_time));
+  EXPECT_EQ(-299999999, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Jun 29 18:40:01 GMT 1960",
+                               &parsed_time));
+  EXPECT_EQ(-299999999, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Jun 29 17:40:01 GMT 1960",
+                               &parsed_time));
+  EXPECT_EQ(-300003599, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEmpty) {
+  Time parsed_time;
+  EXPECT_FALSE(Time::FromString("", &parsed_time));
+}
+
+TEST_F(TimeTest, ParseTimeTestInvalidString) {
+  Time parsed_time;
+  EXPECT_FALSE(Time::FromString("Monday morning 2000", &parsed_time));
+}
+
+TEST_F(TimeTest, ExplodeBeforeUnixEpoch) {
+  static const int kUnixEpochYear = 1970;  // In case this changes (ha!).
+  Time t;
+  Time::Exploded exploded;
+
+  t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59 999 milliseconds (and 999 microseconds).
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(999, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59 999 milliseconds.
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(999, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1001);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59 998 milliseconds (and 999 microseconds).
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(998, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59.
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1001);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:58 999 milliseconds.
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(58, exploded.second);
+  EXPECT_EQ(999, exploded.millisecond);
+
+  // Make sure we still handle at/after Unix epoch correctly.
+  t = Time::UnixEpoch();
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-12-31 00:00:00 0 milliseconds.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:00 0 milliseconds (and 1 microsecond).
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:00 1 millisecond.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(1, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:01.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(1, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1001);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:01 1 millisecond.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(1, exploded.second);
+  EXPECT_EQ(1, exploded.millisecond);
+}
+
+TEST_F(TimeTest, Max) {
+  Time max = Time::Max();
+  EXPECT_TRUE(max.is_max());
+  EXPECT_EQ(max, Time::Max());
+  EXPECT_GT(max, Time::Now());
+  EXPECT_GT(max, Time());
+}
+
+TEST_F(TimeTest, MaxConversions) {
+  Time t = Time::Max();
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue());
+
+  t = Time::FromDoubleT(std::numeric_limits<double>::max());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<double>::max(), t.ToDoubleT());
+
+  t = Time::FromJsTime(std::numeric_limits<double>::max());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<double>::max(), 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>::max());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<CFAbsoluteTime>::max(), t.ToCFAbsoluteTime());
+#endif
+
+#if defined(OS_WIN)
+  FILETIME ftime;
+  ftime.dwHighDateTime = std::numeric_limits<DWORD>::max();
+  ftime.dwLowDateTime = std::numeric_limits<DWORD>::max();
+  t = Time::FromFileTime(ftime);
+  EXPECT_TRUE(t.is_max());
+  ftime = t.ToFileTime();
+  EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwHighDateTime);
+  EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwLowDateTime);
+#endif
+}
+
+#if defined(OS_MACOSX)
+TEST_F(TimeTest, TimeTOverflow) {
+  Time t = Time::FromInternalValue(std::numeric_limits<int64>::max() - 1);
+  EXPECT_FALSE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT());
+}
+#endif
+
+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)()) {
+#if defined(OS_WIN)
+  // HighResNow doesn't work on some systems.  Since the product still works
+  // even if it doesn't work, it makes this entire test questionable.
+  if (!TimeTicks::IsHighResClockWorking())
+    return;
+#endif
+
+  // 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, HighResNow) {
+  HighResClockTest(&TimeTicks::HighResNow);
+}
+
+TEST(TimeTicks, NowFromSystemTraceTime) {
+  // Re-use HighResNow test for now since clock properties are identical.
+  HighResClockTest(&TimeTicks::NowFromSystemTraceTime);
+}
+
+TEST(TimeDelta, FromAndIn) {
+  EXPECT_TRUE(TimeDelta::FromDays(2) == TimeDelta::FromHours(48));
+  EXPECT_TRUE(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180));
+  EXPECT_TRUE(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120));
+  EXPECT_TRUE(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000));
+  EXPECT_TRUE(TimeDelta::FromMilliseconds(2) ==
+              TimeDelta::FromMicroseconds(2000));
+  EXPECT_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::FromMicroseconds(13).InMicroseconds());
+}
+
+#if defined(OS_POSIX)
+TEST(TimeDelta, TimeSpecConversion) {
+  struct timespec result = TimeDelta::FromSeconds(0).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 0);
+  EXPECT_EQ(result.tv_nsec, 0);
+
+  result = TimeDelta::FromSeconds(1).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 1);
+  EXPECT_EQ(result.tv_nsec, 0);
+
+  result = TimeDelta::FromMicroseconds(1).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 0);
+  EXPECT_EQ(result.tv_nsec, 1000);
+
+  result = TimeDelta::FromMicroseconds(
+      Time::kMicrosecondsPerSecond + 1).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 1);
+  EXPECT_EQ(result.tv_nsec, 1000);
+}
+#endif  // OS_POSIX
+
+// Our internal time format is serialized in things like databases, so it's
+// important that it's consistent across all our platforms.  We use the 1601
+// Windows epoch as the internal format across all platforms.
+TEST(TimeDelta, WindowsEpoch) {
+  Time::Exploded exploded;
+  exploded.year = 1970;
+  exploded.month = 1;
+  exploded.day_of_week = 0;  // Should be unusued.
+  exploded.day_of_month = 1;
+  exploded.hour = 0;
+  exploded.minute = 0;
+  exploded.second = 0;
+  exploded.millisecond = 0;
+  Time t = Time::FromUTCExploded(exploded);
+  // Unix 1970 epoch.
+  EXPECT_EQ(GG_INT64_C(11644473600000000), t.ToInternalValue());
+
+  // We can't test 1601 epoch, since the system time functions on Linux
+  // only compute years starting from 1900.
+}
diff --git a/base/time_win.cc b/base/time_win.cc
new file mode 100644
index 0000000..6d8e432
--- /dev/null
+++ b/base/time_win.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.
+
+
+// Windows Timer Primer
+//
+// A good article:  http://www.ddj.com/windows/184416651
+// A good mozilla bug:  http://bugzilla.mozilla.org/show_bug.cgi?id=363258
+//
+// The default windows timer, GetSystemTimeAsFileTime is not very precise.
+// It is only good to ~15.5ms.
+//
+// QueryPerformanceCounter is the logical choice for a high-precision timer.
+// However, it is known to be buggy on some hardware.  Specifically, it can
+// sometimes "jump".  On laptops, QPC can also be very expensive to call.
+// It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower
+// on laptops.  A unittest exists which will show the relative cost of various
+// timers on any system.
+//
+// The next logical choice is timeGetTime().  timeGetTime has a precision of
+// 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other
+// applications on the system.  By default, precision is only 15.5ms.
+// Unfortunately, we don't want to call timeBeginPeriod because we don't
+// want to affect other applications.  Further, on mobile platforms, use of
+// faster multimedia timers can hurt battery life.  See the intel
+// article about this here:
+// http://softwarecommunity.intel.com/articles/eng/1086.htm
+//
+// To work around all this, we're going to generally use timeGetTime().  We
+// will only increase the system-wide timer if we're not running on battery
+// power.  Using timeBeginPeriod(1) is a requirement in order to make our
+// message loop waits have the same resolution that our time measurements
+// do.  Otherwise, WaitForSingleObject(..., 1) will no less than 15ms when
+// there is nothing else to waken the Wait.
+
+#include "base/time.h"
+
+#pragma comment(lib, "winmm.lib")
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/cpu.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace {
+
+// From MSDN, FILETIME "Contains a 64-bit value representing the number of
+// 100-nanosecond intervals since January 1, 1601 (UTC)."
+int64 FileTimeToMicroseconds(const FILETIME& ft) {
+  // Need to bit_cast to fix alignment, then divide by 10 to convert
+  // 100-nanoseconds to milliseconds. This only works on little-endian
+  // machines.
+  return bit_cast<int64, FILETIME>(ft) / 10;
+}
+
+void MicrosecondsToFileTime(int64 us, FILETIME* ft) {
+  DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not "
+      "representable in FILETIME";
+
+  // Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will
+  // handle alignment problems. This only works on little-endian machines.
+  *ft = bit_cast<FILETIME, int64>(us * 10);
+}
+
+int64 CurrentWallclockMicroseconds() {
+  FILETIME ft;
+  ::GetSystemTimeAsFileTime(&ft);
+  return FileTimeToMicroseconds(ft);
+}
+
+// Time between resampling the un-granular clock for this API.  60 seconds.
+const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
+
+int64 initial_time = 0;
+TimeTicks initial_ticks;
+
+void InitializeClock() {
+  initial_ticks = TimeTicks::Now();
+  initial_time = CurrentWallclockMicroseconds();
+}
+
+}  // namespace
+
+// Time -----------------------------------------------------------------------
+
+// The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
+// 00:00:00 UTC.  ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
+// number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
+// 1700, 1800, and 1900.
+// static
+const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000);
+
+bool Time::high_resolution_timer_enabled_ = false;
+int Time::high_resolution_timer_activated_ = 0;
+
+// static
+Time Time::Now() {
+  if (initial_time == 0)
+    InitializeClock();
+
+  // We implement time using the high-resolution timers so that we can get
+  // timeouts which are smaller than 10-15ms.  If we just used
+  // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
+  //
+  // To make this work, we initialize the clock (initial_time) and the
+  // counter (initial_ctr).  To compute the initial time, we can check
+  // the number of ticks that have elapsed, and compute the delta.
+  //
+  // To avoid any drift, we periodically resync the counters to the system
+  // clock.
+  while (true) {
+    TimeTicks ticks = TimeTicks::Now();
+
+    // Calculate the time elapsed since we started our timer
+    TimeDelta elapsed = ticks - initial_ticks;
+
+    // Check if enough time has elapsed that we need to resync the clock.
+    if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
+      InitializeClock();
+      continue;
+    }
+
+    return Time(elapsed + Time(initial_time));
+  }
+}
+
+// static
+Time Time::NowFromSystemTime() {
+  // Force resync.
+  InitializeClock();
+  return Time(initial_time);
+}
+
+// static
+Time Time::FromFileTime(FILETIME ft) {
+  if (bit_cast<int64, FILETIME>(ft) == 0)
+    return Time();
+  if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() &&
+      ft.dwLowDateTime == std::numeric_limits<DWORD>::max())
+    return Max();
+  return Time(FileTimeToMicroseconds(ft));
+}
+
+FILETIME Time::ToFileTime() const {
+  if (is_null())
+    return bit_cast<FILETIME, int64>(0);
+  if (is_max()) {
+    FILETIME result;
+    result.dwHighDateTime = std::numeric_limits<DWORD>::max();
+    result.dwLowDateTime = std::numeric_limits<DWORD>::max();
+    return result;
+  }
+  FILETIME utc_ft;
+  MicrosecondsToFileTime(us_, &utc_ft);
+  return utc_ft;
+}
+
+// static
+void Time::EnableHighResolutionTimer(bool enable) {
+  // Test for single-threaded access.
+  static PlatformThreadId my_thread = PlatformThread::CurrentId();
+  DCHECK(PlatformThread::CurrentId() == my_thread);
+
+  if (high_resolution_timer_enabled_ == enable)
+    return;
+
+  high_resolution_timer_enabled_ = enable;
+}
+
+// static
+bool Time::ActivateHighResolutionTimer(bool activating) {
+  if (!high_resolution_timer_enabled_ && activating)
+    return false;
+
+  // Using anything other than 1ms makes timers granular
+  // to that interval.
+  const int kMinTimerIntervalMs = 1;
+  MMRESULT result;
+  if (activating) {
+    result = timeBeginPeriod(kMinTimerIntervalMs);
+    high_resolution_timer_activated_++;
+  } else {
+    result = timeEndPeriod(kMinTimerIntervalMs);
+    high_resolution_timer_activated_--;
+  }
+  return result == TIMERR_NOERROR;
+}
+
+// static
+bool Time::IsHighResolutionTimerInUse() {
+  // Note:  we should track the high_resolution_timer_activated_ value
+  // under a lock if we want it to be accurate in a system with multiple
+  // message loops.  We don't do that - because we don't want to take the
+  // expense of a lock for this.  We *only* track this value so that unit
+  // tests can see if the high resolution timer is on or off.
+  return high_resolution_timer_enabled_ &&
+      high_resolution_timer_activated_ > 0;
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+  // Create the system struct representing our exploded time. It will either be
+  // in local time or UTC.
+  SYSTEMTIME st;
+  st.wYear = exploded.year;
+  st.wMonth = exploded.month;
+  st.wDayOfWeek = exploded.day_of_week;
+  st.wDay = exploded.day_of_month;
+  st.wHour = exploded.hour;
+  st.wMinute = exploded.minute;
+  st.wSecond = exploded.second;
+  st.wMilliseconds = exploded.millisecond;
+
+  FILETIME ft;
+  bool success = true;
+  // Ensure that it's in UTC.
+  if (is_local) {
+    SYSTEMTIME utc_st;
+    success = TzSpecificLocalTimeToSystemTime(NULL, &st, &utc_st) &&
+              SystemTimeToFileTime(&utc_st, &ft);
+  } else {
+    success = !!SystemTimeToFileTime(&st, &ft);
+  }
+
+  if (!success) {
+    NOTREACHED() << "Unable to convert time";
+    return Time(0);
+  }
+  return Time(FileTimeToMicroseconds(ft));
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+  if (us_ < 0LL) {
+    // We are not able to convert it to FILETIME.
+    ZeroMemory(exploded, sizeof(*exploded));
+    return;
+  }
+
+  // FILETIME in UTC.
+  FILETIME utc_ft;
+  MicrosecondsToFileTime(us_, &utc_ft);
+
+  // FILETIME in local time if necessary.
+  bool success = true;
+  // FILETIME in SYSTEMTIME (exploded).
+  SYSTEMTIME st;
+  if (is_local) {
+    SYSTEMTIME utc_st;
+    // We don't use FileTimeToLocalFileTime here, since it uses the current
+    // settings for the time zone and daylight saving time. Therefore, if it is
+    // daylight saving time, it will take daylight saving time into account,
+    // even if the time you are converting is in standard time.
+    success = FileTimeToSystemTime(&utc_ft, &utc_st) &&
+              SystemTimeToTzSpecificLocalTime(NULL, &utc_st, &st);
+  } else {
+    success = !!FileTimeToSystemTime(&utc_ft, &st);
+  }
+
+  if (!success) {
+    NOTREACHED() << "Unable to convert time, don't know why";
+    ZeroMemory(exploded, sizeof(*exploded));
+    return;
+  }
+
+  exploded->year = st.wYear;
+  exploded->month = st.wMonth;
+  exploded->day_of_week = st.wDayOfWeek;
+  exploded->day_of_month = st.wDay;
+  exploded->hour = st.wHour;
+  exploded->minute = st.wMinute;
+  exploded->second = st.wSecond;
+  exploded->millisecond = st.wMilliseconds;
+}
+
+// TimeTicks ------------------------------------------------------------------
+namespace {
+
+// We define a wrapper to adapt between the __stdcall and __cdecl call of the
+// mock function, and to avoid a static constructor.  Assigning an import to a
+// function pointer directly would require setup code to fetch from the IAT.
+DWORD timeGetTimeWrapper() {
+  return timeGetTime();
+}
+
+DWORD (*tick_function)(void) = &timeGetTimeWrapper;
+
+// Accumulation of time lost due to rollover (in milliseconds).
+int64 rollover_ms = 0;
+
+// The last timeGetTime value we saw, to detect rollover.
+DWORD last_seen_now = 0;
+
+// Lock protecting rollover_ms and last_seen_now.
+// Note: this is a global object, and we usually avoid these. However, the time
+// code is low-level, and we don't want to use Singletons here (it would be too
+// easy to use a Singleton without even knowing it, and that may lead to many
+// gotchas). Its impact on startup time should be negligible due to low-level
+// nature of time code.
+base::Lock rollover_lock;
+
+// We use timeGetTime() to implement TimeTicks::Now().  This can be problematic
+// because it returns the number of milliseconds since Windows has started,
+// which will roll over the 32-bit value every ~49 days.  We try to track
+// rollover ourselves, which works if TimeTicks::Now() is called at least every
+// 49 days.
+TimeDelta RolloverProtectedNow() {
+  base::AutoLock locked(rollover_lock);
+  // We should hold the lock while calling tick_function to make sure that
+  // we keep last_seen_now stay correctly in sync.
+  DWORD now = tick_function();
+  if (now < last_seen_now)
+    rollover_ms += 0x100000000I64;  // ~49.7 days.
+  last_seen_now = now;
+  return TimeDelta::FromMilliseconds(now + rollover_ms);
+}
+
+// Overview of time counters:
+// (1) CPU cycle counter. (Retrieved via RDTSC)
+// The CPU counter provides the highest resolution time stamp and is the least
+// expensive to retrieve. However, the CPU counter is unreliable and should not
+// be used in production. Its biggest issue is that it is per processor and it
+// is not synchronized between processors. Also, on some computers, the counters
+// will change frequency due to thermal and power changes, and stop in some
+// states.
+//
+// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
+// resolution (100 nanoseconds) time stamp but is comparatively more expensive
+// to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
+// (with some help from ACPI).
+// According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
+// in the worst case, it gets the counter from the rollover interrupt on the
+// programmable interrupt timer. In best cases, the HAL may conclude that the
+// RDTSC counter runs at a constant frequency, then it uses that instead. On
+// multiprocessor machines, it will try to verify the values returned from
+// RDTSC on each processor are consistent with each other, and apply a handful
+// of workarounds for known buggy hardware. In other words, QPC is supposed to
+// give consistent result on a multiprocessor computer, but it is unreliable in
+// reality due to bugs in BIOS or HAL on some, especially old computers.
+// With recent updates on HAL and newer BIOS, QPC is getting more reliable but
+// it should be used with caution.
+//
+// (3) System time. The system time provides a low-resolution (typically 10ms
+// to 55 milliseconds) time stamp but is comparatively less expensive to
+// retrieve and more reliable.
+class HighResNowSingleton {
+ public:
+  static HighResNowSingleton* GetInstance() {
+    return Singleton<HighResNowSingleton>::get();
+  }
+
+  bool IsUsingHighResClock() {
+    return ticks_per_second_ != 0.0;
+  }
+
+  void DisableHighResClock() {
+    ticks_per_second_ = 0.0;
+  }
+
+  TimeDelta Now() {
+    if (IsUsingHighResClock())
+      return TimeDelta::FromMicroseconds(UnreliableNow());
+
+    // Just fallback to the slower clock.
+    return RolloverProtectedNow();
+  }
+
+  int64 GetQPCDriftMicroseconds() {
+    if (!IsUsingHighResClock())
+      return 0;
+
+    // The static_cast<long> is needed as a hint to VS 2008 to tell it
+    // which version of abs() to use. Other compilers don't seem to
+    // need it, including VS 2010, but to keep code identical we use it
+    // everywhere.
+    // TODO(joi): Remove the hint if/when we no longer support VS 2008.
+    return abs(static_cast<long>((UnreliableNow() - ReliableNow()) - skew_));
+  }
+
+  int64 QPCValueToMicroseconds(LONGLONG qpc_value) {
+    if (!ticks_per_second_)
+      return 0;
+
+    // Intentionally calculate microseconds in a round about manner to avoid
+    // overflow and precision issues. Think twice before simplifying!
+    int64 whole_seconds = qpc_value / ticks_per_second_;
+    int64 leftover_ticks = qpc_value % ticks_per_second_;
+    int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) +
+                         ((leftover_ticks * Time::kMicrosecondsPerSecond) /
+                          ticks_per_second_);
+    return microseconds;
+  }
+
+ private:
+  HighResNowSingleton()
+    : ticks_per_second_(0),
+      skew_(0) {
+    InitializeClock();
+
+    // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
+    // unreliable.  Fallback to low-res clock.
+    base::CPU cpu;
+    if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15)
+      DisableHighResClock();
+  }
+
+  // Synchronize the QPC clock with GetSystemTimeAsFileTime.
+  void InitializeClock() {
+    LARGE_INTEGER ticks_per_sec = {0};
+    if (!QueryPerformanceFrequency(&ticks_per_sec))
+      return;  // Broken, we don't guarantee this function works.
+    ticks_per_second_ = ticks_per_sec.QuadPart;
+
+    skew_ = UnreliableNow() - ReliableNow();
+  }
+
+  // Get the number of microseconds since boot in an unreliable fashion.
+  int64 UnreliableNow() {
+    LARGE_INTEGER now;
+    QueryPerformanceCounter(&now);
+    return QPCValueToMicroseconds(now.QuadPart);
+  }
+
+  // Get the number of microseconds since boot in a reliable fashion.
+  int64 ReliableNow() {
+    return RolloverProtectedNow().InMicroseconds();
+  }
+
+  int64 ticks_per_second_;  // 0 indicates QPF failed and we're broken.
+  int64 skew_;  // Skew between lo-res and hi-res clocks (for debugging).
+
+  friend struct DefaultSingletonTraits<HighResNowSingleton>;
+};
+
+}  // namespace
+
+// static
+TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
+    TickFunctionType ticker) {
+  TickFunctionType old = tick_function;
+  tick_function = ticker;
+  return old;
+}
+
+// static
+TimeTicks TimeTicks::Now() {
+  return TimeTicks() + RolloverProtectedNow();
+}
+
+// static
+TimeTicks TimeTicks::HighResNow() {
+  return TimeTicks() + HighResNowSingleton::GetInstance()->Now();
+}
+
+// static
+TimeTicks TimeTicks::NowFromSystemTraceTime() {
+  return HighResNow();
+}
+
+// static
+int64 TimeTicks::GetQPCDriftMicroseconds() {
+  return HighResNowSingleton::GetInstance()->GetQPCDriftMicroseconds();
+}
+
+// static
+TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
+  return TimeTicks(
+      HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value));
+}
+
+// static
+bool TimeTicks::IsHighResClockWorking() {
+  return HighResNowSingleton::GetInstance()->IsUsingHighResClock();
+}
+
+// TimeDelta ------------------------------------------------------------------
+
+// static
+TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
+  return TimeDelta(
+      HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value));
+}
diff --git a/base/time_win_unittest.cc b/base/time_win_unittest.cc
new file mode 100644
index 0000000..7ac3662
--- /dev/null
+++ b/base/time_win_unittest.cc
@@ -0,0 +1,239 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <mmsystem.h>
+#include <process.h>
+
+#include "base/threading/platform_thread.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace {
+
+class MockTimeTicks : public TimeTicks {
+ public:
+  static DWORD Ticker() {
+    return static_cast<int>(InterlockedIncrement(&ticker_));
+  }
+
+  static void InstallTicker() {
+    old_tick_function_ = SetMockTickFunction(&Ticker);
+    ticker_ = -5;
+  }
+
+  static void UninstallTicker() {
+    SetMockTickFunction(old_tick_function_);
+  }
+
+ private:
+  static volatile LONG ticker_;
+  static TickFunctionType old_tick_function_;
+};
+
+volatile LONG MockTimeTicks::ticker_;
+MockTimeTicks::TickFunctionType MockTimeTicks::old_tick_function_;
+
+HANDLE g_rollover_test_start;
+
+unsigned __stdcall RolloverTestThreadMain(void* param) {
+  int64 counter = reinterpret_cast<int64>(param);
+  DWORD rv = WaitForSingleObject(g_rollover_test_start, INFINITE);
+  EXPECT_EQ(rv, WAIT_OBJECT_0);
+
+  TimeTicks last = TimeTicks::Now();
+  for (int index = 0; index < counter; index++) {
+    TimeTicks now = TimeTicks::Now();
+    int64 milliseconds = (now - last).InMilliseconds();
+    // This is a tight loop; we could have looped faster than our
+    // measurements, so the time might be 0 millis.
+    EXPECT_GE(milliseconds, 0);
+    EXPECT_LT(milliseconds, 250);
+    last = now;
+  }
+  return 0;
+}
+
+}  // namespace
+
+TEST(TimeTicks, WinRollover) {
+  // The internal counter rolls over at ~49days.  We'll use a mock
+  // timer to test this case.
+  // Basic test algorithm:
+  //   1) Set clock to rollover - N
+  //   2) Create N threads
+  //   3) Start the threads
+  //   4) Each thread loops through TimeTicks() N times
+  //   5) Each thread verifies integrity of result.
+
+  const int kThreads = 8;
+  // Use int64 so we can cast into a void* without a compiler warning.
+  const int64 kChecks = 10;
+
+  // It takes a lot of iterations to reproduce the bug!
+  // (See bug 1081395)
+  for (int loop = 0; loop < 4096; loop++) {
+    // Setup
+    MockTimeTicks::InstallTicker();
+    g_rollover_test_start = CreateEvent(0, TRUE, FALSE, 0);
+    HANDLE threads[kThreads];
+
+    for (int index = 0; index < kThreads; index++) {
+      void* argument = reinterpret_cast<void*>(kChecks);
+      unsigned thread_id;
+      threads[index] = reinterpret_cast<HANDLE>(
+        _beginthreadex(NULL, 0, RolloverTestThreadMain, argument, 0,
+          &thread_id));
+      EXPECT_NE((HANDLE)NULL, threads[index]);
+    }
+
+    // Start!
+    SetEvent(g_rollover_test_start);
+
+    // Wait for threads to finish
+    for (int index = 0; index < kThreads; index++) {
+      DWORD rv = WaitForSingleObject(threads[index], INFINITE);
+      EXPECT_EQ(rv, WAIT_OBJECT_0);
+    }
+
+    CloseHandle(g_rollover_test_start);
+
+    // Teardown
+    MockTimeTicks::UninstallTicker();
+  }
+}
+
+TEST(TimeTicks, SubMillisecondTimers) {
+  // HighResNow doesn't work on some systems.  Since the product still works
+  // even if it doesn't work, it makes this entire test questionable.
+  if (!TimeTicks::IsHighResClockWorking())
+    return;
+
+  const int kRetries = 1000;
+  bool saw_submillisecond_timer = false;
+
+  // Run kRetries attempts to see a sub-millisecond timer.
+  for (int index = 0; index < 1000; index++) {
+    TimeTicks last_time = TimeTicks::HighResNow();
+    TimeDelta delta;
+    // Spin until the clock has detected a change.
+    do {
+      delta = TimeTicks::HighResNow() - last_time;
+    } while (delta.InMicroseconds() == 0);
+    if (delta.InMicroseconds() < 1000) {
+      saw_submillisecond_timer = true;
+      break;
+    }
+  }
+  EXPECT_TRUE(saw_submillisecond_timer);
+}
+
+TEST(TimeTicks, TimeGetTimeCaps) {
+  // Test some basic assumptions that we expect about how timeGetDevCaps works.
+
+  TIMECAPS caps;
+  MMRESULT status = timeGetDevCaps(&caps, sizeof(caps));
+  EXPECT_EQ(TIMERR_NOERROR, status);
+  if (status != TIMERR_NOERROR) {
+    printf("Could not get timeGetDevCaps\n");
+    return;
+  }
+
+  EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1);
+  EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1);
+  EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1);
+  EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1);
+  printf("timeGetTime range is %d to %dms\n", caps.wPeriodMin,
+    caps.wPeriodMax);
+}
+
+TEST(TimeTicks, QueryPerformanceFrequency) {
+  // Test some basic assumptions that we expect about QPC.
+
+  LARGE_INTEGER frequency;
+  BOOL rv = QueryPerformanceFrequency(&frequency);
+  EXPECT_EQ(TRUE, rv);
+  EXPECT_GT(frequency.QuadPart, 1000000);  // Expect at least 1MHz
+  printf("QueryPerformanceFrequency is %5.2fMHz\n",
+    frequency.QuadPart / 1000000.0);
+}
+
+TEST(TimeTicks, TimerPerformance) {
+  // Verify that various timer mechanisms can always complete quickly.
+  // Note:  This is a somewhat arbitrary test.
+  const int kLoops = 10000;
+  // Due to the fact that these run on bbots, which are horribly slow,
+  // we can't really make any guarantees about minimum runtime.
+  // Really, we want these to finish in ~10ms, and that is generous.
+  const int kMaxTime = 35;  // Maximum acceptible milliseconds for test.
+
+  typedef TimeTicks (*TestFunc)();
+  struct TestCase {
+    TestFunc func;
+    char *description;
+  };
+  // Cheating a bit here:  assumes sizeof(TimeTicks) == sizeof(Time)
+  // in order to create a single test case list.
+  COMPILE_ASSERT(sizeof(TimeTicks) == sizeof(Time),
+                 test_only_works_with_same_sizes);
+  TestCase cases[] = {
+    { reinterpret_cast<TestFunc>(Time::Now), "Time::Now" },
+    { TimeTicks::Now, "TimeTicks::Now" },
+    { TimeTicks::HighResNow, "TimeTicks::HighResNow" },
+    { NULL, "" }
+  };
+
+  int test_case = 0;
+  while (cases[test_case].func) {
+    TimeTicks start = TimeTicks::HighResNow();
+    for (int index = 0; index < kLoops; index++)
+      cases[test_case].func();
+    TimeTicks stop = TimeTicks::HighResNow();
+    // Turning off the check for acceptible delays.  Without this check,
+    // the test really doesn't do much other than measure.  But the
+    // measurements are still useful for testing timers on various platforms.
+    // The reason to remove the check is because the tests run on many
+    // buildbots, some of which are VMs.  These machines can run horribly
+    // slow, and there is really no value for checking against a max timer.
+    //EXPECT_LT((stop - start).InMilliseconds(), kMaxTime);
+    printf("%s: %1.2fus per call\n", cases[test_case].description,
+      (stop - start).InMillisecondsF() * 1000 / kLoops);
+    test_case++;
+  }
+}
+
+TEST(TimeTicks, Drift) {
+  // If QPC is disabled, this isn't measuring anything.
+  if (!TimeTicks::IsHighResClockWorking())
+    return;
+
+  const int kIterations = 100;
+  int64 total_drift = 0;
+
+  for (int i = 0; i < kIterations; ++i) {
+    int64 drift_microseconds = TimeTicks::GetQPCDriftMicroseconds();
+
+    // Make sure the drift never exceeds our limit.
+    EXPECT_LT(drift_microseconds, 50000);
+
+    // Sleep for a few milliseconds (note that it means 1000 microseconds).
+    // If we check the drift too frequently, it's going to increase
+    // monotonically, making our measurement less realistic.
+    base::PlatformThread::Sleep(
+        base::TimeDelta::FromMilliseconds((i % 2 == 0) ? 1 : 2));
+
+    total_drift += drift_microseconds;
+  }
+
+  // Sanity check. We expect some time drift to occur, especially across
+  // the number of iterations we do.
+  EXPECT_LT(0, total_drift);
+
+  printf("average time drift in microseconds: %lld\n",
+         total_drift / kIterations);
+}
diff --git a/base/timer.cc b/base/timer.cc
new file mode 100644
index 0000000..410d1b7
--- /dev/null
+++ b/base/timer.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/timer.h"
+
+#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// BaseTimerTaskInternal is a simple delegate for scheduling a callback to
+// Timer in the thread's default task runner. It also handles the following
+// edge cases:
+// - deleted by the task runner.
+// - abandoned (orphaned) by Timer.
+class BaseTimerTaskInternal {
+ public:
+  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();
+}
+
+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_.
+  desired_run_time_ = TimeTicks::Now() + delay_;
+
+  // 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);
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(posted_from_,
+      base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)),
+      delay);
+  scheduled_run_time_ = desired_run_time_ = TimeTicks::Now() + delay;
+  // 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_)
+    thread_id_ = static_cast<int>(PlatformThread::CurrentId());
+}
+
+void Timer::AbandonScheduledTask() {
+  DCHECK(thread_id_ == 0 ||
+         thread_id_ == static_cast<int>(PlatformThread::CurrentId()));
+  if (scheduled_task_) {
+    scheduled_task_->Abandon();
+    scheduled_task_ = NULL;
+  }
+}
+
+void Timer::RunScheduledTask() {
+  // Task may have been disabled.
+  if (!is_running_)
+    return;
+
+  // First check if we need to delay the task because of a new target time.
+  if (desired_run_time_ > scheduled_run_time_) {
+    // TimeTicks::Now() can be expensive, so only call it if we know the user
+    // has changed the desired_run_time_.
+    TimeTicks now = TimeTicks::Now();
+    // Task runner may have called us late anyway, so only post a continuation
+    // task if the desired_run_time_ is in the future.
+    if (desired_run_time_ > now) {
+      // Post a new task to span the remaining time.
+      PostNewScheduledTask(desired_run_time_ - now);
+      return;
+    }
+  }
+
+  // Make a local copy of the task to run. The Stop method will reset the
+  // user_task_ member if retain_user_task_ is false.
+  base::Closure task = user_task_;
+
+  if (is_repeating_)
+    PostNewScheduledTask(delay_);
+  else
+    Stop();
+
+  task.Run();
+
+  // No more member accesses here: *this could be deleted at this point.
+}
+
+}  // namespace base
diff --git a/base/timer.h b/base/timer.h
new file mode 100644
index 0000000..95cae12
--- /dev/null
+++ b/base/timer.h
@@ -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.
+
+// OneShotTimer and RepeatingTimer provide a simple timer API.  As the names
+// suggest, OneShotTimer calls you back once after a time delay expires.
+// RepeatingTimer on the other hand calls you back periodically with the
+// prescribed time interval.
+//
+// OneShotTimer and RepeatingTimer both cancel the timer when they go out of
+// scope, which makes it easy to ensure that you do not get called when your
+// object has gone out of scope.  Just instantiate a OneShotTimer or
+// RepeatingTimer as a member variable of the class for which you wish to
+// receive timer events.
+//
+// Sample RepeatingTimer usage:
+//
+//   class MyClass {
+//    public:
+//     void StartDoingStuff() {
+//       timer_.Start(FROM_HERE, TimeDelta::FromSeconds(1),
+//                    this, &MyClass::DoStuff);
+//     }
+//     void StopDoingStuff() {
+//       timer_.Stop();
+//     }
+//    private:
+//     void DoStuff() {
+//       // This method is called every second to do stuff.
+//       ...
+//     }
+//     base::RepeatingTimer<MyClass> timer_;
+//   };
+//
+// Both OneShotTimer and RepeatingTimer also support a Reset method, which
+// allows you to easily defer the timer event until the timer delay passes once
+// again.  So, in the above example, if 0.5 seconds have already passed,
+// calling Reset on timer_ would postpone DoStuff by another 1 second.  In
+// other words, Reset is shorthand for calling Stop and then Start again with
+// the same arguments.
+//
+// NOTE: These APIs are not thread safe. Always call from the same thread.
+
+#ifndef BASE_TIMER_H_
+#define BASE_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/time.h"
+
+class MessageLoop;
+
+namespace base {
+
+class BaseTimerTaskInternal;
+
+//-----------------------------------------------------------------------------
+// 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).
+  bool IsRunning() const {
+    return is_running_;
+  }
+
+  // Returns the current delay for this timer.
+  TimeDelta GetCurrentDelay() const {
+    return delay_;
+  }
+
+  // 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|.
+  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.
+  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.
+  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);
+
+ 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);
+
+  // 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_;
+
+  // 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().
+  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.
+  TimeTicks desired_run_time_;
+
+  // Thread ID of current MessageLoop for verifying single-threaded usage.
+  int thread_id_;
+
+  // Repeating timers automatically post the task again before calling the task
+  // callback.
+  const bool is_repeating_;
+
+  // If true, hold on to the user_task_ closure object for reuse.
+  const bool retain_user_task_;
+
+  // If true, user_task_ is scheduled to run sometime in the future.
+  bool is_running_;
+
+  DISALLOW_COPY_AND_ASSIGN(Timer);
+};
+
+//-----------------------------------------------------------------------------
+// This class is an implementation detail of OneShotTimer and RepeatingTimer.
+// Please do not use this class directly.
+template <class Receiver, bool kIsRepeating>
+class BaseTimerMethodPointer : public Timer {
+ public:
+  typedef void (Receiver::*ReceiverMethod)();
+
+  // This is here to work around the fact that Timer::Start is "hidden" by the
+  // Start definition below, rather than being overloaded.
+  // TODO(tim): We should remove uses of BaseTimerMethodPointer::Start below
+  // and convert callers to use the base::Closure version in Timer::Start,
+  // see bug 148832.
+  using Timer::Start;
+
+  BaseTimerMethodPointer() : Timer(kIsRepeating, kIsRepeating) {}
+
+  // Start the timer to run at the given |delay| from now. If the timer is
+  // already running, it will be replaced to call a task formed from
+  // |reviewer->*method|.
+  void Start(const tracked_objects::Location& posted_from,
+             TimeDelta delay,
+             Receiver* receiver,
+             ReceiverMethod method) {
+    Timer::Start(posted_from, delay,
+                 base::Bind(method, base::Unretained(receiver)));
+  }
+};
+
+//-----------------------------------------------------------------------------
+// A simple, one-shot timer.  See usage notes at the top of the file.
+template <class Receiver>
+class OneShotTimer : public BaseTimerMethodPointer<Receiver, false> {};
+
+//-----------------------------------------------------------------------------
+// A simple, repeating timer.  See usage notes at the top of the file.
+template <class Receiver>
+class RepeatingTimer : public BaseTimerMethodPointer<Receiver, true> {};
+
+//-----------------------------------------------------------------------------
+// A Delay timer is like The Button from Lost. Once started, you have to keep
+// calling Reset otherwise it will call the given method in the MessageLoop
+// thread.
+//
+// Once created, it is inactive until Reset is called. Once |delay| seconds have
+// passed since the last call to Reset, the callback is made. Once the callback
+// has been made, it's inactive until Reset is called again.
+//
+// If destroyed, the timeout is canceled and will not occur even if already
+// inflight.
+template <class Receiver>
+class DelayTimer : protected Timer {
+ public:
+  typedef void (Receiver::*ReceiverMethod)();
+
+  DelayTimer(const tracked_objects::Location& posted_from,
+             TimeDelta delay,
+             Receiver* receiver,
+             ReceiverMethod method)
+      : Timer(posted_from, delay,
+              base::Bind(method, base::Unretained(receiver)),
+              false) {}
+
+  void Reset() { Timer::Reset(); }
+};
+
+}  // namespace base
+
+#endif  // BASE_TIMER_H_
diff --git a/base/timer_unittest.cc b/base/timer_unittest.cc
new file mode 100644
index 0000000..67bd948
--- /dev/null
+++ b/base/timer_unittest.cc
@@ -0,0 +1,488 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/timer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::TimeDelta;
+
+namespace {
+
+// The message loops on which each timer should be tested.
+const MessageLoop::Type testing_message_loops[] = {
+  MessageLoop::TYPE_DEFAULT,
+  MessageLoop::TYPE_IO,
+#if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop.
+  MessageLoop::TYPE_UI,
+#endif
+};
+
+const int kNumTestingMessageLoops = arraysize(testing_message_loops);
+
+class OneShotTimerTester {
+ public:
+  OneShotTimerTester(bool* did_run, unsigned milliseconds = 10)
+      : did_run_(did_run),
+        delay_ms_(milliseconds) {
+  }
+  void Start() {
+    timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(delay_ms_), this,
+                 &OneShotTimerTester::Run);
+  }
+ private:
+  void Run() {
+    *did_run_ = true;
+    MessageLoop::current()->Quit();
+  }
+  bool* did_run_;
+  base::OneShotTimer<OneShotTimerTester> timer_;
+  const unsigned delay_ms_;
+};
+
+class OneShotSelfDeletingTimerTester {
+ public:
+  explicit OneShotSelfDeletingTimerTester(bool* did_run) :
+      did_run_(did_run),
+      timer_(new base::OneShotTimer<OneShotSelfDeletingTimerTester>()) {
+  }
+  void Start() {
+    timer_->Start(FROM_HERE, TimeDelta::FromMilliseconds(10), this,
+                  &OneShotSelfDeletingTimerTester::Run);
+  }
+ private:
+  void Run() {
+    *did_run_ = true;
+    timer_.reset();
+    MessageLoop::current()->Quit();
+  }
+  bool* did_run_;
+  scoped_ptr<base::OneShotTimer<OneShotSelfDeletingTimerTester> > timer_;
+};
+
+class RepeatingTimerTester {
+ public:
+  explicit RepeatingTimerTester(bool* did_run)
+      : did_run_(did_run), counter_(10) {
+  }
+
+  void Start() {
+    timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), this,
+                 &RepeatingTimerTester::Run);
+  }
+ private:
+  void Run() {
+    if (--counter_ == 0) {
+      *did_run_ = true;
+      MessageLoop::current()->Quit();
+    }
+  }
+  bool* did_run_;
+  int counter_;
+  base::RepeatingTimer<RepeatingTimerTester> timer_;
+};
+
+void RunTest_OneShotTimer(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  bool did_run = false;
+  OneShotTimerTester f(&did_run);
+  f.Start();
+
+  MessageLoop::current()->Run();
+
+  EXPECT_TRUE(did_run);
+}
+
+void RunTest_OneShotTimer_Cancel(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  bool did_run_a = false;
+  OneShotTimerTester* a = new OneShotTimerTester(&did_run_a);
+
+  // This should run before the timer expires.
+  MessageLoop::current()->DeleteSoon(FROM_HERE, a);
+
+  // Now start the timer.
+  a->Start();
+
+  bool did_run_b = false;
+  OneShotTimerTester b(&did_run_b);
+  b.Start();
+
+  MessageLoop::current()->Run();
+
+  EXPECT_FALSE(did_run_a);
+  EXPECT_TRUE(did_run_b);
+}
+
+void RunTest_OneShotSelfDeletingTimer(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  bool did_run = false;
+  OneShotSelfDeletingTimerTester f(&did_run);
+  f.Start();
+
+  MessageLoop::current()->Run();
+
+  EXPECT_TRUE(did_run);
+}
+
+void RunTest_RepeatingTimer(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  bool did_run = false;
+  RepeatingTimerTester f(&did_run);
+  f.Start();
+
+  MessageLoop::current()->Run();
+
+  EXPECT_TRUE(did_run);
+}
+
+void RunTest_RepeatingTimer_Cancel(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  bool did_run_a = false;
+  RepeatingTimerTester* a = new RepeatingTimerTester(&did_run_a);
+
+  // This should run before the timer expires.
+  MessageLoop::current()->DeleteSoon(FROM_HERE, a);
+
+  // Now start the timer.
+  a->Start();
+
+  bool did_run_b = false;
+  RepeatingTimerTester b(&did_run_b);
+  b.Start();
+
+  MessageLoop::current()->Run();
+
+  EXPECT_FALSE(did_run_a);
+  EXPECT_TRUE(did_run_b);
+}
+
+class DelayTimerTarget {
+ public:
+  DelayTimerTarget()
+      : signaled_(false) {
+  }
+
+  bool signaled() const { return signaled_; }
+
+  void Signal() {
+    ASSERT_FALSE(signaled_);
+    signaled_ = true;
+  }
+
+ private:
+  bool signaled_;
+};
+
+void RunTest_DelayTimer_NoCall(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  // If Delay is never called, the timer shouldn't go off.
+  DelayTimerTarget target;
+  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
+      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run);
+  tester.Start();
+  MessageLoop::current()->Run();
+
+  ASSERT_FALSE(target.signaled());
+}
+
+void RunTest_DelayTimer_OneCall(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  DelayTimerTarget target;
+  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
+      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+  timer.Reset();
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run, 100 /* milliseconds */);
+  tester.Start();
+  MessageLoop::current()->Run();
+
+  ASSERT_TRUE(target.signaled());
+}
+
+struct ResetHelper {
+  ResetHelper(base::DelayTimer<DelayTimerTarget>* timer,
+              DelayTimerTarget* target)
+      : timer_(timer),
+        target_(target) {
+  }
+
+  void Reset() {
+    ASSERT_FALSE(target_->signaled());
+    timer_->Reset();
+  }
+
+ private:
+  base::DelayTimer<DelayTimerTarget> *const timer_;
+  DelayTimerTarget *const target_;
+};
+
+void RunTest_DelayTimer_Reset(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  // If Delay is never called, the timer shouldn't go off.
+  DelayTimerTarget target;
+  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
+      TimeDelta::FromMilliseconds(50), &target, &DelayTimerTarget::Signal);
+  timer.Reset();
+
+  ResetHelper reset_helper(&timer, &target);
+
+  base::OneShotTimer<ResetHelper> timers[20];
+  for (size_t i = 0; i < arraysize(timers); ++i) {
+    timers[i].Start(FROM_HERE, TimeDelta::FromMilliseconds(i * 10),
+                    &reset_helper, &ResetHelper::Reset);
+  }
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run, 300);
+  tester.Start();
+  MessageLoop::current()->Run();
+
+  ASSERT_TRUE(target.signaled());
+}
+
+class DelayTimerFatalTarget {
+ public:
+  void Signal() {
+    ASSERT_TRUE(false);
+  }
+};
+
+
+void RunTest_DelayTimer_Deleted(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  DelayTimerFatalTarget target;
+
+  {
+    base::DelayTimer<DelayTimerFatalTarget> timer(
+        FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
+        &DelayTimerFatalTarget::Signal);
+    timer.Reset();
+  }
+
+  // When the timer is deleted, the DelayTimerFatalTarget should never be
+  // called.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+// Each test is run against each type of MessageLoop.  That way we are sure
+// that timers work properly in all configurations.
+
+TEST(TimerTest, OneShotTimer) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OneShotTimer(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, OneShotTimer_Cancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OneShotTimer_Cancel(testing_message_loops[i]);
+  }
+}
+
+// If underline timer does not handle properly, we will crash or fail
+// in full page heap environment.
+TEST(TimerTest, OneShotSelfDeletingTimer) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OneShotSelfDeletingTimer(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, RepeatingTimer) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_RepeatingTimer(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, RepeatingTimer_Cancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_RepeatingTimer_Cancel(testing_message_loops[i]);
+  }
+}
+
+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);
+    {
+      MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+      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) {
+  {
+    MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+    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);
+    MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+    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);
+  {
+    MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+    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) {
+  MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+  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) {
+  MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+  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;
+  MessageLoop::current()->Quit();
+}
+
+void SetCallbackHappened2() {
+  g_callback_happened2 = true;
+  MessageLoop::current()->Quit();
+}
+
+TEST(TimerTest, ContinuationStopStart) {
+  {
+    ClearAllCallbackHappened();
+    MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+    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));
+    MessageLoop::current()->Run();
+    EXPECT_FALSE(g_callback_happened1);
+    EXPECT_TRUE(g_callback_happened2);
+  }
+}
+
+TEST(TimerTest, ContinuationReset) {
+  {
+    ClearAllCallbackHappened();
+    MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+    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());
+    MessageLoop::current()->Run();
+    EXPECT_TRUE(g_callback_happened1);
+  }
+}
+
+}  // namespace
diff --git a/base/tools_sanity_unittest.cc b/base/tools_sanity_unittest.cc
new file mode 100644
index 0000000..d0c57c8
--- /dev/null
+++ b/base/tools_sanity_unittest.cc
@@ -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.
+//
+// This file contains intentional memory errors, some of which may lead to
+// crashes if the test is ran without special memory testing tools. We use these
+// errors to verify the sanity of the tools.
+
+#include "base/atomicops.h"
+#include "base/message_loop.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const base::subtle::Atomic32 kMagicValue = 42;
+
+// Helper for memory accesses that can potentially corrupt memory or cause a
+// crash during a native run.
+#if defined(ADDRESS_SANITIZER)
+#if defined(OS_IOS)
+// EXPECT_DEATH is not supported on IOS.
+#define HARMFUL_ACCESS(action,error_regexp) do { action; } while (0)
+#else
+#define HARMFUL_ACCESS(action,error_regexp) EXPECT_DEATH(action,error_regexp)
+#endif  // !OS_IOS
+#else
+#define HARMFUL_ACCESS(action,error_regexp) \
+do { if (RunningOnValgrind()) { action; } } while (0)
+#endif
+
+void ReadUninitializedValue(char *ptr) {
+  // Comparison with 64 is to prevent clang from optimizing away the
+  // jump -- valgrind only catches jumps and conditional moves, but clang uses
+  // the borrow flag if the condition is just `*ptr == '\0'`.
+  if (*ptr == 64) {
+    (*ptr)++;
+  } else {
+    (*ptr)--;
+  }
+}
+
+void ReadValueOutOfArrayBoundsLeft(char *ptr) {
+  char c = ptr[-2];
+  VLOG(1) << "Reading a byte out of bounds: " << c;
+}
+
+void ReadValueOutOfArrayBoundsRight(char *ptr, size_t size) {
+  char c = ptr[size + 1];
+  VLOG(1) << "Reading a byte out of bounds: " << c;
+}
+
+// This is harmless if you run it under Valgrind thanks to redzones.
+void WriteValueOutOfArrayBoundsLeft(char *ptr) {
+  ptr[-1] = kMagicValue;
+}
+
+// This is harmless if you run it under Valgrind thanks to redzones.
+void WriteValueOutOfArrayBoundsRight(char *ptr, size_t size) {
+  ptr[size] = kMagicValue;
+}
+
+void MakeSomeErrors(char *ptr, size_t size) {
+  ReadUninitializedValue(ptr);
+  HARMFUL_ACCESS(ReadValueOutOfArrayBoundsLeft(ptr),
+                 "heap-buffer-overflow.*2 bytes to the left");
+  HARMFUL_ACCESS(ReadValueOutOfArrayBoundsRight(ptr, size),
+                 "heap-buffer-overflow.*1 bytes to the right");
+  HARMFUL_ACCESS(WriteValueOutOfArrayBoundsLeft(ptr),
+                 "heap-buffer-overflow.*1 bytes to the left");
+  HARMFUL_ACCESS(WriteValueOutOfArrayBoundsRight(ptr, size),
+                 "heap-buffer-overflow.*0 bytes to the right");
+}
+
+}  // namespace
+
+// A memory leak detector should report an error in this test.
+TEST(ToolsSanityTest, MemoryLeak) {
+  // Without the |volatile|, clang optimizes away the next two lines.
+  int* volatile leak = new int[256];  // Leak some memory intentionally.
+  leak[4] = 1;  // Make sure the allocated memory is used.
+}
+
+#if defined(ADDRESS_SANITIZER) && defined(OS_IOS)
+// Because iOS doesn't support death tests, each of the following tests will
+// crash the whole program under ASan.
+#define MAYBE_AccessesToNewMemory DISABLED_AccessesToNewMemory
+#define MAYBE_AccessesToMallocMemory DISABLED_AccessesToMallocMemory
+#define MAYBE_ArrayDeletedWithoutBraces DISABLED_ArrayDeletedWithoutBraces
+#define MAYBE_SingleElementDeletedWithBraces \
+    DISABLED_SingleElementDeletedWithBraces
+#else
+#define MAYBE_AccessesToNewMemory AccessesToNewMemory
+#define MAYBE_AccessesToMallocMemory AccessesToMallocMemory
+#define MAYBE_ArrayDeletedWithoutBraces ArrayDeletedWithoutBraces
+#define MAYBE_SingleElementDeletedWithBraces SingleElementDeletedWithBraces
+#endif
+TEST(ToolsSanityTest, MAYBE_AccessesToNewMemory) {
+  char *foo = new char[10];
+  MakeSomeErrors(foo, 10);
+  delete [] foo;
+  // Use after delete.
+  HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
+}
+
+TEST(ToolsSanityTest, MAYBE_AccessesToMallocMemory) {
+  char *foo = reinterpret_cast<char*>(malloc(10));
+  MakeSomeErrors(foo, 10);
+  free(foo);
+  // Use after free.
+  HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
+}
+
+TEST(ToolsSanityTest, MAYBE_ArrayDeletedWithoutBraces) {
+#if !defined(ADDRESS_SANITIZER)
+  // This test may corrupt memory if not run under Valgrind or compiled with
+  // AddressSanitizer.
+  if (!RunningOnValgrind())
+    return;
+#endif
+
+  // Without the |volatile|, clang optimizes away the next two lines.
+  int* volatile foo = new int[10];
+  delete foo;
+}
+
+TEST(ToolsSanityTest, MAYBE_SingleElementDeletedWithBraces) {
+#if !defined(ADDRESS_SANITIZER)
+  // This test may corrupt memory if not run under Valgrind or compiled with
+  // AddressSanitizer.
+  if (!RunningOnValgrind())
+    return;
+#endif
+
+  // Without the |volatile|, clang optimizes away the next two lines.
+  int* volatile foo = new int;
+  (void) foo;
+  delete [] foo;
+}
+
+#if defined(ADDRESS_SANITIZER)
+TEST(ToolsSanityTest, DISABLED_AddressSanitizerNullDerefCrashTest) {
+  // Intentionally crash to make sure AddressSanitizer is running.
+  // This test should not be ran on bots.
+  int* volatile zero = NULL;
+  *zero = 0;
+}
+
+TEST(ToolsSanityTest, DISABLED_AddressSanitizerLocalOOBCrashTest) {
+  // Intentionally crash to make sure AddressSanitizer is instrumenting
+  // the local variables.
+  // This test should not be ran on bots.
+  int array[5];
+  // Work around the OOB warning reported by Clang.
+  int* volatile access = &array[5];
+  *access = 43;
+}
+
+namespace {
+int g_asan_test_global_array[10];
+}  // namespace
+
+TEST(ToolsSanityTest, DISABLED_AddressSanitizerGlobalOOBCrashTest) {
+  // Intentionally crash to make sure AddressSanitizer is instrumenting
+  // the global variables.
+  // This test should not be ran on bots.
+
+  // Work around the OOB warning reported by Clang.
+  int* volatile access = g_asan_test_global_array - 1;
+  *access = 43;
+}
+
+#endif
+
+namespace {
+
+// We use caps here just to ensure that the method name doesn't interfere with
+// the wildcarded suppressions.
+class TOOLS_SANITY_TEST_CONCURRENT_THREAD : public PlatformThread::Delegate {
+ public:
+  explicit TOOLS_SANITY_TEST_CONCURRENT_THREAD(bool *value) : value_(value) {}
+  virtual ~TOOLS_SANITY_TEST_CONCURRENT_THREAD() {}
+  virtual void ThreadMain() OVERRIDE {
+    *value_ = true;
+
+    // Sleep for a few milliseconds so the two threads are more likely to live
+    // simultaneously. Otherwise we may miss the report due to mutex
+    // lock/unlock's inside thread creation code in pure-happens-before mode...
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  }
+ private:
+  bool *value_;
+};
+
+class ReleaseStoreThread : public PlatformThread::Delegate {
+ public:
+  explicit ReleaseStoreThread(base::subtle::Atomic32 *value) : value_(value) {}
+  virtual ~ReleaseStoreThread() {}
+  virtual void ThreadMain() OVERRIDE {
+    base::subtle::Release_Store(value_, kMagicValue);
+
+    // Sleep for a few milliseconds so the two threads are more likely to live
+    // simultaneously. Otherwise we may miss the report due to mutex
+    // lock/unlock's inside thread creation code in pure-happens-before mode...
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  }
+ private:
+  base::subtle::Atomic32 *value_;
+};
+
+class AcquireLoadThread : public PlatformThread::Delegate {
+ public:
+  explicit AcquireLoadThread(base::subtle::Atomic32 *value) : value_(value) {}
+  virtual ~AcquireLoadThread() {}
+  virtual void ThreadMain() OVERRIDE {
+    // Wait for the other thread to make Release_Store
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+    base::subtle::Acquire_Load(value_);
+  }
+ private:
+  base::subtle::Atomic32 *value_;
+};
+
+void RunInParallel(PlatformThread::Delegate *d1, PlatformThread::Delegate *d2) {
+  PlatformThreadHandle a;
+  PlatformThreadHandle b;
+  PlatformThread::Create(0, d1, &a);
+  PlatformThread::Create(0, d2, &b);
+  PlatformThread::Join(a);
+  PlatformThread::Join(b);
+}
+
+}  // namespace
+
+// A data race detector should report an error in this test.
+TEST(ToolsSanityTest, DataRace) {
+  bool shared = false;
+  TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(&shared), thread2(&shared);
+  RunInParallel(&thread1, &thread2);
+  EXPECT_TRUE(shared);
+}
+
+TEST(ToolsSanityTest, AnnotateBenignRace) {
+  bool shared = false;
+  ANNOTATE_BENIGN_RACE(&shared, "Intentional race - make sure doesn't show up");
+  TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(&shared), thread2(&shared);
+  RunInParallel(&thread1, &thread2);
+  EXPECT_TRUE(shared);
+}
+
+TEST(ToolsSanityTest, AtomicsAreIgnored) {
+  base::subtle::Atomic32 shared = 0;
+  ReleaseStoreThread thread1(&shared);
+  AcquireLoadThread thread2(&shared);
+  RunInParallel(&thread1, &thread2);
+  EXPECT_EQ(kMagicValue, shared);
+}
+
+}  // namespace base
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
new file mode 100644
index 0000000..f5dc82d
--- /dev/null
+++ b/base/tracked_objects.cc
@@ -0,0 +1,872 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <math.h>
+#include <stdlib.h>
+
+#include "base/format_macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process_util.h"
+#include "base/profiler/alternate_timer.h"
+#include "base/stringprintf.h"
+#include "base/third_party/valgrind/memcheck.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/port.h"
+
+using base::TimeDelta;
+
+namespace tracked_objects {
+
+namespace {
+// Flag to compile out almost all of the task tracking code.
+const bool kTrackAllTaskObjects = true;
+
+// TODO(jar): Evaluate the perf impact of enabling this.  If the perf impact is
+// negligible, enable by default.
+// Flag to compile out parent-child link recording.
+const bool kTrackParentChildLinks = false;
+
+// When ThreadData is first initialized, should we start in an ACTIVE state to
+// record all of the startup-time tasks, or should we start up DEACTIVATED, so
+// that we only record after parsing the command line flag --enable-tracking.
+// Note that the flag may force either state, so this really controls only the
+// period of time up until that flag is parsed. If there is no flag seen, then
+// this state may prevail for much or all of the process lifetime.
+const ThreadData::Status kInitialStartupState =
+    ThreadData::PROFILING_CHILDREN_ACTIVE;
+
+// Control whether an alternate time source (Now() function) is supported by
+// the ThreadData class.  This compile time flag should be set to true if we
+// want other modules (such as a memory allocator, or a thread-specific CPU time
+// clock) to be able to provide a thread-specific Now() function.  Without this
+// compile-time flag, the code will only support the wall-clock time.  This flag
+// can be flipped to efficiently disable this path (if there is a performance
+// problem with its presence).
+static const bool kAllowAlternateTimeSourceHandling = true;
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+// DeathData tallies durations when a death takes place.
+
+DeathData::DeathData() {
+  Clear();
+}
+
+DeathData::DeathData(int count) {
+  Clear();
+  count_ = count;
+}
+
+// TODO(jar): I need to see if this macro to optimize branching is worth using.
+//
+// This macro has no branching, so it is surely fast, and is equivalent to:
+//             if (assign_it)
+//               target = source;
+// We use a macro rather than a template to force this to inline.
+// Related code for calculating max is discussed on the web.
+#define CONDITIONAL_ASSIGN(assign_it, target, source) \
+    ((target) ^= ((target) ^ (source)) & -static_cast<int32>(assign_it))
+
+void DeathData::RecordDeath(const int32 queue_duration,
+                            const int32 run_duration,
+                            int32 random_number) {
+  ++count_;
+  queue_duration_sum_ += queue_duration;
+  run_duration_sum_ += run_duration;
+
+  if (queue_duration_max_ < queue_duration)
+    queue_duration_max_ = queue_duration;
+  if (run_duration_max_ < run_duration)
+    run_duration_max_ = run_duration;
+
+  // Take a uniformly distributed sample over all durations ever supplied.
+  // The probability that we (instead) use this new sample is 1/count_.  This
+  // results in a completely uniform selection of the sample (at least when we
+  // don't clamp count_... but that should be inconsequentially likely).
+  // We ignore the fact that we correlated our selection of a sample to the run
+  // and queue times (i.e., we used them to generate random_number).
+  if (count_ <= 0) {  // Handle wrapping of count_, such as in bug 138961.
+    CHECK_GE(count_ - 1, 0);  // Detect memory corruption.
+    // We'll just clamp at INT_MAX, but we should note this in the UI as such.
+    count_ = INT_MAX;
+  }
+  if (0 == (random_number % count_)) {
+    queue_duration_sample_ = queue_duration;
+    run_duration_sample_ = run_duration;
+  }
+}
+
+int DeathData::count() const { return count_; }
+
+int32 DeathData::run_duration_sum() const { return run_duration_sum_; }
+
+int32 DeathData::run_duration_max() const { return run_duration_max_; }
+
+int32 DeathData::run_duration_sample() const {
+  return run_duration_sample_;
+}
+
+int32 DeathData::queue_duration_sum() const {
+  return queue_duration_sum_;
+}
+
+int32 DeathData::queue_duration_max() const {
+  return queue_duration_max_;
+}
+
+int32 DeathData::queue_duration_sample() const {
+  return queue_duration_sample_;
+}
+
+void DeathData::ResetMax() {
+  run_duration_max_ = 0;
+  queue_duration_max_ = 0;
+}
+
+void DeathData::Clear() {
+  count_ = 0;
+  run_duration_sum_ = 0;
+  run_duration_max_ = 0;
+  run_duration_sample_ = 0;
+  queue_duration_sum_ = 0;
+  queue_duration_max_ = 0;
+  queue_duration_sample_ = 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(
+    const tracked_objects::DeathData& death_data)
+    : count(death_data.count()),
+      run_duration_sum(death_data.run_duration_sum()),
+      run_duration_max(death_data.run_duration_max()),
+      run_duration_sample(death_data.run_duration_sample()),
+      queue_duration_sum(death_data.queue_duration_sum()),
+      queue_duration_max(death_data.queue_duration_max()),
+      queue_duration_sample(death_data.queue_duration_sample()) {
+}
+
+DeathDataSnapshot::~DeathDataSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+BirthOnThread::BirthOnThread(const Location& location,
+                             const ThreadData& current)
+    : location_(location),
+      birth_thread_(&current) {
+}
+
+//------------------------------------------------------------------------------
+BirthOnThreadSnapshot::BirthOnThreadSnapshot() {
+}
+
+BirthOnThreadSnapshot::BirthOnThreadSnapshot(
+    const tracked_objects::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_; }
+
+void Births::ForgetBirth() { --birth_count_; }
+
+void Births::Clear() { birth_count_ = 0; }
+
+//------------------------------------------------------------------------------
+// ThreadData maintains the central data for all births and deaths on a single
+// thread.
+
+// TODO(jar): We should pull all these static vars together, into a struct, and
+// optimize layout so that we benefit from locality of reference during accesses
+// to them.
+
+// static
+NowFunction* ThreadData::now_function_ = NULL;
+
+// A TLS slot which points to the ThreadData instance for the current thread. We
+// do a fake initialization here (zeroing out data), and then the real in-place
+// construction happens when we call tls_index_.Initialize().
+// static
+base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER;
+
+// static
+int ThreadData::worker_thread_data_creation_count_ = 0;
+
+// static
+int ThreadData::cleanup_count_ = 0;
+
+// static
+int ThreadData::incarnation_counter_ = 0;
+
+// static
+ThreadData* ThreadData::all_thread_data_list_head_ = NULL;
+
+// static
+ThreadData* ThreadData::first_retired_worker_ = NULL;
+
+// static
+base::LazyInstance<base::Lock>::Leaky
+    ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER;
+
+// static
+ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
+
+ThreadData::ThreadData(const std::string& suggested_name)
+    : next_(NULL),
+      next_retired_worker_(NULL),
+      worker_thread_number_(0),
+      incarnation_count_for_pool_(-1) {
+  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)  {
+  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_));
+  random_number_ += static_cast<int32>(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 (!Initialize())  // Always initialize if needed.
+    return;
+  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.
+  if (!kTrackAllTaskObjects)
+    return;  // Not compiled in.
+  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(bool reset_max, ProcessDataSnapshot* process_data) {
+  // Add births that have run to completion to |collected_data|.
+  // |birth_counts| tracks the total number of births recorded at each location
+  // for which we have not seen a death count.
+  BirthCountMap birth_counts;
+  ThreadData::SnapshotAllExecutedTasks(reset_max, process_data, &birth_counts);
+
+  // Add births that are still active -- i.e. objects that have tallied a birth,
+  // but have not yet tallied a matching death, and hence must be either
+  // running, queued up, or being held in limbo for future posting.
+  for (BirthCountMap::const_iterator it = birth_counts.begin();
+       it != birth_counts.end(); ++it) {
+    if (it->second > 0) {
+      process_data->tasks.push_back(
+          TaskSnapshot(*it->first, DeathData(it->second), "Still_Alive"));
+    }
+  }
+}
+
+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;
+  }
+
+  if (kTrackParentChildLinks && status_ > PROFILING_ACTIVE &&
+      !parent_stack_.empty()) {
+    const Births* parent = parent_stack_.top();
+    ParentChildPair pair(parent, child);
+    if (parent_child_set_.find(pair) == parent_child_set_.end()) {
+      // Lock since the map may get relocated now, and other threads sometimes
+      // snapshot it (but they lock before copying it).
+      base::AutoLock lock(map_lock_);
+      parent_child_set_.insert(pair);
+    }
+  }
+
+  return child;
+}
+
+void ThreadData::TallyADeath(const Births& birth,
+                             int32 queue_duration,
+                             int32 run_duration) {
+  // Stir in some randomness, plus add constant in case durations are zero.
+  const int32 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<int32>(&birth - reinterpret_cast<Births*>(0));
+
+  // We don't have queue durations without OS timer. OS timer is automatically
+  // used for task-post-timing, so the use of an alternate timer implies all
+  // queue times are invalid.
+  if (kAllowAlternateTimeSourceHandling && now_function_)
+    queue_duration = 0;
+
+  DeathMap::iterator it = death_map_.find(&birth);
+  DeathData* death_data;
+  if (it != death_map_.end()) {
+    death_data = &it->second;
+  } else {
+    base::AutoLock lock(map_lock_);  // Lock as the map may get relocated now.
+    death_data = &death_map_[&birth];
+  }  // Release lock ASAP.
+  death_data->RecordDeath(queue_duration, run_duration, random_number_);
+
+  if (!kTrackParentChildLinks)
+    return;
+  if (!parent_stack_.empty()) {  // We might get turned off.
+    DCHECK_EQ(parent_stack_.top(), &birth);
+    parent_stack_.pop();
+  }
+}
+
+// static
+Births* ThreadData::TallyABirthIfActive(const Location& location) {
+  if (!kTrackAllTaskObjects)
+    return NULL;  // Not compiled in.
+
+  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 TrackedTime& start_of_run,
+    const TrackedTime& end_of_run) {
+  if (!kTrackAllTaskObjects)
+    return;  // Not compiled in.
+
+  // Even if we have been DEACTIVATED, we will process any pending births so
+  // that our data structures (which counted the outstanding births) remain
+  // consistent.
+  const Births* birth = completed_task.birth_tally;
+  if (!birth)
+    return;
+  ThreadData* current_thread_data = Get();
+  if (!current_thread_data)
+    return;
+
+  // 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 queueing 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 queueing delay.
+  TrackedTime effective_post_time = completed_task.delayed_run_time.is_null()
+      ? tracked_objects::TrackedTime(completed_task.time_posted)
+      : tracked_objects::TrackedTime(completed_task.delayed_run_time);
+
+  // 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.
+  int32 queue_duration = 0;
+  int32 run_duration = 0;
+  if (!start_of_run.is_null()) {
+    queue_duration = (start_of_run - effective_post_time).InMilliseconds();
+    if (!end_of_run.is_null())
+      run_duration = (end_of_run - start_of_run).InMilliseconds();
+  }
+  current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
+}
+
+// static
+void ThreadData::TallyRunOnWorkerThreadIfTracking(
+    const Births* birth,
+    const TrackedTime& time_posted,
+    const TrackedTime& start_of_run,
+    const TrackedTime& end_of_run) {
+  if (!kTrackAllTaskObjects)
+    return;  // Not compiled in.
+
+  // Even if we have been DEACTIVATED, we will process any pending births so
+  // that our data structures (which counted the outstanding births) remain
+  // consistent.
+  if (!birth)
+    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 TallyBirth and TallyDeath).  The good news is
+  // that the locks on TallyDeath 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 = Get();
+  if (!current_thread_data)
+    return;
+
+  int32 queue_duration = 0;
+  int32 run_duration = 0;
+  if (!start_of_run.is_null()) {
+    queue_duration = (start_of_run - time_posted).InMilliseconds();
+    if (!end_of_run.is_null())
+      run_duration = (end_of_run - start_of_run).InMilliseconds();
+  }
+  current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
+}
+
+// static
+void ThreadData::TallyRunInAScopedRegionIfTracking(
+    const Births* birth,
+    const TrackedTime& start_of_run,
+    const TrackedTime& end_of_run) {
+  if (!kTrackAllTaskObjects)
+    return;  // Not compiled in.
+
+  // Even if we have been DEACTIVATED, we will process any pending births so
+  // that our data structures (which counted the outstanding births) remain
+  // consistent.
+  if (!birth)
+    return;
+
+  ThreadData* current_thread_data = Get();
+  if (!current_thread_data)
+    return;
+
+  int32 queue_duration = 0;
+  int32 run_duration = 0;
+  if (!start_of_run.is_null() && !end_of_run.is_null())
+    run_duration = (end_of_run - start_of_run).InMilliseconds();
+  current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
+}
+
+// static
+void ThreadData::SnapshotAllExecutedTasks(bool reset_max,
+                                          ProcessDataSnapshot* process_data,
+                                          BirthCountMap* birth_counts) {
+  if (!kTrackAllTaskObjects)
+    return;  // Not compiled in.
+
+  // Get an unchanging copy of a ThreadData list.
+  ThreadData* my_list = ThreadData::first();
+
+  // Gather data serially.
+  // This hackish approach *can* get some slighly corrupt tallies, as we are
+  // grabbing values without the protection of a lock, but it has the advantage
+  // of working even with threads that don't have message loops.  If a user
+  // sees any strangeness, they can always just run their stats gathering a
+  // second time.
+  for (ThreadData* thread_data = my_list;
+       thread_data;
+       thread_data = thread_data->next()) {
+    thread_data->SnapshotExecutedTasks(reset_max, process_data, birth_counts);
+  }
+}
+
+void ThreadData::SnapshotExecutedTasks(bool reset_max,
+                                       ProcessDataSnapshot* process_data,
+                                       BirthCountMap* birth_counts) {
+  // Get copy of data, so that the data will not change during the iterations
+  // and processing.
+  ThreadData::BirthMap birth_map;
+  ThreadData::DeathMap death_map;
+  ThreadData::ParentChildSet parent_child_set;
+  SnapshotMaps(reset_max, &birth_map, &death_map, &parent_child_set);
+
+  for (ThreadData::DeathMap::const_iterator it = death_map.begin();
+       it != death_map.end(); ++it) {
+    process_data->tasks.push_back(
+        TaskSnapshot(*it->first, it->second, thread_name()));
+    (*birth_counts)[it->first] -= it->first->birth_count();
+  }
+
+  for (ThreadData::BirthMap::const_iterator it = birth_map.begin();
+       it != birth_map.end(); ++it) {
+    (*birth_counts)[it->second] += it->second->birth_count();
+  }
+
+  if (!kTrackParentChildLinks)
+    return;
+
+  for (ThreadData::ParentChildSet::const_iterator it = parent_child_set.begin();
+       it != parent_child_set.end(); ++it) {
+    process_data->descendants.push_back(ParentChildPairSnapshot(*it));
+  }
+}
+
+// This may be called from another thread.
+void ThreadData::SnapshotMaps(bool reset_max,
+                              BirthMap* birth_map,
+                              DeathMap* death_map,
+                              ParentChildSet* parent_child_set) {
+  base::AutoLock lock(map_lock_);
+  for (BirthMap::const_iterator it = birth_map_.begin();
+       it != birth_map_.end(); ++it)
+    (*birth_map)[it->first] = it->second;
+  for (DeathMap::iterator it = death_map_.begin();
+       it != death_map_.end(); ++it) {
+    (*death_map)[it->first] = it->second;
+    if (reset_max)
+      it->second.ResetMax();
+  }
+
+  if (!kTrackParentChildLinks)
+    return;
+
+  for (ParentChildSet::iterator it = parent_child_set_.begin();
+       it != parent_child_set_.end(); ++it)
+    parent_child_set->insert(*it);
+}
+
+// static
+void ThreadData::ResetAllThreadData() {
+  ThreadData* my_list = first();
+
+  for (ThreadData* thread_data = my_list;
+       thread_data;
+       thread_data = thread_data->next())
+    thread_data->Reset();
+}
+
+void ThreadData::Reset() {
+  base::AutoLock lock(map_lock_);
+  for (DeathMap::iterator it = death_map_.begin();
+       it != death_map_.end(); ++it)
+    it->second.Clear();
+  for (BirthMap::iterator it = birth_map_.begin();
+       it != birth_map_.end(); ++it)
+    it->second->Clear();
+}
+
+static void OptionallyInitializeAlternateTimer() {
+  NowFunction* alternate_time_source = GetAlternateTimeSource();
+  if (alternate_time_source)
+    ThreadData::SetAlternateTimeSource(alternate_time_source);
+}
+
+bool ThreadData::Initialize() {
+  if (!kTrackAllTaskObjects)
+    return false;  // Not compiled in.
+  if (status_ >= DEACTIVATED)
+    return true;  // Someone else did the initialization.
+  // Due to racy lazy initialization in tests, we'll need to recheck status_
+  // after we acquire the lock.
+
+  // Ensure that we don't double initialize tls.  We are called when single
+  // threaded in the product, but some tests may be racy and lazy about our
+  // initialization.
+  base::AutoLock lock(*list_lock_.Pointer());
+  if (status_ >= DEACTIVATED)
+    return true;  // Someone raced in here and beat us.
+
+  // Put an alternate timer in place if the environment calls for it, such as
+  // for tracking TCMalloc allocations.  This insertion is idempotent, so we
+  // don't mind if there is a race, and we'd prefer not to be in a lock while
+  // doing this work.
+  if (kAllowAlternateTimeSourceHandling)
+    OptionallyInitializeAlternateTimer();
+
+  // Perform the "real" TLS initialization now, and leave it intact through
+  // process termination.
+  if (!tls_index_.initialized()) {  // Testing may have initialized this.
+    DCHECK_EQ(status_, UNINITIALIZED);
+    tls_index_.Initialize(&ThreadData::OnThreadTermination);
+    if (!tls_index_.initialized())
+      return false;
+  } else {
+    // TLS was initialzed for us earlier.
+    DCHECK_EQ(status_, DORMANT_DURING_TESTS);
+  }
+
+  // Incarnation counter is only significant to testing, as it otherwise will
+  // never again change in this process.
+  ++incarnation_counter_;
+
+  // The lock is not critical for setting status_, but it doesn't hurt. It also
+  // ensures that if we have a racy initialization, that we'll bail as soon as
+  // we get the lock earlier in this method.
+  status_ = kInitialStartupState;
+  if (!kTrackParentChildLinks &&
+      kInitialStartupState == PROFILING_CHILDREN_ACTIVE)
+    status_ = PROFILING_ACTIVE;
+  DCHECK(status_ != UNINITIALIZED);
+  return true;
+}
+
+// static
+bool ThreadData::InitializeAndSetTrackingStatus(Status status) {
+  DCHECK_GE(status, DEACTIVATED);
+  DCHECK_LE(status, PROFILING_CHILDREN_ACTIVE);
+
+  if (!Initialize())  // No-op if already initialized.
+    return false;  // Not compiled in.
+
+  if (!kTrackParentChildLinks && status > DEACTIVATED)
+    status = PROFILING_ACTIVE;
+  status_ = status;
+  return true;
+}
+
+// static
+ThreadData::Status ThreadData::status() {
+  return status_;
+}
+
+// static
+bool ThreadData::TrackingStatus() {
+  return status_ > DEACTIVATED;
+}
+
+// static
+bool ThreadData::TrackingParentChildStatus() {
+  return status_ >= PROFILING_CHILDREN_ACTIVE;
+}
+
+// static
+TrackedTime ThreadData::NowForStartOfRun(const Births* parent) {
+  if (kTrackParentChildLinks && parent && status_ > PROFILING_ACTIVE) {
+    ThreadData* current_thread_data = Get();
+    if (current_thread_data)
+      current_thread_data->parent_stack_.push(parent);
+  }
+  return Now();
+}
+
+// static
+TrackedTime ThreadData::NowForEndOfRun() {
+  return Now();
+}
+
+// static
+void ThreadData::SetAlternateTimeSource(NowFunction* now_function) {
+  DCHECK(now_function);
+  if (kAllowAlternateTimeSourceHandling)
+    now_function_ = now_function;
+}
+
+// static
+TrackedTime ThreadData::Now() {
+  if (kAllowAlternateTimeSourceHandling && now_function_)
+    return TrackedTime::FromMilliseconds((*now_function_)());
+  if (kTrackAllTaskObjects && 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.
+  // 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.
+  return;  // TODO(jar): until this is working on XP, don't run the real test.
+  CHECK_GT(cleanup_count_, major_threads_shutdown_count);
+}
+
+// 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.
+  if (!InitializeAndSetTrackingStatus(DEACTIVATED))
+    return;
+  ThreadData* thread_data_list;
+  {
+    base::AutoLock lock(*list_lock_.Pointer());
+    thread_data_list = all_thread_data_list_head_;
+    all_thread_data_list_head_ = NULL;
+    ++incarnation_counter_;
+    // To be clean, break apart the retired worker list (though we leak them).
+    while (first_retired_worker_) {
+      ThreadData* worker = first_retired_worker_;
+      CHECK_GT(worker->worker_thread_number_, 0);
+      first_retired_worker_ = worker->next_retired_worker_;
+      worker->next_retired_worker_ = NULL;
+    }
+  }
+
+  // Put most global static back in pristine shape.
+  worker_thread_data_creation_count_ = 0;
+  cleanup_count_ = 0;
+  tls_index_.Set(NULL);
+  status_ = DORMANT_DURING_TESTS;  // Almost UNINITIALIZED.
+
+  // To avoid any chance of racing in unit tests, which is the only place we
+  // call this function, we may sometimes leak all the data structures we
+  // recovered, as they may still be in use on threads from prior tests!
+  if (leak)
+    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.
+  }
+}
+
+//------------------------------------------------------------------------------
+TaskSnapshot::TaskSnapshot() {
+}
+
+TaskSnapshot::TaskSnapshot(const BirthOnThread& birth,
+                           const DeathData& death_data,
+                           const std::string& death_thread_name)
+    : birth(birth),
+      death_data(death_data),
+      death_thread_name(death_thread_name) {
+}
+
+TaskSnapshot::~TaskSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+// ParentChildPairSnapshot
+
+ParentChildPairSnapshot::ParentChildPairSnapshot() {
+}
+
+ParentChildPairSnapshot::ParentChildPairSnapshot(
+    const ThreadData::ParentChildPair& parent_child)
+    : parent(*parent_child.first),
+      child(*parent_child.second) {
+}
+
+ParentChildPairSnapshot::~ParentChildPairSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+// ProcessDataSnapshot
+
+ProcessDataSnapshot::ProcessDataSnapshot()
+#if !defined(OS_NACL)
+    : process_id(base::GetCurrentProcId()) {
+#else
+    : process_id(0) {
+#endif
+}
+
+ProcessDataSnapshot::~ProcessDataSnapshot() {
+}
+
+}  // namespace tracked_objects
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
new file mode 100644
index 0000000..a4e971d
--- /dev/null
+++ b/base/tracked_objects.h
@@ -0,0 +1,717 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACKED_OBJECTS_H_
+#define BASE_TRACKED_OBJECTS_H_
+
+#include <map>
+#include <set>
+#include <stack>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/profiler/alternate_timer.h"
+#include "base/profiler/tracked_time.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/tracking_info.h"
+
+// 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 lifecycle 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 lifecycle 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
+// primarilly 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).
+//
+// The ProcessDataSnapshot struct is a serialized representation of the list
+// of ThreadData objects for a process.  It holds a set of TaskSnapshots
+// and tracks parent/child relationships for the executed tasks.  The statistics
+// in a snapshot are gathered asynhcronously relative to their ongoing updates.
+// 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 constrast, pointer data that
+// is accessed during snapshotting is completely invariant, and hence is
+// perfectly acquired (i.e., no potential corruption, and no risk of a bad
+// memory reference).
+//
+// TODO(jar): We can implement a Snapshot system that *tries* to grab the
+// snapshots on the source threads *when* they have MessageLoops available
+// (worker threads don't have message loops generally, and hence gathering from
+// them will continue to be asynchronous).  We had an implementation of this in
+// the past, but the difficulty is dealing with message loops being terminated.
+// We can *try* to spam the available threads via some message loop proxy to
+// achieve this feat, and it *might* be valuable when we are colecting data for
+// upload via UMA (where correctness of data may be more significant than for a
+// single screen of about:profiler).
+//
+// TODO(jar): We should support (optionally) the recording of parent-child
+// relationships for tasks.  This should be done by detecting what tasks are
+// Born during the running of a parent task.  The resulting data can be used by
+// a smarter profiler to aggregate the cost of a series of child tasks into
+// the ancestor task.  It can also be used to illuminate what child or parent is
+// related to each task.
+//
+// TODO(jar): We need to store DataCollections, and provide facilities for
+// taking the difference between two gathered DataCollections.  For now, we're
+// just adding a hack that Reset()s to zero all counts and stats.  This is also
+// done in a slighly 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();
+
+  // When a birthplace is changed (updated), we need to decrement the counter
+  // for the old instance.
+  void ForgetBirth();
+
+  // Hack to quickly reset all counts to zero.
+  void Clear();
+
+ private:
+  // The number of births on this thread for our location_.
+  int birth_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(Births);
+};
+
+//------------------------------------------------------------------------------
+// Basic info summarizing multiple destructions of a tracked object with a
+// single birthplace (fixed Location).  Used both on specific threads, and also
+// in snapshots when integrating assembled data.
+
+class BASE_EXPORT DeathData {
+ public:
+  // Default initializer.
+  DeathData();
+
+  // When deaths have not yet taken place, and we gather data from all the
+  // threads, we create DeathData stats that tally the number of births without
+  // a corresponding death.
+  explicit DeathData(int count);
+
+  // Update stats for a task destruction (death) that had a Run() time of
+  // |duration|, and has had a queueing delay of |queue_duration|.
+  void RecordDeath(const int32 queue_duration,
+                   const int32 run_duration,
+                   int random_number);
+
+  // Metrics accessors, used only for serialization and in tests.
+  int count() const;
+  int32 run_duration_sum() const;
+  int32 run_duration_max() const;
+  int32 run_duration_sample() const;
+  int32 queue_duration_sum() const;
+  int32 queue_duration_max() const;
+  int32 queue_duration_sample() const;
+
+  // Reset the max values to zero.
+  void ResetMax();
+
+  // Reset all tallies to zero. This is used as a hack on realtime data.
+  void Clear();
+
+ private:
+  // Members are ordered from most regularly read and updated, to least
+  // frequently used.  This might help a bit with cache lines.
+  // Number of runs seen (divisor for calculating averages).
+  int count_;
+  // Basic tallies, used to compute averages.
+  int32 run_duration_sum_;
+  int32 queue_duration_sum_;
+  // Max values, used by local visualization routines.  These are often read,
+  // but rarely updated.
+  int32 run_duration_max_;
+  int32 queue_duration_max_;
+  // Samples, used by crowd sourcing gatherers.  These are almost never read,
+  // and rarely updated.
+  int32 run_duration_sample_;
+  int32 queue_duration_sample_;
+};
+
+//------------------------------------------------------------------------------
+// A "snapshotted" representation of the DeathData class.
+
+struct BASE_EXPORT DeathDataSnapshot {
+  DeathDataSnapshot();
+  explicit DeathDataSnapshot(const DeathData& death_data);
+  ~DeathDataSnapshot();
+
+  int count;
+  int32 run_duration_sum;
+  int32 run_duration_max;
+  int32 run_duration_sample;
+  int32 queue_duration_sum;
+  int32 queue_duration_max;
+  int32 queue_duration_sample;
+};
+
+//------------------------------------------------------------------------------
+// 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 BirthOnThread& birth,
+               const DeathData& death_data,
+               const std::string& death_thread_name);
+  ~TaskSnapshot();
+
+  BirthOnThreadSnapshot birth;
+  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 ProcessDataSnapshot;
+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 profling.
+    PROFILING_ACTIVE,           // Recording profiles (no parent-child links).
+    PROFILING_CHILDREN_ACTIVE,  // Fully active, recording parent-child links.
+  };
+
+  typedef std::map<Location, Births*> BirthMap;
+  typedef std::map<const Births*, DeathData> DeathMap;
+  typedef std::pair<const Births*, const Births*> ParentChildPair;
+  typedef std::set<ParentChildPair> ParentChildSet;
+  typedef std::stack<const Births*> ParentStack;
+
+  // Initialize the current thread context with a new instance of ThreadData.
+  // This is used by all threads that have names, and should be explicitly
+  // 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| with all the recursive results in our process.
+  // During the scavenging, if |reset_max| is true, then the DeathData instances
+  // max-values are reset to zero during this scan.
+  static void Snapshot(bool reset_max, ProcessDataSnapshot* process_data);
+
+  // 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 TrackedTime& start_of_run,
+      const TrackedTime& end_of_run);
+
+  // 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* birth,
+      const TrackedTime& time_posted,
+      const TrackedTime& start_of_run,
+      const TrackedTime& end_of_run);
+
+  // Record the end of execution in region, generally corresponding to a scope
+  // being exited.
+  static void TallyRunInAScopedRegionIfTracking(
+      const Births* birth,
+      const TrackedTime& start_of_run,
+      const TrackedTime& end_of_run);
+
+  const std::string& thread_name() const { return thread_name_; }
+
+  // Hack: asynchronously clear all birth counts and death tallies data values
+  // in all ThreadData instances.  The numerical (zeroing) part is done without
+  // use of a locks or atomics exchanges, and may (for int64 values) produce
+  // bogus counts VERY rarely.
+  static void ResetAllThreadData();
+
+  // Initializes all statics if needed (this initialization call should be made
+  // while we are single threaded). Returns false if unable to initialize.
+  static bool Initialize();
+
+  // Sets internal status_.
+  // If |status| is false, then status_ is set to DEACTIVATED.
+  // If |status| is true, then status_ is set to, PROFILING_ACTIVE, or
+  // PROFILING_CHILDREN_ACTIVE.
+  // If tracking is not compiled in, this function will return false.
+  // If parent-child tracking is not compiled in, then an attempt to set the
+  // status to PROFILING_CHILDREN_ACTIVE will only result in a status of
+  // PROFILING_ACTIVE (i.e., it can't be set to a higher level than what is
+  // compiled into the binary, and parent-child tracking at the
+  // PROFILING_CHILDREN_ACTIVE level might not be compiled in).
+  static bool 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();
+
+  // For testing only, indicate if the status of parent-child tracking is turned
+  // on.  This is currently a compiled option, atop TrackingStatus().
+  static bool TrackingParentChildStatus();
+
+  // Special versions of Now() for getting times at start and end of a tracked
+  // run.  They are super fast when tracking is disabled, and have some internal
+  // side effects when we are tracking, so that we can deduce the amount of time
+  // accumulated outside of execution of tracked runs.
+  // The task that will be tracked is passed in as |parent| so that parent-child
+  // relationships can be (optionally) calculated.
+  static TrackedTime NowForStartOfRun(const Births* parent);
+  static TrackedTime NowForEndOfRun();
+
+  // Provide a time function that does nothing (runs fast) when we don't have
+  // the profiler enabled.  It will generally be optimized away when it is
+  // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of
+  // the code).
+  static TrackedTime Now();
+
+  // Use the function |now| to provide current times, instead of calling the
+  // TrackedTime::Now() function.  Since this alternate function is being used,
+  // the other time arguments (used for calculating queueing delay) will be
+  // ignored.
+  static void SetAlternateTimeSource(NowFunction* now);
+
+  // This function can be called at process termination to validate that thread
+  // cleanup routines have been called for at least some number of named
+  // threads.
+  static void EnsureCleanupWasCalled(int major_threads_shutdown_count);
+
+ private:
+  // 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);
+  FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, ParentChildTest);
+
+  typedef std::map<const BirthOnThread*, int> BirthCountMap;
+
+  // 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& birth, int32 queue_duration, int32 duration);
+
+  // Snapshot (under a lock) the profiled data for the tasks in each ThreadData
+  // instance.  Also updates the |birth_counts| tally for each task to keep
+  // track of the number of living instances of the task.  If |reset_max| is
+  // true, then the max values in each DeathData instance are reset during the
+  // scan.
+  static void SnapshotAllExecutedTasks(bool reset_max,
+                                       ProcessDataSnapshot* process_data,
+                                       BirthCountMap* birth_counts);
+
+  // Snapshots (under a lock) the profiled data for the tasks for this thread
+  // and writes all of the executed tasks' data -- i.e. the data for the tasks
+  // with with entries in the death_map_ -- into |process_data|.  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.  If
+  // |reset_max| is true, then the max values in each DeathData instance are
+  // reset during the scan.
+  void SnapshotExecutedTasks(bool reset_max,
+                             ProcessDataSnapshot* process_data,
+                             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 reallocaed while they are copied. If |reset_max| is
+  // true, then, just after we copy the DeathMap, we will set the max values to
+  // zero in the active DeathMap (not the snapshot).
+  void SnapshotMaps(bool reset_max,
+                    BirthMap* birth_map,
+                    DeathMap* death_map,
+                    ParentChildSet* parent_child_set);
+
+  // Using our lock to protect the iteration, Clear all birth and death data.
+  void Reset();
+
+  // 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_;
+
+  // 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 llist.  When a new worker
+  // thread is created, we first try to re-use a ThreadData instance from the
+  // list, and if none are available, construct a new one.
+  // This is only accessed while list_lock_ is held.
+  static ThreadData* first_retired_worker_;
+
+  // Link to the most recently created instance (starts a null terminated list).
+  // The list is traversed by about:profiler when it needs to snapshot data.
+  // This is only accessed while list_lock_ is held.
+  static ThreadData* all_thread_data_list_head_;
+
+  // The next available worker thread number.  This should only be accessed when
+  // the list_lock_ is held.
+  static int worker_thread_data_creation_count_;
+
+  // The number of times TLS has called us back to cleanup a ThreadData
+  // instance. This is only accessed while list_lock_ is held.
+  static int cleanup_count_;
+
+  // Incarnation sequence number, indicating how many times (during unittests)
+  // we've either transitioned out of UNINITIALIZED, or into that state.  This
+  // value is only accessed while the list_lock_ is held.
+  static int incarnation_counter_;
+
+  // Protection for access to all_thread_data_list_head_, and to
+  // unregistered_thread_data_pool_.  This lock is leaked at shutdown.
+  // The lock is very infrequently used, so we can afford to just make a lazy
+  // instance and be safe.
+  static base::LazyInstance<base::Lock>::Leaky list_lock_;
+
+  // We set status_ to SHUTDOWN when we shut down the tracking service.
+  static Status status_;
+
+  // Link to next instance (null terminated list). Used to globally track all
+  // registered instances (corresponds to all registered threads where we keep
+  // data).
+  ThreadData* next_;
+
+  // Pointer to another ThreadData instance for a Worker-Thread that has been
+  // retired (its thread was terminated).  This value is non-NULL only for a
+  // retired ThreadData associated with a Worker-Thread.
+  ThreadData* next_retired_worker_;
+
+  // The name of the thread that is being recorded.  If this thread has no
+  // message_loop, then this is a worker thread, with a sequence number postfix.
+  std::string thread_name_;
+
+  // Indicate if this is a worker thread, and the ThreadData contexts should be
+  // stored in the unregistered_thread_data_pool_ when not in use.
+  // Value is zero when it is not a worker thread.  Value is a positive integer
+  // corresponding to the created thread name if it is a worker thread.
+  int worker_thread_number_;
+
+  // A map used on each thread to keep track of Births on this thread.
+  // This map should only be accessed on the thread it was constructed on.
+  // When a snapshot is needed, this structure can be locked in place for the
+  // duration of the snapshotting activity.
+  BirthMap birth_map_;
+
+  // Similar to birth_map_, this records informations about death of tracked
+  // instances (i.e., when a tracked instance was destroyed on this thread).
+  // It is locked before changing, and hence other threads may access it by
+  // locking before reading it.
+  DeathMap death_map_;
+
+  // A set of parents that created children tasks on this thread. Each pair
+  // corresponds to potentially non-local Births (location and thread), and a
+  // local Births (that took place on this thread).
+  ParentChildSet parent_child_set_;
+
+  // Lock to protect *some* access to BirthMap and DeathMap.  The maps are
+  // regularly read and written on this thread, but may only be read from other
+  // threads.  To support this, we acquire this lock if we are writing from this
+  // 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_;
+
+  // The stack of parents that are currently being profiled. This includes only
+  // tasks that have started a timer recently via NowForStartOfRun(), but not
+  // yet concluded with a NowForEndOfRun().  Usually this stack is one deep, but
+  // if a scoped region is profiled, or <sigh> a task runs a nested-message
+  // loop, then the stack can grow larger.  Note that we don't try to deduct
+  // time in nested porfiles, as our current timer is based on wall-clock time,
+  // and not CPU time (and we're hopeful that nested timing won't be a
+  // significant additional cost).
+  ParentStack parent_stack_;
+
+  // A random number that we used to select decide which sample to keep as a
+  // representative sample in each DeathData instance.  We can't start off with
+  // much randomness (because we can't call RandInt() on all our threads), so
+  // we stir in more and more as we go.
+  int32 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_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadData);
+};
+
+//------------------------------------------------------------------------------
+// A snapshotted representation of a (parent, child) task pair, for tracking
+// hierarchical profiles.
+
+struct BASE_EXPORT ParentChildPairSnapshot {
+ public:
+  ParentChildPairSnapshot();
+  explicit ParentChildPairSnapshot(
+      const ThreadData::ParentChildPair& parent_child);
+  ~ParentChildPairSnapshot();
+
+  BirthOnThreadSnapshot parent;
+  BirthOnThreadSnapshot child;
+};
+
+//------------------------------------------------------------------------------
+// A snapshotted representation of the list of ThreadData objects for a process.
+
+struct BASE_EXPORT ProcessDataSnapshot {
+ public:
+  ProcessDataSnapshot();
+  ~ProcessDataSnapshot();
+
+  std::vector<TaskSnapshot> tasks;
+  std::vector<ParentChildPairSnapshot> descendants;
+  int process_id;
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_TRACKED_OBJECTS_H_
diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc
new file mode 100644
index 0000000..1e64508
--- /dev/null
+++ b/base/tracked_objects_unittest.cc
@@ -0,0 +1,581 @@
+// Copyright (c) 2012 The Chromium 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 "base/memory/scoped_ptr.h"
+#include "base/process_util.h"
+#include "base/time.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);
+  }
+
+  virtual ~TrackedObjectsTest() {
+    // 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);
+  }
+
+  // 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.tasks.size());
+
+    EXPECT_EQ(kFile, process_data.tasks[0].birth.location.file_name);
+    EXPECT_EQ(function_name,
+              process_data.tasks[0].birth.location.function_name);
+    EXPECT_EQ(kLineNumber, process_data.tasks[0].birth.location.line_number);
+
+    EXPECT_EQ(birth_thread, process_data.tasks[0].birth.thread_name);
+
+    EXPECT_EQ(count, process_data.tasks[0].death_data.count);
+    EXPECT_EQ(count * run_ms,
+              process_data.tasks[0].death_data.run_duration_sum);
+    EXPECT_EQ(run_ms, process_data.tasks[0].death_data.run_duration_max);
+    EXPECT_EQ(run_ms, process_data.tasks[0].death_data.run_duration_sample);
+    EXPECT_EQ(count * queue_ms,
+              process_data.tasks[0].death_data.queue_duration_sum);
+    EXPECT_EQ(queue_ms, process_data.tasks[0].death_data.queue_duration_max);
+    EXPECT_EQ(queue_ms, process_data.tasks[0].death_data.queue_duration_sample);
+
+    EXPECT_EQ(death_thread, process_data.tasks[0].death_thread_name);
+
+    EXPECT_EQ(0u, process_data.descendants.size());
+
+    EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+  }
+};
+
+TEST_F(TrackedObjectsTest, MinimalStartupShutdown) {
+  // Minimal test doesn't even create any tasks.
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+
+  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::DeathMap death_map;
+  ThreadData::ParentChildSet parent_child_set;
+  data->SnapshotMaps(false, &birth_map, &death_map, &parent_child_set);
+  EXPECT_EQ(0u, birth_map.size());
+  EXPECT_EQ(0u, death_map.size());
+  EXPECT_EQ(0u, parent_child_set.size());
+
+  // Clean up with no leaking.
+  Reset();
+
+  // Do it again, just to be sure we reset state completely.
+  EXPECT_TRUE(ThreadData::InitializeAndSetTrackingStatus(
+      ThreadData::PROFILING_CHILDREN_ACTIVE));
+  EXPECT_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();
+  death_map.clear();
+  parent_child_set.clear();
+  data->SnapshotMaps(false, &birth_map, &death_map, &parent_child_set);
+  EXPECT_EQ(0u, birth_map.size());
+  EXPECT_EQ(0u, death_map.size());
+  EXPECT_EQ(0u, parent_child_set.size());
+}
+
+TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+
+  // Instigate tracking on a single tracked object, on our thread.
+  const char kFunction[] = "TinyStartupShutdown";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  Births* first_birth = ThreadData::TallyABirthIfActive(location);
+
+  ThreadData* data = ThreadData::first();
+  ASSERT_TRUE(data);
+  EXPECT_FALSE(data->next());
+  EXPECT_EQ(data, ThreadData::Get());
+  ThreadData::BirthMap birth_map;
+  ThreadData::DeathMap death_map;
+  ThreadData::ParentChildSet parent_child_set;
+  data->SnapshotMaps(false, &birth_map, &death_map, &parent_child_set);
+  EXPECT_EQ(1u, birth_map.size());                         // 1 birth location.
+  EXPECT_EQ(1, birth_map.begin()->second->birth_count());  // 1 birth.
+  EXPECT_EQ(0u, death_map.size());                         // No deaths.
+  EXPECT_EQ(0u, parent_child_set.size());                  // No children.
+
+
+  // Now instigate another birth, while we are timing the run of the first
+  // execution.
+  ThreadData::NowForStartOfRun(first_birth);
+  // Create a child (using the same birth location).
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TimeTicks kBogusBirthTime;
+  base::TrackingInfo pending_task(location, kBogusBirthTime);
+  TrackedTime start_time(pending_task.time_posted);
+  // Finally conclude the outer run.
+  TrackedTime end_time = ThreadData::NowForEndOfRun();
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, start_time,
+                                              end_time);
+
+  birth_map.clear();
+  death_map.clear();
+  parent_child_set.clear();
+  data->SnapshotMaps(false, &birth_map, &death_map, &parent_child_set);
+  EXPECT_EQ(1u, birth_map.size());                         // 1 birth location.
+  EXPECT_EQ(2, birth_map.begin()->second->birth_count());  // 2 births.
+  EXPECT_EQ(1u, death_map.size());                         // 1 location.
+  EXPECT_EQ(1, death_map.begin()->second.count());         // 1 death.
+  if (ThreadData::TrackingParentChildStatus()) {
+    EXPECT_EQ(1u, parent_child_set.size());                  // 1 child.
+    EXPECT_EQ(parent_child_set.begin()->first,
+              parent_child_set.begin()->second);
+  } else {
+    EXPECT_EQ(0u, parent_child_set.size());                  // no stats.
+  }
+
+  // The births were at the same location as the one known death.
+  EXPECT_EQ(birth_map.begin()->second, death_map.begin()->first);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(false, &process_data);
+
+  const int32 time_elapsed = (end_time - start_time).InMilliseconds();
+  ASSERT_EQ(1u, process_data.tasks.size());
+  EXPECT_EQ(kFile, process_data.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction, process_data.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber, process_data.tasks[0].birth.location.line_number);
+  EXPECT_EQ(kWorkerThreadName, process_data.tasks[0].birth.thread_name);
+  EXPECT_EQ(1, process_data.tasks[0].death_data.count);
+  EXPECT_EQ(time_elapsed, process_data.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(time_elapsed, process_data.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(time_elapsed, process_data.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(0, process_data.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(0, process_data.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(0, process_data.tasks[0].death_data.queue_duration_sample);
+  EXPECT_EQ(kWorkerThreadName, process_data.tasks[0].death_thread_name);
+
+  if (ThreadData::TrackingParentChildStatus()) {
+    ASSERT_EQ(1u, process_data.descendants.size());
+    EXPECT_EQ(kFile, process_data.descendants[0].parent.location.file_name);
+    EXPECT_EQ(kFunction,
+              process_data.descendants[0].parent.location.function_name);
+    EXPECT_EQ(kLineNumber,
+              process_data.descendants[0].parent.location.line_number);
+    EXPECT_EQ(kWorkerThreadName,
+              process_data.descendants[0].parent.thread_name);
+    EXPECT_EQ(kFile, process_data.descendants[0].child.location.file_name);
+    EXPECT_EQ(kFunction,
+              process_data.descendants[0].child.location.function_name);
+    EXPECT_EQ(kLineNumber,
+              process_data.descendants[0].child.location.line_number);
+    EXPECT_EQ(kWorkerThreadName, process_data.descendants[0].child.thread_name);
+  } else {
+    EXPECT_EQ(0u, process_data.descendants.size());
+  }
+}
+
+TEST_F(TrackedObjectsTest, DeathDataTest) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+
+  scoped_ptr<DeathData> data(new DeathData());
+  ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+  EXPECT_EQ(data->run_duration_sum(), 0);
+  EXPECT_EQ(data->run_duration_sample(), 0);
+  EXPECT_EQ(data->queue_duration_sum(), 0);
+  EXPECT_EQ(data->queue_duration_sample(), 0);
+  EXPECT_EQ(data->count(), 0);
+
+  int32 run_ms = 42;
+  int32 queue_ms = 8;
+
+  const int kUnrandomInt = 0;  // Fake random int that ensure we sample data.
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+  EXPECT_EQ(data->run_duration_sum(), run_ms);
+  EXPECT_EQ(data->run_duration_sample(), run_ms);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms);
+  EXPECT_EQ(data->count(), 1);
+
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+  EXPECT_EQ(data->run_duration_sum(), run_ms + 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_sample(), queue_ms);
+  EXPECT_EQ(data->count(), 2);
+
+  DeathDataSnapshot snapshot(*data);
+  EXPECT_EQ(2, snapshot.count);
+  EXPECT_EQ(2 * run_ms, snapshot.run_duration_sum);
+  EXPECT_EQ(run_ms, snapshot.run_duration_max);
+  EXPECT_EQ(run_ms, snapshot.run_duration_sample);
+  EXPECT_EQ(2 * queue_ms, snapshot.queue_duration_sum);
+  EXPECT_EQ(queue_ms, snapshot.queue_duration_max);
+  EXPECT_EQ(queue_ms, snapshot.queue_duration_sample);
+}
+
+TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotWorkerThread) {
+  // Start in the deactivated state.
+  if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED))
+    return;
+
+  const char kFunction[] = "DeactivatedBirthOnlyToSnapshotWorkerThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, std::string());
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(false, &process_data);
+  EXPECT_EQ(0u, process_data.tasks.size());
+  EXPECT_EQ(0u, process_data.descendants.size());
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotMainThread) {
+  // Start in the deactivated state.
+  if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED))
+    return;
+
+  const char kFunction[] = "DeactivatedBirthOnlyToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(false, &process_data);
+  EXPECT_EQ(0u, process_data.tasks.size());
+  EXPECT_EQ(0u, process_data.descendants.size());
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotWorkerThread) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+
+  const char kFunction[] = "BirthOnlyToSnapshotWorkerThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, std::string());
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(false, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kWorkerThreadName,
+                          kStillAlive, 1, 0, 0);
+}
+
+TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotMainThread) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+
+  const char kFunction[] = "BirthOnlyToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(false, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName, kStillAlive,
+                          1, 0, 0);
+}
+
+TEST_F(TrackedObjectsTest, LifeCycleToSnapshotMainThread) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+
+  const char kFunction[] = "LifeCycleToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const base::TimeTicks kTimePosted = base::TimeTicks() +
+      base::TimeDelta::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 TrackedTime kStartOfRun = TrackedTime() +
+      Duration::FromMilliseconds(5);
+  const TrackedTime kEndOfRun = TrackedTime() + Duration::FromMilliseconds(7);
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task,
+      kStartOfRun, kEndOfRun);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(false, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 1, 2, 4);
+}
+
+// We will deactivate tracking after the birth, and before the death, and
+// demonstrate that the lifecycle is completely tallied. This ensures that
+// our tallied births are matched by tallied deaths (except for when the
+// task is still running, or is queued).
+TEST_F(TrackedObjectsTest, LifeCycleMidDeactivatedToSnapshotMainThread) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+
+  const char kFunction[] = "LifeCycleMidDeactivatedToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const base::TimeTicks kTimePosted = base::TimeTicks() +
+      base::TimeDelta::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.
+  EXPECT_TRUE(ThreadData::InitializeAndSetTrackingStatus(
+      ThreadData::DEACTIVATED));
+
+  const TrackedTime kStartOfRun = TrackedTime() +
+      Duration::FromMilliseconds(5);
+  const TrackedTime kEndOfRun = TrackedTime() + Duration::FromMilliseconds(7);
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task,
+      kStartOfRun, kEndOfRun);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(false, &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.
+  if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED))
+    return;
+
+  const char kFunction[] = "LifeCyclePreDeactivatedToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const base::TimeTicks kTimePosted = base::TimeTicks() +
+      base::TimeDelta::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 TrackedTime kStartOfRun = TrackedTime() +
+      Duration::FromMilliseconds(5);
+  const TrackedTime kEndOfRun = TrackedTime() + Duration::FromMilliseconds(7);
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task,
+      kStartOfRun, kEndOfRun);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(false, &process_data);
+  EXPECT_EQ(0u, process_data.tasks.size());
+  EXPECT_EQ(0u, process_data.descendants.size());
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, LifeCycleToSnapshotWorkerThread) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+
+  const char kFunction[] = "LifeCycleToSnapshotWorkerThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  // Do not delete |birth|.  We don't own it.
+  Births* birth = ThreadData::TallyABirthIfActive(location);
+  EXPECT_NE(reinterpret_cast<Births*>(NULL), birth);
+
+  const TrackedTime kTimePosted = TrackedTime() + Duration::FromMilliseconds(1);
+  const TrackedTime kStartOfRun = TrackedTime() +
+      Duration::FromMilliseconds(5);
+  const TrackedTime kEndOfRun = TrackedTime() + Duration::FromMilliseconds(7);
+  ThreadData::TallyRunOnWorkerThreadIfTracking(birth, kTimePosted,
+      kStartOfRun, kEndOfRun);
+
+  // Call for the ToSnapshot, but tell it to not reset the maxes after scanning.
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(false, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kWorkerThreadName,
+                          kWorkerThreadName, 1, 2, 4);
+
+  // Call for the ToSnapshot, but tell it to reset the maxes after scanning.
+  // We'll still get the same values, but the data will be reset (which we'll
+  // see in a moment).
+  ProcessDataSnapshot process_data_pre_reset;
+  ThreadData::Snapshot(true, &process_data_pre_reset);
+  ExpectSimpleProcessData(process_data, kFunction, kWorkerThreadName,
+                          kWorkerThreadName, 1, 2, 4);
+
+  // Call for the ToSnapshot, and now we'll see the result of the last
+  // translation, as the max will have been pushed back to zero.
+  ProcessDataSnapshot process_data_post_reset;
+  ThreadData::Snapshot(true, &process_data_post_reset);
+  ASSERT_EQ(1u, process_data_post_reset.tasks.size());
+  EXPECT_EQ(kFile, process_data_post_reset.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_post_reset.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_post_reset.tasks[0].birth.location.line_number);
+  EXPECT_EQ(kWorkerThreadName,
+            process_data_post_reset.tasks[0].birth.thread_name);
+  EXPECT_EQ(1, process_data_post_reset.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_post_reset.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(0, process_data_post_reset.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_post_reset.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_post_reset.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(0, process_data_post_reset.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4,
+            process_data_post_reset.tasks[0].death_data.queue_duration_sample);
+  EXPECT_EQ(kWorkerThreadName,
+            process_data_post_reset.tasks[0].death_thread_name);
+  EXPECT_EQ(0u, process_data_post_reset.descendants.size());
+  EXPECT_EQ(base::GetCurrentProcId(), process_data_post_reset.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoLives) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+
+  const char kFunction[] = "TwoLives";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const base::TimeTicks kTimePosted = base::TimeTicks() +
+      base::TimeDelta::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 TrackedTime kStartOfRun = TrackedTime() +
+      Duration::FromMilliseconds(5);
+  const TrackedTime kEndOfRun = TrackedTime() + Duration::FromMilliseconds(7);
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task,
+      kStartOfRun, kEndOfRun);
+
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task2(location, kDelayedStartTime);
+  pending_task2.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task2,
+      kStartOfRun, kEndOfRun);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(false, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 2, 2, 4);
+}
+
+TEST_F(TrackedObjectsTest, DifferentLives) {
+  if (!ThreadData::InitializeAndSetTrackingStatus(
+          ThreadData::PROFILING_CHILDREN_ACTIVE))
+    return;
+
+  // Use a well named thread.
+  ThreadData::InitializeThreadContext(kMainThreadName);
+  const char kFunction[] = "DifferentLives";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+
+  const base::TimeTicks kTimePosted = base::TimeTicks() +
+      base::TimeDelta::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 TrackedTime kStartOfRun = TrackedTime() +
+      Duration::FromMilliseconds(5);
+  const TrackedTime kEndOfRun = TrackedTime() + Duration::FromMilliseconds(7);
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task,
+      kStartOfRun, kEndOfRun);
+
+  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(false, &process_data);
+  ASSERT_EQ(2u, process_data.tasks.size());
+  EXPECT_EQ(kFile, process_data.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction, process_data.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber, process_data.tasks[0].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data.tasks[0].birth.thread_name);
+  EXPECT_EQ(1, process_data.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data.tasks[0].death_data.queue_duration_sample);
+  EXPECT_EQ(kMainThreadName, process_data.tasks[0].death_thread_name);
+  EXPECT_EQ(kFile, process_data.tasks[1].birth.location.file_name);
+  EXPECT_EQ(kFunction, process_data.tasks[1].birth.location.function_name);
+  EXPECT_EQ(kSecondFakeLineNumber,
+            process_data.tasks[1].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data.tasks[1].birth.thread_name);
+  EXPECT_EQ(1, process_data.tasks[1].death_data.count);
+  EXPECT_EQ(0, process_data.tasks[1].death_data.run_duration_sum);
+  EXPECT_EQ(0, process_data.tasks[1].death_data.run_duration_max);
+  EXPECT_EQ(0, process_data.tasks[1].death_data.run_duration_sample);
+  EXPECT_EQ(0, process_data.tasks[1].death_data.queue_duration_sum);
+  EXPECT_EQ(0, process_data.tasks[1].death_data.queue_duration_max);
+  EXPECT_EQ(0, process_data.tasks[1].death_data.queue_duration_sample);
+  EXPECT_EQ(kStillAlive, process_data.tasks[1].death_thread_name);
+  EXPECT_EQ(0u, process_data.descendants.size());
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+}  // namespace tracked_objects
diff --git a/base/tracking_info.cc b/base/tracking_info.cc
new file mode 100644
index 0000000..0b091f8
--- /dev/null
+++ b/base/tracking_info.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/tracking_info.h"
+
+#include <stddef.h>
+#include "base/tracked_objects.h"
+
+namespace base {
+
+TrackingInfo::TrackingInfo()
+    : birth_tally(NULL) {
+}
+
+TrackingInfo::TrackingInfo(
+    const tracked_objects::Location& posted_from,
+    base::TimeTicks delayed_run_time)
+    : birth_tally(
+          tracked_objects::ThreadData::TallyABirthIfActive(posted_from)),
+      time_posted(TimeTicks::Now()),
+      delayed_run_time(delayed_run_time) {
+}
+
+TrackingInfo::~TrackingInfo() {}
+
+}  // namespace base
+
diff --git a/base/tracking_info.h b/base/tracking_info.h
new file mode 100644
index 0000000..738bdee
--- /dev/null
+++ b/base/tracking_info.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.
+
+// 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/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();
+
+  // Record of location and thread that the task came from.
+  tracked_objects::Births* birth_tally;
+
+  // Time when the related task was posted.
+  base::TimeTicks time_posted;
+
+  // The time when the task should be run.
+  base::TimeTicks delayed_run_time;
+};
+
+}  // namespace base
+
+#endif  // BASE_TRACKING_INFO_H_
diff --git a/base/tuple.h b/base/tuple.h
new file mode 100644
index 0000000..04809d9
--- /dev/null
+++ b/base/tuple.h
@@ -0,0 +1,1051 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A Tuple is a generic templatized container, similar in concept to std::pair.
+// There are classes Tuple0 to Tuple6, cooresponding to the number of elements
+// it contains.  The convenient MakeTuple() function takes 0 to 6 arguments,
+// and will construct and return the appropriate Tuple object.  The functions
+// DispatchToMethod and DispatchToFunction take a function pointer or instance
+// and method pointer, and unpack a tuple into arguments to the call.
+//
+// Tuple elements are copied by value, and stored in the tuple.  See the unit
+// tests for more details of how/when the values are copied.
+//
+// Example usage:
+//   // These two methods of creating a Tuple are identical.
+//   Tuple2<int, const char*> tuple_a(1, "wee");
+//   Tuple2<int, const char*> tuple_b = MakeTuple(1, "wee");
+//
+//   void SomeFunc(int a, const char* b) { }
+//   DispatchToFunction(&SomeFunc, tuple_a);  // SomeFunc(1, "wee")
+//   DispatchToFunction(
+//       &SomeFunc, MakeTuple(10, "foo"));    // SomeFunc(10, "foo")
+//
+//   struct { void SomeMeth(int a, int b, int c) { } } foo;
+//   DispatchToMethod(&foo, &Foo::SomeMeth, MakeTuple(1, 2, 3));
+//   // foo->SomeMeth(1, 2, 3);
+
+#ifndef BASE_TUPLE_H__
+#define BASE_TUPLE_H__
+
+// Traits ----------------------------------------------------------------------
+//
+// A simple traits class for tuple arguments.
+//
+// ValueType: the bare, nonref version of a type (same as the type for nonrefs).
+// RefType: the ref version of a type (same as the type for refs).
+// ParamType: what type to pass to functions (refs should not be constified).
+
+template <class P>
+struct TupleTraits {
+  typedef P ValueType;
+  typedef P& RefType;
+  typedef const P& ParamType;
+};
+
+template <class P>
+struct TupleTraits<P&> {
+  typedef P ValueType;
+  typedef P& RefType;
+  typedef P& ParamType;
+};
+
+template <class P>
+struct TupleTypes { };
+
+// Tuple -----------------------------------------------------------------------
+//
+// This set of classes is useful for bundling 0 or more heterogeneous data types
+// into a single variable.  The advantage of this is that it greatly simplifies
+// function objects that need to take an arbitrary number of parameters; see
+// RunnableMethod and IPC::MessageWithTuple.
+//
+// Tuple0 is supplied to act as a 'void' type.  It can be used, for example,
+// when dispatching to a function that accepts no arguments (see the
+// Dispatchers below).
+// Tuple1<A> is rarely useful.  One such use is when A is non-const ref that you
+// want filled by the dispatchee, and the tuple is merely a container for that
+// output (a "tier").  See MakeRefTuple and its usages.
+
+struct Tuple0 {
+  typedef Tuple0 ValueTuple;
+  typedef Tuple0 RefTuple;
+  typedef Tuple0 ParamTuple;
+};
+
+template <class A>
+struct Tuple1 {
+ public:
+  typedef A TypeA;
+
+  Tuple1() {}
+  explicit Tuple1(typename TupleTraits<A>::ParamType a) : a(a) {}
+
+  A a;
+};
+
+template <class A, class B>
+struct Tuple2 {
+ public:
+  typedef A TypeA;
+  typedef B TypeB;
+
+  Tuple2() {}
+  Tuple2(typename TupleTraits<A>::ParamType a,
+         typename TupleTraits<B>::ParamType b)
+      : a(a), b(b) {
+  }
+
+  A a;
+  B b;
+};
+
+template <class A, class B, class C>
+struct Tuple3 {
+ public:
+  typedef A TypeA;
+  typedef B TypeB;
+  typedef C TypeC;
+
+  Tuple3() {}
+  Tuple3(typename TupleTraits<A>::ParamType a,
+         typename TupleTraits<B>::ParamType b,
+         typename TupleTraits<C>::ParamType c)
+      : a(a), b(b), c(c){
+  }
+
+  A a;
+  B b;
+  C c;
+};
+
+template <class A, class B, class C, class D>
+struct Tuple4 {
+ public:
+  typedef A TypeA;
+  typedef B TypeB;
+  typedef C TypeC;
+  typedef D TypeD;
+
+  Tuple4() {}
+  Tuple4(typename TupleTraits<A>::ParamType a,
+         typename TupleTraits<B>::ParamType b,
+         typename TupleTraits<C>::ParamType c,
+         typename TupleTraits<D>::ParamType d)
+      : a(a), b(b), c(c), d(d) {
+  }
+
+  A a;
+  B b;
+  C c;
+  D d;
+};
+
+template <class A, class B, class C, class D, class E>
+struct Tuple5 {
+ public:
+  typedef A TypeA;
+  typedef B TypeB;
+  typedef C TypeC;
+  typedef D TypeD;
+  typedef E TypeE;
+
+  Tuple5() {}
+  Tuple5(typename TupleTraits<A>::ParamType a,
+    typename TupleTraits<B>::ParamType b,
+    typename TupleTraits<C>::ParamType c,
+    typename TupleTraits<D>::ParamType d,
+    typename TupleTraits<E>::ParamType e)
+    : a(a), b(b), c(c), d(d), e(e) {
+  }
+
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+};
+
+template <class A, class B, class C, class D, class E, class F>
+struct Tuple6 {
+ public:
+  typedef A TypeA;
+  typedef B TypeB;
+  typedef C TypeC;
+  typedef D TypeD;
+  typedef E TypeE;
+  typedef F TypeF;
+
+  Tuple6() {}
+  Tuple6(typename TupleTraits<A>::ParamType a,
+    typename TupleTraits<B>::ParamType b,
+    typename TupleTraits<C>::ParamType c,
+    typename TupleTraits<D>::ParamType d,
+    typename TupleTraits<E>::ParamType e,
+    typename TupleTraits<F>::ParamType f)
+    : a(a), b(b), c(c), d(d), e(e), f(f) {
+  }
+
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+  F f;
+};
+
+template <class A, class B, class C, class D, class E, class F, class G>
+struct Tuple7 {
+ public:
+  typedef A TypeA;
+  typedef B TypeB;
+  typedef C TypeC;
+  typedef D TypeD;
+  typedef E TypeE;
+  typedef F TypeF;
+  typedef G TypeG;
+
+  Tuple7() {}
+  Tuple7(typename TupleTraits<A>::ParamType a,
+    typename TupleTraits<B>::ParamType b,
+    typename TupleTraits<C>::ParamType c,
+    typename TupleTraits<D>::ParamType d,
+    typename TupleTraits<E>::ParamType e,
+    typename TupleTraits<F>::ParamType f,
+    typename TupleTraits<G>::ParamType g)
+    : a(a), b(b), c(c), d(d), e(e), f(f), g(g) {
+  }
+
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+  F f;
+  G g;
+};
+
+template <class A, class B, class C, class D, class E, class F, class G,
+          class H>
+struct Tuple8 {
+ public:
+  typedef A TypeA;
+  typedef B TypeB;
+  typedef C TypeC;
+  typedef D TypeD;
+  typedef E TypeE;
+  typedef F TypeF;
+  typedef G TypeG;
+  typedef H TypeH;
+
+  Tuple8() {}
+  Tuple8(typename TupleTraits<A>::ParamType a,
+    typename TupleTraits<B>::ParamType b,
+    typename TupleTraits<C>::ParamType c,
+    typename TupleTraits<D>::ParamType d,
+    typename TupleTraits<E>::ParamType e,
+    typename TupleTraits<F>::ParamType f,
+    typename TupleTraits<G>::ParamType g,
+    typename TupleTraits<H>::ParamType h)
+    : a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) {
+  }
+
+  A a;
+  B b;
+  C c;
+  D d;
+  E e;
+  F f;
+  G g;
+  H h;
+};
+
+// Tuple types ----------------------------------------------------------------
+//
+// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the
+// definitions of class types the tuple takes as parameters.
+
+template <>
+struct TupleTypes< Tuple0 > {
+  typedef Tuple0 ValueTuple;
+  typedef Tuple0 RefTuple;
+  typedef Tuple0 ParamTuple;
+};
+
+template <class A>
+struct TupleTypes< Tuple1<A> > {
+  typedef Tuple1<typename TupleTraits<A>::ValueType> ValueTuple;
+  typedef Tuple1<typename TupleTraits<A>::RefType> RefTuple;
+  typedef Tuple1<typename TupleTraits<A>::ParamType> ParamTuple;
+};
+
+template <class A, class B>
+struct TupleTypes< Tuple2<A, B> > {
+  typedef Tuple2<typename TupleTraits<A>::ValueType,
+                 typename TupleTraits<B>::ValueType> ValueTuple;
+typedef Tuple2<typename TupleTraits<A>::RefType,
+               typename TupleTraits<B>::RefType> RefTuple;
+  typedef Tuple2<typename TupleTraits<A>::ParamType,
+                 typename TupleTraits<B>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C>
+struct TupleTypes< Tuple3<A, B, C> > {
+  typedef Tuple3<typename TupleTraits<A>::ValueType,
+                 typename TupleTraits<B>::ValueType,
+                 typename TupleTraits<C>::ValueType> ValueTuple;
+typedef Tuple3<typename TupleTraits<A>::RefType,
+               typename TupleTraits<B>::RefType,
+               typename TupleTraits<C>::RefType> RefTuple;
+  typedef Tuple3<typename TupleTraits<A>::ParamType,
+                 typename TupleTraits<B>::ParamType,
+                 typename TupleTraits<C>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D>
+struct TupleTypes< Tuple4<A, B, C, D> > {
+  typedef Tuple4<typename TupleTraits<A>::ValueType,
+                 typename TupleTraits<B>::ValueType,
+                 typename TupleTraits<C>::ValueType,
+                 typename TupleTraits<D>::ValueType> ValueTuple;
+typedef Tuple4<typename TupleTraits<A>::RefType,
+               typename TupleTraits<B>::RefType,
+               typename TupleTraits<C>::RefType,
+               typename TupleTraits<D>::RefType> RefTuple;
+  typedef Tuple4<typename TupleTraits<A>::ParamType,
+                 typename TupleTraits<B>::ParamType,
+                 typename TupleTraits<C>::ParamType,
+                 typename TupleTraits<D>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E>
+struct TupleTypes< Tuple5<A, B, C, D, E> > {
+  typedef Tuple5<typename TupleTraits<A>::ValueType,
+                 typename TupleTraits<B>::ValueType,
+                 typename TupleTraits<C>::ValueType,
+                 typename TupleTraits<D>::ValueType,
+                 typename TupleTraits<E>::ValueType> ValueTuple;
+typedef Tuple5<typename TupleTraits<A>::RefType,
+               typename TupleTraits<B>::RefType,
+               typename TupleTraits<C>::RefType,
+               typename TupleTraits<D>::RefType,
+               typename TupleTraits<E>::RefType> RefTuple;
+  typedef Tuple5<typename TupleTraits<A>::ParamType,
+                 typename TupleTraits<B>::ParamType,
+                 typename TupleTraits<C>::ParamType,
+                 typename TupleTraits<D>::ParamType,
+                 typename TupleTraits<E>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E, class F>
+struct TupleTypes< Tuple6<A, B, C, D, E, F> > {
+  typedef Tuple6<typename TupleTraits<A>::ValueType,
+                 typename TupleTraits<B>::ValueType,
+                 typename TupleTraits<C>::ValueType,
+                 typename TupleTraits<D>::ValueType,
+                 typename TupleTraits<E>::ValueType,
+                 typename TupleTraits<F>::ValueType> ValueTuple;
+typedef Tuple6<typename TupleTraits<A>::RefType,
+               typename TupleTraits<B>::RefType,
+               typename TupleTraits<C>::RefType,
+               typename TupleTraits<D>::RefType,
+               typename TupleTraits<E>::RefType,
+               typename TupleTraits<F>::RefType> RefTuple;
+  typedef Tuple6<typename TupleTraits<A>::ParamType,
+                 typename TupleTraits<B>::ParamType,
+                 typename TupleTraits<C>::ParamType,
+                 typename TupleTraits<D>::ParamType,
+                 typename TupleTraits<E>::ParamType,
+                 typename TupleTraits<F>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E, class F, class G>
+struct TupleTypes< Tuple7<A, B, C, D, E, F, G> > {
+  typedef Tuple7<typename TupleTraits<A>::ValueType,
+                 typename TupleTraits<B>::ValueType,
+                 typename TupleTraits<C>::ValueType,
+                 typename TupleTraits<D>::ValueType,
+                 typename TupleTraits<E>::ValueType,
+                 typename TupleTraits<F>::ValueType,
+                 typename TupleTraits<G>::ValueType> ValueTuple;
+typedef Tuple7<typename TupleTraits<A>::RefType,
+               typename TupleTraits<B>::RefType,
+               typename TupleTraits<C>::RefType,
+               typename TupleTraits<D>::RefType,
+               typename TupleTraits<E>::RefType,
+               typename TupleTraits<F>::RefType,
+               typename TupleTraits<G>::RefType> RefTuple;
+  typedef Tuple7<typename TupleTraits<A>::ParamType,
+                 typename TupleTraits<B>::ParamType,
+                 typename TupleTraits<C>::ParamType,
+                 typename TupleTraits<D>::ParamType,
+                 typename TupleTraits<E>::ParamType,
+                 typename TupleTraits<F>::ParamType,
+                 typename TupleTraits<G>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E, class F, class G,
+          class H>
+struct TupleTypes< Tuple8<A, B, C, D, E, F, G, H> > {
+  typedef Tuple8<typename TupleTraits<A>::ValueType,
+                 typename TupleTraits<B>::ValueType,
+                 typename TupleTraits<C>::ValueType,
+                 typename TupleTraits<D>::ValueType,
+                 typename TupleTraits<E>::ValueType,
+                 typename TupleTraits<F>::ValueType,
+                 typename TupleTraits<G>::ValueType,
+                 typename TupleTraits<H>::ValueType> ValueTuple;
+typedef Tuple8<typename TupleTraits<A>::RefType,
+               typename TupleTraits<B>::RefType,
+               typename TupleTraits<C>::RefType,
+               typename TupleTraits<D>::RefType,
+               typename TupleTraits<E>::RefType,
+               typename TupleTraits<F>::RefType,
+               typename TupleTraits<G>::RefType,
+               typename TupleTraits<H>::RefType> RefTuple;
+  typedef Tuple8<typename TupleTraits<A>::ParamType,
+                 typename TupleTraits<B>::ParamType,
+                 typename TupleTraits<C>::ParamType,
+                 typename TupleTraits<D>::ParamType,
+                 typename TupleTraits<E>::ParamType,
+                 typename TupleTraits<F>::ParamType,
+                 typename TupleTraits<G>::ParamType,
+                 typename TupleTraits<H>::ParamType> ParamTuple;
+};
+
+// Tuple creators -------------------------------------------------------------
+//
+// Helper functions for constructing tuples while inferring the template
+// argument types.
+
+inline Tuple0 MakeTuple() {
+  return Tuple0();
+}
+
+template <class A>
+inline Tuple1<A> MakeTuple(const A& a) {
+  return Tuple1<A>(a);
+}
+
+template <class A, class B>
+inline Tuple2<A, B> MakeTuple(const A& a, const B& b) {
+  return Tuple2<A, B>(a, b);
+}
+
+template <class A, class B, class C>
+inline Tuple3<A, B, C> MakeTuple(const A& a, const B& b, const C& c) {
+  return Tuple3<A, B, C>(a, b, c);
+}
+
+template <class A, class B, class C, class D>
+inline Tuple4<A, B, C, D> MakeTuple(const A& a, const B& b, const C& c,
+                                    const D& d) {
+  return Tuple4<A, B, C, D>(a, b, c, d);
+}
+
+template <class A, class B, class C, class D, class E>
+inline Tuple5<A, B, C, D, E> MakeTuple(const A& a, const B& b, const C& c,
+                                       const D& d, const E& e) {
+  return Tuple5<A, B, C, D, E>(a, b, c, d, e);
+}
+
+template <class A, class B, class C, class D, class E, class F>
+inline Tuple6<A, B, C, D, E, F> MakeTuple(const A& a, const B& b, const C& c,
+                                          const D& d, const E& e, const F& f) {
+  return Tuple6<A, B, C, D, E, F>(a, b, c, d, e, f);
+}
+
+template <class A, class B, class C, class D, class E, class F, class G>
+inline Tuple7<A, B, C, D, E, F, G> MakeTuple(const A& a, const B& b, const C& c,
+                                             const D& d, const E& e, const F& f,
+                                             const G& g) {
+  return Tuple7<A, B, C, D, E, F, G>(a, b, c, d, e, f, g);
+}
+
+template <class A, class B, class C, class D, class E, class F, class G,
+          class H>
+inline Tuple8<A, B, C, D, E, F, G, H> MakeTuple(const A& a, const B& b,
+                                                const C& c, const D& d,
+                                                const E& e, const F& f,
+                                                const G& g, const H& h) {
+  return Tuple8<A, B, C, D, E, F, G, H>(a, b, c, d, e, f, g, h);
+}
+
+// The following set of helpers make what Boost refers to as "Tiers" - a tuple
+// of references.
+
+template <class A>
+inline Tuple1<A&> MakeRefTuple(A& a) {
+  return Tuple1<A&>(a);
+}
+
+template <class A, class B>
+inline Tuple2<A&, B&> MakeRefTuple(A& a, B& b) {
+  return Tuple2<A&, B&>(a, b);
+}
+
+template <class A, class B, class C>
+inline Tuple3<A&, B&, C&> MakeRefTuple(A& a, B& b, C& c) {
+  return Tuple3<A&, B&, C&>(a, b, c);
+}
+
+template <class A, class B, class C, class D>
+inline Tuple4<A&, B&, C&, D&> MakeRefTuple(A& a, B& b, C& c, D& d) {
+  return Tuple4<A&, B&, C&, D&>(a, b, c, d);
+}
+
+template <class A, class B, class C, class D, class E>
+inline Tuple5<A&, B&, C&, D&, E&> MakeRefTuple(A& a, B& b, C& c, D& d, E& e) {
+  return Tuple5<A&, B&, C&, D&, E&>(a, b, c, d, e);
+}
+
+template <class A, class B, class C, class D, class E, class F>
+inline Tuple6<A&, B&, C&, D&, E&, F&> MakeRefTuple(A& a, B& b, C& c, D& d, E& e,
+                                                   F& f) {
+  return Tuple6<A&, B&, C&, D&, E&, F&>(a, b, c, d, e, f);
+}
+
+template <class A, class B, class C, class D, class E, class F, class G>
+inline Tuple7<A&, B&, C&, D&, E&, F&, G&> MakeRefTuple(A& a, B& b, C& c, D& d,
+                                                       E& e, F& f, G& g) {
+  return Tuple7<A&, B&, C&, D&, E&, F&, G&>(a, b, c, d, e, f, g);
+}
+
+template <class A, class B, class C, class D, class E, class F, class G,
+          class H>
+inline Tuple8<A&, B&, C&, D&, E&, F&, G&, H&> MakeRefTuple(A& a, B& b, C& c,
+                                                           D& d, E& e, F& f,
+                                                           G& g, H& h) {
+  return Tuple8<A&, B&, C&, D&, E&, F&, G&, H&>(a, b, c, d, e, f, g, h);
+}
+
+// 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 <class ObjT, class Method>
+inline void DispatchToMethod(ObjT* obj, Method method, const Tuple0& arg) {
+  (obj->*method)();
+}
+
+template <class ObjT, class Method, class A>
+inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) {
+  (obj->*method)(arg);
+}
+
+template <class ObjT, class Method, class A>
+inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1<A>& arg) {
+  (obj->*method)(arg.a);
+}
+
+template<class ObjT, class Method, class A, class B>
+inline void DispatchToMethod(ObjT* obj,
+                             Method method,
+                             const Tuple2<A, B>& arg) {
+  (obj->*method)(arg.a, arg.b);
+}
+
+template<class ObjT, class Method, class A, class B, class C>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple3<A, B, C>& arg) {
+  (obj->*method)(arg.a, arg.b, arg.c);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple4<A, B, C, D>& arg) {
+  (obj->*method)(arg.a, arg.b, arg.c, arg.d);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple5<A, B, C, D, E>& arg) {
+  (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E,
+         class F>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple6<A, B, C, D, E, F>& arg) {
+  (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E,
+         class F, class G>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple7<A, B, C, D, E, F, G>& arg) {
+  (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E,
+         class F, class G, class H>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple8<A, B, C, D, E, F, G, H>& arg) {
+  (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g, arg.h);
+}
+
+// Static Dispatchers with no out params.
+
+template <class Function>
+inline void DispatchToFunction(Function function, const Tuple0& arg) {
+  (*function)();
+}
+
+template <class Function, class A>
+inline void DispatchToFunction(Function function, const A& arg) {
+  (*function)(arg);
+}
+
+template <class Function, class A>
+inline void DispatchToFunction(Function function, const Tuple1<A>& arg) {
+  (*function)(arg.a);
+}
+
+template<class Function, class A, class B>
+inline void DispatchToFunction(Function function, const Tuple2<A, B>& arg) {
+  (*function)(arg.a, arg.b);
+}
+
+template<class Function, class A, class B, class C>
+inline void DispatchToFunction(Function function, const Tuple3<A, B, C>& arg) {
+  (*function)(arg.a, arg.b, arg.c);
+}
+
+template<class Function, class A, class B, class C, class D>
+inline void DispatchToFunction(Function function,
+                               const Tuple4<A, B, C, D>& arg) {
+  (*function)(arg.a, arg.b, arg.c, arg.d);
+}
+
+template<class Function, class A, class B, class C, class D, class E>
+inline void DispatchToFunction(Function function,
+                               const Tuple5<A, B, C, D, E>& arg) {
+  (*function)(arg.a, arg.b, arg.c, arg.d, arg.e);
+}
+
+template<class Function, class A, class B, class C, class D, class E, class F>
+inline void DispatchToFunction(Function function,
+                               const Tuple6<A, B, C, D, E, F>& arg) {
+  (*function)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f);
+}
+
+template<class Function, class A, class B, class C, class D, class E, class F,
+         class G>
+inline void DispatchToFunction(Function function,
+                               const Tuple7<A, B, C, D, E, F, G>& arg) {
+  (*function)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g);
+}
+
+template<class Function, class A, class B, class C, class D, class E, class F,
+         class G, class H>
+inline void DispatchToFunction(Function function,
+                               const Tuple8<A, B, C, D, E, F, G, H>& arg) {
+  (*function)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g, arg.h);
+}
+
+// Dispatchers with 0 out param (as a Tuple0).
+
+template <class ObjT, class Method>
+inline void DispatchToMethod(ObjT* obj,
+                             Method method,
+                             const Tuple0& arg, Tuple0*) {
+  (obj->*method)();
+}
+
+template <class ObjT, class Method, class A>
+inline void DispatchToMethod(ObjT* obj, Method method, const A& arg, Tuple0*) {
+  (obj->*method)(arg);
+}
+
+template <class ObjT, class Method, class A>
+inline void DispatchToMethod(ObjT* obj,
+                             Method method,
+                             const Tuple1<A>& arg, Tuple0*) {
+  (obj->*method)(arg.a);
+}
+
+template<class ObjT, class Method, class A, class B>
+inline void DispatchToMethod(ObjT* obj,
+                             Method method,
+                             const Tuple2<A, B>& arg, Tuple0*) {
+  (obj->*method)(arg.a, arg.b);
+}
+
+template<class ObjT, class Method, class A, class B, class C>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple3<A, B, C>& arg, Tuple0*) {
+  (obj->*method)(arg.a, arg.b, arg.c);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple4<A, B, C, D>& arg, Tuple0*) {
+  (obj->*method)(arg.a, arg.b, arg.c, arg.d);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple5<A, B, C, D, E>& arg, Tuple0*) {
+  (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E,
+         class F>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple6<A, B, C, D, E, F>& arg, Tuple0*) {
+  (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f);
+}
+
+// Dispatchers with 1 out param.
+
+template<class ObjT, class Method,
+         class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple0& in,
+                             Tuple1<OutA>* out) {
+  (obj->*method)(&out->a);
+}
+
+template<class ObjT, class Method, class InA,
+         class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const InA& in,
+                             Tuple1<OutA>* out) {
+  (obj->*method)(in, &out->a);
+}
+
+template<class ObjT, class Method, class InA,
+         class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple1<InA>& in,
+                             Tuple1<OutA>* out) {
+  (obj->*method)(in.a, &out->a);
+}
+
+template<class ObjT, class Method, class InA, class InB,
+         class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple2<InA, InB>& in,
+                             Tuple1<OutA>* out) {
+  (obj->*method)(in.a, in.b, &out->a);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC,
+         class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple3<InA, InB, InC>& in,
+                             Tuple1<OutA>* out) {
+  (obj->*method)(in.a, in.b, in.c, &out->a);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+         class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple4<InA, InB, InC, InD>& in,
+                             Tuple1<OutA>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, &out->a);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+         class InE, class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple5<InA, InB, InC, InD, InE>& in,
+                             Tuple1<OutA>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, in.e, &out->a);
+}
+
+template<class ObjT, class Method,
+         class InA, class InB, class InC, class InD, class InE, class InF,
+         class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple6<InA, InB, InC, InD, InE, InF>& in,
+                             Tuple1<OutA>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, &out->a);
+}
+
+// Dispatchers with 2 out params.
+
+template<class ObjT, class Method,
+         class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple0& in,
+                             Tuple2<OutA, OutB>* out) {
+  (obj->*method)(&out->a, &out->b);
+}
+
+template<class ObjT, class Method, class InA,
+         class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const InA& in,
+                             Tuple2<OutA, OutB>* out) {
+  (obj->*method)(in, &out->a, &out->b);
+}
+
+template<class ObjT, class Method, class InA,
+         class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple1<InA>& in,
+                             Tuple2<OutA, OutB>* out) {
+  (obj->*method)(in.a, &out->a, &out->b);
+}
+
+template<class ObjT, class Method, class InA, class InB,
+         class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple2<InA, InB>& in,
+                             Tuple2<OutA, OutB>* out) {
+  (obj->*method)(in.a, in.b, &out->a, &out->b);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC,
+         class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple3<InA, InB, InC>& in,
+                             Tuple2<OutA, OutB>* out) {
+  (obj->*method)(in.a, in.b, in.c, &out->a, &out->b);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+         class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple4<InA, InB, InC, InD>& in,
+                             Tuple2<OutA, OutB>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b);
+}
+
+template<class ObjT, class Method,
+         class InA, class InB, class InC, class InD, class InE,
+         class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple5<InA, InB, InC, InD, InE>& in,
+                             Tuple2<OutA, OutB>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, in.e, &out->a, &out->b);
+}
+
+template<class ObjT, class Method,
+         class InA, class InB, class InC, class InD, class InE, class InF,
+         class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple6<InA, InB, InC, InD, InE, InF>& in,
+                             Tuple2<OutA, OutB>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, &out->a, &out->b);
+}
+
+// Dispatchers with 3 out params.
+
+template<class ObjT, class Method,
+         class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple0& in,
+                             Tuple3<OutA, OutB, OutC>* out) {
+  (obj->*method)(&out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method, class InA,
+         class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const InA& in,
+                             Tuple3<OutA, OutB, OutC>* out) {
+  (obj->*method)(in, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method, class InA,
+         class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple1<InA>& in,
+                             Tuple3<OutA, OutB, OutC>* out) {
+  (obj->*method)(in.a, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method, class InA, class InB,
+         class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple2<InA, InB>& in,
+                             Tuple3<OutA, OutB, OutC>* out) {
+  (obj->*method)(in.a, in.b, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC,
+         class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple3<InA, InB, InC>& in,
+                             Tuple3<OutA, OutB, OutC>* out) {
+  (obj->*method)(in.a, in.b, in.c, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+         class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple4<InA, InB, InC, InD>& in,
+                             Tuple3<OutA, OutB, OutC>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method,
+         class InA, class InB, class InC, class InD, class InE,
+         class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple5<InA, InB, InC, InD, InE>& in,
+                             Tuple3<OutA, OutB, OutC>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, in.e, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method,
+         class InA, class InB, class InC, class InD, class InE, class InF,
+         class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple6<InA, InB, InC, InD, InE, InF>& in,
+                             Tuple3<OutA, OutB, OutC>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, &out->a, &out->b, &out->c);
+}
+
+// Dispatchers with 4 out params.
+
+template<class ObjT, class Method,
+         class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple0& in,
+                             Tuple4<OutA, OutB, OutC, OutD>* out) {
+  (obj->*method)(&out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method, class InA,
+         class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const InA& in,
+                             Tuple4<OutA, OutB, OutC, OutD>* out) {
+  (obj->*method)(in, &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method, class InA,
+         class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple1<InA>& in,
+                             Tuple4<OutA, OutB, OutC, OutD>* out) {
+  (obj->*method)(in.a, &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method, class InA, class InB,
+         class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple2<InA, InB>& in,
+                             Tuple4<OutA, OutB, OutC, OutD>* out) {
+  (obj->*method)(in.a, in.b, &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC,
+         class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple3<InA, InB, InC>& in,
+                             Tuple4<OutA, OutB, OutC, OutD>* out) {
+  (obj->*method)(in.a, in.b, in.c, &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+         class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple4<InA, InB, InC, InD>& in,
+                             Tuple4<OutA, OutB, OutC, OutD>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method,
+         class InA, class InB, class InC, class InD, class InE,
+         class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple5<InA, InB, InC, InD, InE>& in,
+                             Tuple4<OutA, OutB, OutC, OutD>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, in.e,
+                 &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method,
+         class InA, class InB, class InC, class InD, class InE, class InF,
+         class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple6<InA, InB, InC, InD, InE, InF>& in,
+                             Tuple4<OutA, OutB, OutC, OutD>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f,
+                 &out->a, &out->b, &out->c, &out->d);
+}
+
+// Dispatchers with 5 out params.
+
+template<class ObjT, class Method,
+         class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple0& in,
+                             Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+  (obj->*method)(&out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method, class InA,
+         class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const InA& in,
+                             Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+  (obj->*method)(in, &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method, class InA,
+         class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple1<InA>& in,
+                             Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+  (obj->*method)(in.a, &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method, class InA, class InB,
+         class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple2<InA, InB>& in,
+                             Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+  (obj->*method)(in.a, in.b, &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC,
+         class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple3<InA, InB, InC>& in,
+                             Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+  (obj->*method)(in.a, in.b, in.c, &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+         class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple4<InA, InB, InC, InD>& in,
+                             Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b, &out->c, &out->d,
+                 &out->e);
+}
+
+template<class ObjT, class Method,
+         class InA, class InB, class InC, class InD, class InE,
+         class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple5<InA, InB, InC, InD, InE>& in,
+                             Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, in.e,
+                 &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method,
+         class InA, class InB, class InC, class InD, class InE, class InF,
+         class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+                             const Tuple6<InA, InB, InC, InD, InE, InF>& in,
+                             Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+  (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f,
+                 &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+#endif  // BASE_TUPLE_H__
diff --git a/base/tuple_unittest.cc b/base/tuple_unittest.cc
new file mode 100644
index 0000000..402394c
--- /dev/null
+++ b/base/tuple_unittest.cc
@@ -0,0 +1,128 @@
+// 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 {
+
+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) {
+  Tuple0 t0 ALLOW_UNUSED = MakeTuple();
+  Tuple1<int> t1(1);
+  Tuple2<int, const char*> t2 = MakeTuple(1, static_cast<const char*>("wee"));
+  Tuple3<int, int, int> t3(1, 2, 3);
+  Tuple4<int, int, int, int*> t4(1, 2, 3, &t1.a);
+  Tuple5<int, int, int, int, int*> t5(1, 2, 3, 4, &t4.a);
+  Tuple6<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &t4.a);
+
+  EXPECT_EQ(1, t1.a);
+  EXPECT_EQ(1, t2.a);
+  EXPECT_EQ(1, t3.a);
+  EXPECT_EQ(2, t3.b);
+  EXPECT_EQ(3, t3.c);
+  EXPECT_EQ(1, t4.a);
+  EXPECT_EQ(2, t4.b);
+  EXPECT_EQ(3, t4.c);
+  EXPECT_EQ(1, t5.a);
+  EXPECT_EQ(2, t5.b);
+  EXPECT_EQ(3, t5.c);
+  EXPECT_EQ(4, t5.d);
+  EXPECT_EQ(1, t6.a);
+  EXPECT_EQ(2, t6.b);
+  EXPECT_EQ(3, t6.c);
+  EXPECT_EQ(4, t6.d);
+  EXPECT_EQ(5, t6.e);
+
+  EXPECT_EQ(1, t1.a);
+  DispatchToFunction(&DoAdd, t4);
+  EXPECT_EQ(6, t1.a);
+
+  int res = 0;
+  DispatchToFunction(&DoAdd, MakeTuple(9, 8, 7, &res));
+  EXPECT_EQ(24, res);
+
+  Addy addy;
+  EXPECT_EQ(1, t4.a);
+  DispatchToMethod(&addy, &Addy::DoAdd, t5);
+  EXPECT_EQ(10, t4.a);
+
+  Addz addz;
+  EXPECT_EQ(10, t4.a);
+  DispatchToMethod(&addz, &Addz::DoAdd, t6);
+  EXPECT_EQ(15, t4.a);
+}
+
+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.
+  Tuple3<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res);
+  tuple.b = &tuple.a;
+  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);
+}
diff --git a/base/utf_offset_string_conversions.cc b/base/utf_offset_string_conversions.cc
new file mode 100644
index 0000000..8405303
--- /dev/null
+++ b/base/utf_offset_string_conversions.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/utf_offset_string_conversions.h"
+
+#include <algorithm>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/string_piece.h"
+#include "base/utf_string_conversion_utils.h"
+
+using base::PrepareForUTF16Or32Output;
+using base::PrepareForUTF8Output;
+using base::ReadUnicodeCharacter;
+using base::WriteUnicodeCharacter;
+
+// 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 SrcChar, typename DestStdString>
+bool ConvertUnicode(const SrcChar* src,
+                    size_t src_len,
+                    DestStdString* output,
+                    std::vector<size_t>* offsets_for_adjustment) {
+  if (offsets_for_adjustment) {
+    std::for_each(offsets_for_adjustment->begin(),
+                  offsets_for_adjustment->end(),
+                  LimitOffset<DestStdString>(src_len));
+  }
+
+  // ICU requires 32-bit numbers.
+  bool success = true;
+  OffsetAdjuster offset_adjuster(offsets_for_adjustment);
+  int32 src_len32 = static_cast<int32>(src_len);
+  for (int32 i = 0; i < src_len32; i++) {
+    uint32 code_point;
+    size_t original_i = i;
+    size_t chars_written = 0;
+    if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) {
+      chars_written = WriteUnicodeCharacter(code_point, output);
+    } else {
+      chars_written = WriteUnicodeCharacter(0xFFFD, output);
+      success = false;
+    }
+    if (offsets_for_adjustment) {
+      // NOTE: ReadUnicodeCharacter() adjusts |i| to point _at_ the last
+      // character read, not after it (so that incrementing it in the loop
+      // increment will place it at the right location), so we need to account
+      // for that in determining the amount that was read.
+      offset_adjuster.Add(OffsetAdjuster::Adjustment(original_i,
+          i - original_i + 1, chars_written));
+    }
+  }
+  return success;
+}
+
+bool UTF8ToUTF16AndAdjustOffset(const char* src,
+                                size_t src_len,
+                                string16* output,
+                                size_t* offset_for_adjustment) {
+  std::vector<size_t> offsets;
+  if (offset_for_adjustment)
+    offsets.push_back(*offset_for_adjustment);
+  PrepareForUTF16Or32Output(src, src_len, output);
+  bool ret = ConvertUnicode(src, src_len, output, &offsets);
+  if (offset_for_adjustment)
+    *offset_for_adjustment = offsets[0];
+  return ret;
+}
+
+bool UTF8ToUTF16AndAdjustOffsets(const char* src,
+                                 size_t src_len,
+                                 string16* output,
+                                 std::vector<size_t>* offsets_for_adjustment) {
+  PrepareForUTF16Or32Output(src, src_len, output);
+  return ConvertUnicode(src, src_len, output, offsets_for_adjustment);
+}
+
+string16 UTF8ToUTF16AndAdjustOffset(const base::StringPiece& utf8,
+                                        size_t* offset_for_adjustment) {
+  std::vector<size_t> offsets;
+  if (offset_for_adjustment)
+    offsets.push_back(*offset_for_adjustment);
+  string16 result;
+  UTF8ToUTF16AndAdjustOffsets(utf8.data(), utf8.length(), &result,
+                              &offsets);
+  if (offset_for_adjustment)
+    *offset_for_adjustment = offsets[0];
+  return result;
+}
+
+string16 UTF8ToUTF16AndAdjustOffsets(
+    const base::StringPiece& utf8,
+    std::vector<size_t>* offsets_for_adjustment) {
+  string16 result;
+  UTF8ToUTF16AndAdjustOffsets(utf8.data(), utf8.length(), &result,
+                              offsets_for_adjustment);
+  return result;
+}
+
+std::string UTF16ToUTF8AndAdjustOffset(
+    const base::StringPiece16& utf16,
+    size_t* offset_for_adjustment) {
+  std::vector<size_t> offsets;
+  if (offset_for_adjustment)
+    offsets.push_back(*offset_for_adjustment);
+  std::string result = UTF16ToUTF8AndAdjustOffsets(utf16, &offsets);
+  if (offset_for_adjustment)
+    *offset_for_adjustment = offsets[0];
+  return result;
+}
+
+std::string UTF16ToUTF8AndAdjustOffsets(
+    const base::StringPiece16& utf16,
+    std::vector<size_t>* offsets_for_adjustment) {
+  std::string result;
+  PrepareForUTF8Output(utf16.data(), utf16.length(), &result);
+  ConvertUnicode(utf16.data(), utf16.length(), &result, offsets_for_adjustment);
+  return result;
+}
+
+OffsetAdjuster::Adjustment::Adjustment(size_t original_offset,
+                                       size_t original_length,
+                                       size_t output_length)
+    : original_offset(original_offset),
+      original_length(original_length),
+      output_length(output_length) {
+}
+
+OffsetAdjuster::OffsetAdjuster(std::vector<size_t>* offsets_for_adjustment)
+    : offsets_for_adjustment_(offsets_for_adjustment) {
+}
+
+OffsetAdjuster::~OffsetAdjuster() {
+  if (!offsets_for_adjustment_ || adjustments_.empty())
+    return;
+  for (std::vector<size_t>::iterator i(offsets_for_adjustment_->begin());
+       i != offsets_for_adjustment_->end(); ++i)
+    AdjustOffset(i);
+}
+
+void OffsetAdjuster::Add(const Adjustment& adjustment) {
+  adjustments_.push_back(adjustment);
+}
+
+void OffsetAdjuster::AdjustOffset(std::vector<size_t>::iterator offset) {
+  if (*offset == string16::npos)
+    return;
+  size_t adjustment = 0;
+  for (std::vector<Adjustment>::const_iterator i = adjustments_.begin();
+       i != adjustments_.end(); ++i) {
+    if (*offset == i->original_offset && i->output_length == 0) {
+      *offset = string16::npos;
+      return;
+    }
+    if (*offset <= i->original_offset)
+      break;
+    if (*offset < (i->original_offset + i->original_length)) {
+      *offset = string16::npos;
+      return;
+    }
+    adjustment += (i->original_length - i->output_length);
+  }
+  *offset -= adjustment;
+}
diff --git a/base/utf_offset_string_conversions.h b/base/utf_offset_string_conversions.h
new file mode 100644
index 0000000..e9cb558
--- /dev/null
+++ b/base/utf_offset_string_conversions.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_UTF_OFFSET_STRING_CONVERSIONS_H_
+#define BASE_UTF_OFFSET_STRING_CONVERSIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/string16.h"
+#include "base/string_piece.h"
+
+// Like the conversions in utf_string_conversions.h, but also takes one or more
+// offsets (|offset[s]_for_adjustment|) into the source strings, each offset
+// will be adjusted to point at the same logical place in the result strings.
+// If this isn't possible because an offset points past the end of the source
+// strings or into the middle of a multibyte sequence, the offending offset will
+// be set to string16::npos. |offset[s]_for_adjustment| may be NULL.
+BASE_EXPORT bool UTF8ToUTF16AndAdjustOffset(const char* src,
+                                            size_t src_len,
+                                            string16* output,
+                                            size_t* offset_for_adjustment);
+BASE_EXPORT bool UTF8ToUTF16AndAdjustOffsets(
+    const char* src,
+    size_t src_len,
+    string16* output,
+    std::vector<size_t>* offsets_for_adjustment);
+
+BASE_EXPORT string16 UTF8ToUTF16AndAdjustOffset(const base::StringPiece& utf8,
+                                                size_t* offset_for_adjustment);
+BASE_EXPORT string16 UTF8ToUTF16AndAdjustOffsets(
+    const base::StringPiece& utf8,
+    std::vector<size_t>* offsets_for_adjustment);
+
+BASE_EXPORT std::string UTF16ToUTF8AndAdjustOffset(
+    const base::StringPiece16& utf16,
+    size_t* offset_for_adjustment);
+BASE_EXPORT std::string UTF16ToUTF8AndAdjustOffsets(
+    const base::StringPiece16& utf16,
+    std::vector<size_t>* offsets_for_adjustment);
+
+// Limiting function callable by std::for_each which will replace any value
+// which is equal to or greater than |limit| with npos.
+template <typename T>
+struct LimitOffset {
+  explicit LimitOffset(size_t limit)
+    : limit_(limit) {}
+
+  void operator()(size_t& offset) {
+    if (offset >= limit_)
+      offset = T::npos;
+  }
+
+  size_t limit_;
+};
+
+// Stack object which, on destruction, will update a vector of offsets based on
+// any supplied adjustments.  To use, declare one of these, providing the
+// address of the offset vector to adjust.  Then Add() any number of Adjustments
+// (each Adjustment gives the |original_offset| of a substring and the lengths
+// of the substring before and after transforming).  When the OffsetAdjuster
+// goes out of scope, all the offsets in the provided vector will be updated.
+class BASE_EXPORT OffsetAdjuster {
+ public:
+  struct BASE_EXPORT Adjustment {
+    Adjustment(size_t original_offset,
+               size_t original_length,
+               size_t output_length);
+
+    size_t original_offset;
+    size_t original_length;
+    size_t output_length;
+  };
+
+  explicit OffsetAdjuster(std::vector<size_t>* offsets_for_adjustment);
+  ~OffsetAdjuster();
+
+  void Add(const Adjustment& adjustment);
+
+ private:
+  void AdjustOffset(std::vector<size_t>::iterator offset);
+
+  std::vector<size_t>* offsets_for_adjustment_;
+  std::vector<Adjustment> adjustments_;
+};
+
+#endif  // BASE_UTF_OFFSET_STRING_CONVERSIONS_H_
diff --git a/base/utf_offset_string_conversions_unittest.cc b/base/utf_offset_string_conversions_unittest.cc
new file mode 100644
index 0000000..ff03a75
--- /dev/null
+++ b/base/utf_offset_string_conversions_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 <algorithm>
+
+#include "base/logging.h"
+#include "base/string_piece.h"
+#include "base/utf_offset_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+static const size_t kNpos = string16::npos;
+
+}  // namespace
+
+TEST(UTFOffsetStringConversionsTest, AdjustOffset) {
+  struct UTF8ToUTF16Case {
+    const char* utf8;
+    size_t input_offset;
+    size_t output_offset;
+  } utf8_to_utf16_cases[] = {
+    {"", 0, kNpos},
+    {"\xe4\xbd\xa0\xe5\xa5\xbd", 1, kNpos},
+    {"\xe4\xbd\xa0\xe5\xa5\xbd", 3, 1},
+    {"\xed\xb0\x80z", 3, 1},
+    {"A\xF0\x90\x8C\x80z", 1, 1},
+    {"A\xF0\x90\x8C\x80z", 2, kNpos},
+    {"A\xF0\x90\x8C\x80z", 5, 3},
+  };
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(utf8_to_utf16_cases); ++i) {
+    size_t offset = utf8_to_utf16_cases[i].input_offset;
+    UTF8ToUTF16AndAdjustOffset(utf8_to_utf16_cases[i].utf8, &offset);
+    EXPECT_EQ(utf8_to_utf16_cases[i].output_offset, offset);
+  }
+
+  struct UTF16ToUTF8Case {
+    char16 utf16[10];
+    size_t input_offset;
+    size_t output_offset;
+  } utf16_to_utf8_cases[] = {
+      {{}, 0, kNpos},
+      // Converted to 3-byte utf-8 sequences
+      {{0x5909, 0x63DB}, 2, kNpos},
+      {{0x5909, 0x63DB}, 1, 3},
+      // Converted to 2-byte utf-8 sequences
+      {{'A', 0x00bc, 0x00be, 'z'}, 1, 1},
+      {{'A', 0x00bc, 0x00be, 'z'}, 2, 3},
+      {{'A', 0x00bc, 0x00be, 'z'}, 3, 5},
+      // Surrogate pair
+      {{'A', 0xd800, 0xdf00, 'z'}, 1, 1},
+      {{'A', 0xd800, 0xdf00, 'z'}, 2, kNpos},
+      {{'A', 0xd800, 0xdf00, 'z'}, 3, 5},
+  };
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(utf16_to_utf8_cases); ++i) {
+    size_t offset = utf16_to_utf8_cases[i].input_offset;
+    UTF16ToUTF8AndAdjustOffset(utf16_to_utf8_cases[i].utf16, &offset);
+    EXPECT_EQ(utf16_to_utf8_cases[i].output_offset, offset);
+  }
+}
+
+TEST(UTFOffsetStringConversionsTest, LimitOffsets) {
+  const size_t kLimit = 10;
+  const size_t kItems = 20;
+  std::vector<size_t> size_ts;
+  for (size_t t = 0; t < kItems; ++t)
+    size_ts.push_back(t);
+  std::for_each(size_ts.begin(), size_ts.end(),
+                LimitOffset<string16>(kLimit));
+  size_t unlimited_count = 0;
+  for (std::vector<size_t>::iterator ti = size_ts.begin(); ti != size_ts.end();
+       ++ti) {
+    if (*ti < kLimit && *ti != kNpos)
+      ++unlimited_count;
+  }
+  EXPECT_EQ(10U, unlimited_count);
+
+  // Reverse the values in the vector and try again.
+  size_ts.clear();
+  for (size_t t = kItems; t > 0; --t)
+    size_ts.push_back(t - 1);
+  std::for_each(size_ts.begin(), size_ts.end(),
+                LimitOffset<string16>(kLimit));
+  unlimited_count = 0;
+  for (std::vector<size_t>::iterator ti = size_ts.begin(); ti != size_ts.end();
+       ++ti) {
+    if (*ti < kLimit && *ti != kNpos)
+      ++unlimited_count;
+  }
+  EXPECT_EQ(10U, unlimited_count);
+}
+
+TEST(UTFOffsetStringConversionsTest, AdjustOffsets) {
+  // Imagine we have strings as shown in the following cases where the
+  // X's represent encoded characters.
+  // 1: abcXXXdef ==> abcXdef
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t < 9; ++t)
+      offsets.push_back(t);
+    {
+      OffsetAdjuster offset_adjuster(&offsets);
+      offset_adjuster.Add(OffsetAdjuster::Adjustment(3, 3, 1));
+    }
+    size_t expected_1[] = {0, 1, 2, 3, kNpos, kNpos, 4, 5, 6};
+    EXPECT_EQ(offsets.size(), arraysize(expected_1));
+    for (size_t i = 0; i < arraysize(expected_1); ++i)
+      EXPECT_EQ(expected_1[i], offsets[i]);
+  }
+
+  // 2: XXXaXXXXbcXXXXXXXdefXXX ==> XaXXbcXXXXdefX
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t < 23; ++t)
+      offsets.push_back(t);
+    {
+      OffsetAdjuster offset_adjuster(&offsets);
+      offset_adjuster.Add(OffsetAdjuster::Adjustment(0, 3, 1));
+      offset_adjuster.Add(OffsetAdjuster::Adjustment(4, 4, 2));
+      offset_adjuster.Add(OffsetAdjuster::Adjustment(10, 7, 4));
+      offset_adjuster.Add(OffsetAdjuster::Adjustment(20, 3, 1));
+    }
+    size_t expected_2[] = {0, kNpos, kNpos, 1, 2, kNpos, kNpos, kNpos, 4, 5, 6,
+                           kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 10, 11, 12,
+                           13, kNpos, kNpos};
+    EXPECT_EQ(offsets.size(), arraysize(expected_2));
+    for (size_t i = 0; i < arraysize(expected_2); ++i)
+      EXPECT_EQ(expected_2[i], offsets[i]);
+  }
+
+  // 3: XXXaXXXXbcdXXXeXX ==> aXXXXbcdXXXe
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t < 17; ++t)
+      offsets.push_back(t);
+    {
+      OffsetAdjuster offset_adjuster(&offsets);
+      offset_adjuster.Add(OffsetAdjuster::Adjustment(0, 3, 0));
+      offset_adjuster.Add(OffsetAdjuster::Adjustment(4, 4, 4));
+      offset_adjuster.Add(OffsetAdjuster::Adjustment(11, 3, 3));
+      offset_adjuster.Add(OffsetAdjuster::Adjustment(15, 2, 0));
+    }
+    size_t expected_3[] = {kNpos, kNpos, kNpos, 0, 1, kNpos, kNpos, kNpos, 5, 6,
+                           7, 8, kNpos, kNpos, 11, kNpos, kNpos};
+    EXPECT_EQ(offsets.size(), arraysize(expected_3));
+    for (size_t i = 0; i < arraysize(expected_3); ++i)
+      EXPECT_EQ(expected_3[i], offsets[i]);
+  }
+}
+
+}  // namaspace base
diff --git a/base/utf_string_conversion_utils.cc b/base/utf_string_conversion_utils.cc
new file mode 100644
index 0000000..ebd8fd9
--- /dev/null
+++ b/base/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/utf_string_conversion_utils.h"
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+// ReadUnicodeCharacter --------------------------------------------------------
+
+bool ReadUnicodeCharacter(const char* src,
+                          int32 src_len,
+                          int32* char_index,
+                          uint32* code_point_out) {
+  // U8_NEXT expects to be able to use -1 to signal an error, so we must
+  // use a signed type for code_point.  But this function returns false
+  // on error anyway, so code_point_out is unsigned.
+  int32 code_point;
+  CBU8_NEXT(src, *char_index, src_len, code_point);
+  *code_point_out = static_cast<uint32>(code_point);
+
+  // The ICU macro above moves to the next char, we want to point to the last
+  // char consumed.
+  (*char_index)--;
+
+  // Validate the decoded value.
+  return IsValidCodepoint(code_point);
+}
+
+bool ReadUnicodeCharacter(const char16* src,
+                          int32 src_len,
+                          int32* char_index,
+                          uint32* code_point) {
+  if (CBU16_IS_SURROGATE(src[*char_index])) {
+    if (!CBU16_IS_SURROGATE_LEAD(src[*char_index]) ||
+        *char_index + 1 >= src_len ||
+        !CBU16_IS_TRAIL(src[*char_index + 1])) {
+      // Invalid surrogate pair.
+      return false;
+    }
+
+    // Valid surrogate pair.
+    *code_point = CBU16_GET_SUPPLEMENTARY(src[*char_index],
+                                          src[*char_index + 1]);
+    (*char_index)++;
+  } else {
+    // Not a surrogate, just one 16-bit word.
+    *code_point = src[*char_index];
+  }
+
+  return IsValidCodepoint(*code_point);
+}
+
+#if defined(WCHAR_T_IS_UTF32)
+bool ReadUnicodeCharacter(const wchar_t* src,
+                          int32 src_len,
+                          int32* char_index,
+                          uint32* code_point) {
+  // Conversion is easy since the source is 32-bit.
+  *code_point = src[*char_index];
+
+  // Validate the value.
+  return IsValidCodepoint(*code_point);
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// WriteUnicodeCharacter -------------------------------------------------------
+
+size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) {
+  if (code_point <= 0x7f) {
+    // Fast path the common case of one byte.
+    output->push_back(code_point);
+    return 1;
+  }
+
+
+  // CBU8_APPEND_UNSAFE can append up to 4 bytes.
+  size_t char_offset = output->length();
+  size_t original_char_offset = char_offset;
+  output->resize(char_offset + CBU8_MAX_LENGTH);
+
+  CBU8_APPEND_UNSAFE(&(*output)[0], char_offset, code_point);
+
+  // CBU8_APPEND_UNSAFE will advance our pointer past the inserted character, so
+  // it will represent the new length of the string.
+  output->resize(char_offset);
+  return char_offset - original_char_offset;
+}
+
+size_t WriteUnicodeCharacter(uint32 code_point, string16* output) {
+  if (CBU16_LENGTH(code_point) == 1) {
+    // Thie code point is in the Basic Multilingual Plane (BMP).
+    output->push_back(static_cast<char16>(code_point));
+    return 1;
+  }
+  // Non-BMP characters use a double-character encoding.
+  size_t char_offset = output->length();
+  output->resize(char_offset + CBU16_MAX_LENGTH);
+  CBU16_APPEND_UNSAFE(&(*output)[0], char_offset, code_point);
+  return CBU16_MAX_LENGTH;
+}
+
+// Generalized Unicode converter -----------------------------------------------
+
+template<typename CHAR>
+void PrepareForUTF8Output(const CHAR* src,
+                          size_t src_len,
+                          std::string* output) {
+  output->clear();
+  if (src_len == 0)
+    return;
+  if (src[0] < 0x80) {
+    // Assume that the entire input will be ASCII.
+    output->reserve(src_len);
+  } else {
+    // Assume that the entire input is non-ASCII and will have 3 bytes per char.
+    output->reserve(src_len * 3);
+  }
+}
+
+// Instantiate versions we know callers will need.
+template void PrepareForUTF8Output(const wchar_t*, size_t, std::string*);
+template void PrepareForUTF8Output(const char16*, size_t, std::string*);
+
+template<typename STRING>
+void PrepareForUTF16Or32Output(const char* src,
+                               size_t src_len,
+                               STRING* output) {
+  output->clear();
+  if (src_len == 0)
+    return;
+  if (static_cast<unsigned char>(src[0]) < 0x80) {
+    // Assume the input is all ASCII, which means 1:1 correspondence.
+    output->reserve(src_len);
+  } else {
+    // Otherwise assume that the UTF-8 sequences will have 2 bytes for each
+    // character.
+    output->reserve(src_len / 2);
+  }
+}
+
+// Instantiate versions we know callers will need.
+template void PrepareForUTF16Or32Output(const char*, size_t, std::wstring*);
+template void PrepareForUTF16Or32Output(const char*, size_t, string16*);
+
+}  // namespace base
diff --git a/base/utf_string_conversion_utils.h b/base/utf_string_conversion_utils.h
new file mode 100644
index 0000000..17e04f1
--- /dev/null
+++ b/base/utf_string_conversion_utils.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_UTF_STRING_CONVERSION_UTILS_H_
+#define BASE_UTF_STRING_CONVERSION_UTILS_H_
+
+// This should only be used by the various UTF string conversion files.
+
+#include "base/base_export.h"
+#include "base/string16.h"
+
+namespace base {
+
+inline bool IsValidCodepoint(uint32 code_point) {
+  // Excludes the surrogate code points ([0xD800, 0xDFFF]) and
+  // codepoints larger than 0x10FFFF (the highest codepoint allowed).
+  // Non-characters and unassigned codepoints are allowed.
+  return code_point < 0xD800u ||
+         (code_point >= 0xE000u && code_point <= 0x10FFFFu);
+}
+
+inline bool IsValidCharacter(uint32 code_point) {
+  // Excludes non-characters (U+FDD0..U+FDEF, and all codepoints ending in
+  // 0xFFFE or 0xFFFF) from the set of valid code points.
+  return code_point < 0xD800u || (code_point >= 0xE000u &&
+      code_point < 0xFDD0u) || (code_point > 0xFDEFu &&
+      code_point <= 0x10FFFFu && (code_point & 0xFFFEu) != 0xFFFEu);
+}
+
+// ReadUnicodeCharacter --------------------------------------------------------
+
+// Reads a UTF-8 stream, placing the next code point into the given output
+// |*code_point|. |src| represents the entire string to read, and |*char_index|
+// is the character offset within the string to start reading at. |*char_index|
+// will be updated to index the last character read, such that incrementing it
+// (as in a for loop) will take the reader to the next character.
+//
+// Returns true on success. On false, |*code_point| will be invalid.
+BASE_EXPORT bool ReadUnicodeCharacter(const char* src,
+                                      int32 src_len,
+                                      int32* char_index,
+                                      uint32* code_point_out);
+
+// Reads a UTF-16 character. The usage is the same as the 8-bit version above.
+BASE_EXPORT bool ReadUnicodeCharacter(const char16* src,
+                                      int32 src_len,
+                                      int32* char_index,
+                                      uint32* code_point);
+
+#if defined(WCHAR_T_IS_UTF32)
+// Reads UTF-32 character. The usage is the same as the 8-bit version above.
+BASE_EXPORT bool ReadUnicodeCharacter(const wchar_t* src,
+                                      int32 src_len,
+                                      int32* char_index,
+                                      uint32* code_point);
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// WriteUnicodeCharacter -------------------------------------------------------
+
+// Appends a UTF-8 character to the given 8-bit string.  Returns the number of
+// bytes written.
+// TODO(brettw) Bug 79631: This function should not be exposed.
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point,
+                                         std::string* output);
+
+// Appends the given code point as a UTF-16 character to the given 16-bit
+// string.  Returns the number of 16-bit values written.
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point, string16* output);
+
+#if defined(WCHAR_T_IS_UTF32)
+// Appends the given UTF-32 character to the given 32-bit string.  Returns the
+// number of 32-bit values written.
+inline size_t WriteUnicodeCharacter(uint32 code_point, std::wstring* output) {
+  // This is the easy case, just append the character.
+  output->push_back(code_point);
+  return 1;
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// Generalized Unicode converter -----------------------------------------------
+
+// Guesses the length of the output in UTF-8 in bytes, clears that output
+// string, and reserves that amount of space.  We assume that the input
+// character types are unsigned, which will be true for UTF-16 and -32 on our
+// systems.
+template<typename CHAR>
+void PrepareForUTF8Output(const CHAR* src, size_t src_len, std::string* output);
+
+// Prepares an output buffer (containing either UTF-16 or -32 data) given some
+// UTF-8 input that will be converted to it.  See PrepareForUTF8Output().
+template<typename STRING>
+void PrepareForUTF16Or32Output(const char* src, size_t src_len, STRING* output);
+
+}  // namespace base
+
+#endif  // BASE_UTF_STRING_CONVERSION_UTILS_H_
diff --git a/base/utf_string_conversions.cc b/base/utf_string_conversions.cc
new file mode 100644
index 0000000..7b73696
--- /dev/null
+++ b/base/utf_string_conversions.cc
@@ -0,0 +1,186 @@
+// 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/utf_string_conversions.h"
+
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversion_utils.h"
+
+using base::PrepareForUTF8Output;
+using base::PrepareForUTF16Or32Output;
+using base::ReadUnicodeCharacter;
+using base::WriteUnicodeCharacter;
+
+namespace {
+
+// Generalized Unicode converter -----------------------------------------------
+
+// Converts the given source Unicode character type to the given destination
+// Unicode character type as a STL string. The given input buffer and size
+// determine the source, and the given output STL string will be replaced by
+// the result.
+template<typename SRC_CHAR, typename DEST_STRING>
+bool ConvertUnicode(const SRC_CHAR* src,
+                    size_t src_len,
+                    DEST_STRING* output) {
+  // ICU requires 32-bit numbers.
+  bool success = true;
+  int32 src_len32 = static_cast<int32>(src_len);
+  for (int32 i = 0; i < src_len32; i++) {
+    uint32 code_point;
+    if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) {
+      WriteUnicodeCharacter(code_point, output);
+    } else {
+      WriteUnicodeCharacter(0xFFFD, output);
+      success = false;
+    }
+  }
+
+  return success;
+}
+
+}  // namespace
+
+// UTF-8 <-> Wide --------------------------------------------------------------
+
+bool WideToUTF8(const wchar_t* src, size_t src_len, std::string* output) {
+  PrepareForUTF8Output(src, src_len, output);
+  return ConvertUnicode(src, src_len, output);
+}
+
+std::string WideToUTF8(const std::wstring& wide) {
+  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.
+  WideToUTF8(wide.data(), wide.length(), &ret);
+  return ret;
+}
+
+bool UTF8ToWide(const char* src, size_t src_len, std::wstring* output) {
+  PrepareForUTF16Or32Output(src, src_len, output);
+  return ConvertUnicode(src, src_len, output);
+}
+
+std::wstring UTF8ToWide(const base::StringPiece& utf8) {
+  std::wstring ret;
+  UTF8ToWide(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) {
+  PrepareForUTF16Or32Output(src, src_len, output);
+  return ConvertUnicode(src, src_len, output);
+}
+
+string16 UTF8ToUTF16(const base::StringPiece& utf8) {
+  string16 ret;
+  // Ignore the success flag of this call, it will do the best it can for
+  // invalid input, which is what we want here.
+  UTF8ToUTF16(utf8.data(), utf8.length(), &ret);
+  return ret;
+}
+
+bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) {
+  PrepareForUTF8Output(src, src_len, output);
+  return ConvertUnicode(src, src_len, output);
+}
+
+std::string UTF16ToUTF8(const string16& utf16) {
+  std::string ret;
+  // Ignore the success flag of this call, it will do the best it can for
+  // invalid input, which is what we want here.
+  UTF16ToUTF8(utf16.data(), utf16.length(), &ret);
+  return ret;
+}
+
+#elif defined(WCHAR_T_IS_UTF16)
+// Easy case since we can use the "wide" versions we already wrote above.
+
+bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
+  return UTF8ToWide(src, src_len, output);
+}
+
+string16 UTF8ToUTF16(const base::StringPiece& utf8) {
+  return UTF8ToWide(utf8);
+}
+
+bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) {
+  return WideToUTF8(src, src_len, output);
+}
+
+std::string UTF16ToUTF8(const string16& utf16) {
+  return WideToUTF8(utf16);
+}
+
+#endif
+
+std::wstring ASCIIToWide(const base::StringPiece& ascii) {
+  DCHECK(IsStringASCII(ascii)) << ascii;
+  return std::wstring(ascii.begin(), ascii.end());
+}
+
+string16 ASCIIToUTF16(const base::StringPiece& ascii) {
+  DCHECK(IsStringASCII(ascii)) << ascii;
+  return string16(ascii.begin(), ascii.end());
+}
diff --git a/base/utf_string_conversions.h b/base/utf_string_conversions.h
new file mode 100644
index 0000000..5a391fa
--- /dev/null
+++ b/base/utf_string_conversions.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_UTF_STRING_CONVERSIONS_H_
+#define BASE_UTF_STRING_CONVERSIONS_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/string16.h"
+#include "base/string_piece.h"
+
+// These convert between UTF-8, -16, and -32 strings. They are potentially slow,
+// so avoid unnecessary conversions. The low-level versions return a boolean
+// indicating whether the conversion was 100% valid. In this case, it will still
+// do the best it can and put the result in the output buffer. The versions that
+// return strings ignore this error and just return the best conversion
+// possible.
+BASE_EXPORT bool WideToUTF8(const wchar_t* src, size_t src_len,
+                            std::string* output);
+BASE_EXPORT std::string WideToUTF8(const std::wstring& wide);
+BASE_EXPORT bool UTF8ToWide(const char* src, size_t src_len,
+                            std::wstring* output);
+BASE_EXPORT std::wstring UTF8ToWide(const base::StringPiece& utf8);
+
+BASE_EXPORT bool WideToUTF16(const wchar_t* src, size_t src_len,
+                             string16* output);
+BASE_EXPORT string16 WideToUTF16(const std::wstring& wide);
+BASE_EXPORT bool UTF16ToWide(const char16* src, size_t src_len,
+                             std::wstring* output);
+BASE_EXPORT std::wstring UTF16ToWide(const string16& utf16);
+
+BASE_EXPORT bool UTF8ToUTF16(const char* src, size_t src_len, string16* output);
+BASE_EXPORT string16 UTF8ToUTF16(const base::StringPiece& utf8);
+BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len,
+                             std::string* output);
+BASE_EXPORT std::string UTF16ToUTF8(const string16& utf16);
+
+// We are trying to get rid of wstring as much as possible, but it's too big
+// a mess to do it all at once.  These conversions should be used when we
+// really should just be passing a string16 around, but we haven't finished
+// porting whatever module uses wstring and the conversion is being used as a
+// stopcock.  This makes it easy to grep for the ones that should be removed.
+#if defined(OS_WIN)
+# define WideToUTF16Hack
+# define UTF16ToWideHack
+#else
+# define WideToUTF16Hack WideToUTF16
+# define UTF16ToWideHack UTF16ToWide
+#endif
+
+// These convert an ASCII string, typically a hardcoded constant, to a
+// UTF16/Wide string.
+BASE_EXPORT std::wstring ASCIIToWide(const base::StringPiece& ascii);
+BASE_EXPORT string16 ASCIIToUTF16(const base::StringPiece& ascii);
+
+#endif  // BASE_UTF_STRING_CONVERSIONS_H_
diff --git a/base/utf_string_conversions_unittest.cc b/base/utf_string_conversions_unittest.cc
new file mode 100644
index 0000000..7c180a6
--- /dev/null
+++ b/base/utf_string_conversions_unittest.cc
@@ -0,0 +1,211 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const wchar_t* const kConvertRoundtripCases[] = {
+  L"Google Video",
+  // "网页 图片 资讯更多 »"
+  L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb",
+  //  "Παγκόσμιος Ιστός"
+  L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+  L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2",
+  // "Поиск страниц на русском"
+  L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442"
+  L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430"
+  L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c",
+  // "전체서비스"
+  L"\xc804\xccb4\xc11c\xbe44\xc2a4",
+
+  // Test characters that take more than 16 bits. This will depend on whether
+  // wchar_t is 16 or 32 bits.
+#if defined(WCHAR_T_IS_UTF16)
+  L"\xd800\xdf00",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44",
+#elif defined(WCHAR_T_IS_UTF32)
+  L"\x10300",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\x11d40\x11d41\x11d42\x11d43\x11d44",
+#endif
+};
+
+}  // namespace
+
+TEST(UTFStringConversionsTest, ConvertUTF8AndWide) {
+  // we round-trip all the wide strings through UTF-8 to make sure everything
+  // agrees on the conversion. This uses the stream operators to test them
+  // simultaneously.
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::ostringstream utf8;
+    utf8 << WideToUTF8(kConvertRoundtripCases[i]);
+    std::wostringstream wide;
+    wide << UTF8ToWide(utf8.str());
+
+    EXPECT_EQ(kConvertRoundtripCases[i], wide.str());
+  }
+}
+
+TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) {
+  // An empty std::wstring should be converted to an empty std::string,
+  // and vice versa.
+  std::wstring wempty;
+  std::string empty;
+  EXPECT_EQ(empty, WideToUTF8(wempty));
+  EXPECT_EQ(wempty, UTF8ToWide(empty));
+}
+
+TEST(UTFStringConversionsTest, ConvertUTF8ToWide) {
+  struct UTF8ToWideCase {
+    const char* utf8;
+    const wchar_t* wide;
+    bool success;
+  } convert_cases[] = {
+    // Regular UTF-8 input.
+    {"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true},
+    // Non-character is passed through.
+    {"\xef\xbf\xbfHello", L"\xffffHello", true},
+    // Truncated UTF-8 sequence.
+    {"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
+    // Truncated off the end.
+    {"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false},
+    // Non-shortest-form UTF-8.
+    {"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
+    // This UTF-8 character decodes to a UTF-16 surrogate, which is illegal.
+    {"\xed\xb0\x80", L"\xfffd", false},
+    // Non-BMP characters. The second is a non-character regarded as valid.
+    // The result will either be in UTF-16 or UTF-32.
+#if defined(WCHAR_T_IS_UTF16)
+    {"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true},
+    {"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true},
+#elif defined(WCHAR_T_IS_UTF32)
+    {"A\xF0\x90\x8C\x80z", L"A\x10300z", true},
+    {"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true},
+#endif
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(convert_cases); i++) {
+    std::wstring converted;
+    EXPECT_EQ(convert_cases[i].success,
+              UTF8ToWide(convert_cases[i].utf8,
+                         strlen(convert_cases[i].utf8),
+                         &converted));
+    std::wstring expected(convert_cases[i].wide);
+    EXPECT_EQ(expected, converted);
+  }
+
+  // Manually test an embedded NULL.
+  std::wstring converted;
+  EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted));
+  ASSERT_EQ(3U, converted.length());
+  EXPECT_EQ(static_cast<wchar_t>(0), converted[0]);
+  EXPECT_EQ('Z', converted[1]);
+  EXPECT_EQ('\t', converted[2]);
+
+  // Make sure that conversion replaces, not appends.
+  EXPECT_TRUE(UTF8ToWide("B", 1, &converted));
+  ASSERT_EQ(1U, converted.length());
+  EXPECT_EQ('B', converted[0]);
+}
+
+#if defined(WCHAR_T_IS_UTF16)
+// This test is only valid when wchar_t == UTF-16.
+TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) {
+  struct WideToUTF8Case {
+    const wchar_t* utf16;
+    const char* utf8;
+    bool success;
+  } convert_cases[] = {
+    // Regular UTF-16 input.
+    {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
+    // Test a non-BMP character.
+    {L"\xd800\xdf00", "\xF0\x90\x8C\x80", true},
+    // Non-characters are passed through.
+    {L"\xffffHello", "\xEF\xBF\xBFHello", true},
+    {L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true},
+    // The first character is a truncated UTF-16 character.
+    {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false},
+    // Truncated at the end.
+    {L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd", false},
+  };
+
+  for (int i = 0; i < arraysize(convert_cases); i++) {
+    std::string converted;
+    EXPECT_EQ(convert_cases[i].success,
+              WideToUTF8(convert_cases[i].utf16,
+                         wcslen(convert_cases[i].utf16),
+                         &converted));
+    std::string expected(convert_cases[i].utf8);
+    EXPECT_EQ(expected, converted);
+  }
+}
+
+#elif defined(WCHAR_T_IS_UTF32)
+// This test is only valid when wchar_t == UTF-32.
+TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) {
+  struct WideToUTF8Case {
+    const wchar_t* utf32;
+    const char* utf8;
+    bool success;
+  } convert_cases[] = {
+    // Regular 16-bit input.
+    {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
+    // Test a non-BMP character.
+    {L"A\x10300z", "A\xF0\x90\x8C\x80z", true},
+    // Non-characters are passed through.
+    {L"\xffffHello", "\xEF\xBF\xBFHello", true},
+    {L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true},
+    // Invalid Unicode code points.
+    {L"\xfffffffHello", "\xEF\xBF\xBDHello", false},
+    // The first character is a truncated UTF-16 character.
+    {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false},
+    {L"\xdc01Hello", "\xef\xbf\xbdHello", false},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(convert_cases); i++) {
+    std::string converted;
+    EXPECT_EQ(convert_cases[i].success,
+              WideToUTF8(convert_cases[i].utf32,
+                         wcslen(convert_cases[i].utf32),
+                         &converted));
+    std::string expected(convert_cases[i].utf8);
+    EXPECT_EQ(expected, converted);
+  }
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+TEST(UTFStringConversionsTest, ConvertMultiString) {
+  static wchar_t wmulti[] = {
+    L'f', L'o', L'o', L'\0',
+    L'b', L'a', L'r', L'\0',
+    L'b', L'a', L'z', L'\0',
+    L'\0'
+  };
+  static char multi[] = {
+    'f', 'o', 'o', '\0',
+    'b', 'a', 'r', '\0',
+    'b', 'a', 'z', '\0',
+    '\0'
+  };
+  std::wstring wmultistring;
+  memcpy(WriteInto(&wmultistring, arraysize(wmulti)), wmulti, sizeof(wmulti));
+  EXPECT_EQ(arraysize(wmulti) - 1, wmultistring.length());
+  std::string expected;
+  memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi));
+  EXPECT_EQ(arraysize(multi) - 1, expected.length());
+  const std::string& converted = WideToUTF8(wmultistring);
+  EXPECT_EQ(arraysize(multi) - 1, converted.length());
+  EXPECT_EQ(expected, converted);
+}
+
+}  // base
diff --git a/base/value_conversions.cc b/base/value_conversions.cc
new file mode 100644
index 0000000..6bde1ae
--- /dev/null
+++ b/base/value_conversions.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/value_conversions.h"
+
+#include "base/file_path.h"
+#include "base/string_number_conversions.h"
+#include "base/time.h"
+#include "base/values.h"
+
+namespace base {
+
+// |Value| internally stores strings in UTF-8, so we have to convert from the
+// system native code to UTF-8 and back.
+StringValue* CreateFilePathValue(const FilePath& in_value) {
+  return new StringValue(in_value.AsUTF8Unsafe());
+}
+
+bool GetValueAsFilePath(const Value& value, FilePath* file_path) {
+  std::string str;
+  if (!value.GetAsString(&str))
+    return false;
+  if (file_path)
+    *file_path = FilePath::FromUTF8Unsafe(str);
+  return true;
+}
+
+// |Value| does not support 64-bit integers, and doubles do not have enough
+// precision, so we store the 64-bit time value as a string instead.
+StringValue* CreateTimeDeltaValue(const TimeDelta& time) {
+  std::string string_value = base::Int64ToString(time.ToInternalValue());
+  return new StringValue(string_value);
+}
+
+bool GetValueAsTimeDelta(const Value& value, TimeDelta* time) {
+  std::string str;
+  int64 int_value;
+  if (!value.GetAsString(&str) || !base::StringToInt64(str, &int_value))
+    return false;
+  if (time)
+    *time = TimeDelta::FromInternalValue(int_value);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/value_conversions.h b/base/value_conversions.h
new file mode 100644
index 0000000..99cd514
--- /dev/null
+++ b/base/value_conversions.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_VALUE_CONVERSIONS_H_
+#define BASE_VALUE_CONVERSIONS_H_
+
+// This file contains methods to convert things to a |Value| and back.
+
+#include "base/base_export.h"
+
+class FilePath;
+
+namespace base {
+
+class TimeDelta;
+class StringValue;
+class Value;
+
+// The caller takes ownership of the returned value.
+BASE_EXPORT StringValue* CreateFilePathValue(const FilePath& in_value);
+BASE_EXPORT bool GetValueAsFilePath(const Value& value, FilePath* file_path);
+
+BASE_EXPORT StringValue* CreateTimeDeltaValue(const TimeDelta& time);
+BASE_EXPORT bool GetValueAsTimeDelta(const Value& value, TimeDelta* time);
+
+}  // namespace
+
+#endif  // BASE_VALUE_CONVERSIONS_H_
diff --git a/base/values.cc b/base/values.cc
new file mode 100644
index 0000000..0b0eb07
--- /dev/null
+++ b/base/values.cc
@@ -0,0 +1,1138 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <algorithm>
+#include <ostream>
+
+#include "base/float_util.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+
+namespace {
+
+// 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.
+Value* CopyWithoutEmptyChildren(Value* node) {
+  DCHECK(node);
+  switch (node->GetType()) {
+    case Value::TYPE_LIST: {
+      ListValue* list = static_cast<ListValue*>(node);
+      ListValue* copy = new ListValue;
+      for (ListValue::const_iterator it = list->begin(); it != list->end();
+           ++it) {
+        Value* child_copy = CopyWithoutEmptyChildren(*it);
+        if (child_copy)
+          copy->Append(child_copy);
+      }
+      if (!copy->empty())
+        return copy;
+
+      delete copy;
+      return NULL;
+    }
+
+    case Value::TYPE_DICTIONARY: {
+      DictionaryValue* dict = static_cast<DictionaryValue*>(node);
+      DictionaryValue* copy = new DictionaryValue;
+      for (DictionaryValue::key_iterator it = dict->begin_keys();
+           it != dict->end_keys(); ++it) {
+        Value* child = NULL;
+        bool rv = dict->GetWithoutPathExpansion(*it, &child);
+        DCHECK(rv);
+        Value* child_copy = CopyWithoutEmptyChildren(child);
+        if (child_copy)
+          copy->SetWithoutPathExpansion(*it, child_copy);
+      }
+      if (!copy->empty())
+        return copy;
+
+      delete copy;
+      return NULL;
+    }
+
+    default:
+      // For everything else, just make a copy.
+      return node->DeepCopy();
+  }
+}
+
+// A small functor for comparing Values for std::find_if and similar.
+class ValueEquals {
+ public:
+  // Pass the value against which all consecutive calls of the () operator will
+  // compare their argument to. This Value object must not be destroyed while
+  // the ValueEquals is  in use.
+  ValueEquals(const Value* first) : first_(first) { }
+
+  bool operator ()(const Value* second) const {
+    return first_->Equals(second);
+  }
+
+ private:
+  const Value* first_;
+};
+
+}  // namespace
+
+namespace base {
+
+///////////////////// Value ////////////////////
+
+Value::~Value() {
+}
+
+// static
+Value* Value::CreateNullValue() {
+  return new Value(TYPE_NULL);
+}
+
+// static
+FundamentalValue* Value::CreateBooleanValue(bool in_value) {
+  return new FundamentalValue(in_value);
+}
+
+// static
+FundamentalValue* Value::CreateIntegerValue(int in_value) {
+  return new FundamentalValue(in_value);
+}
+
+// static
+FundamentalValue* Value::CreateDoubleValue(double in_value) {
+  return new FundamentalValue(in_value);
+}
+
+// static
+StringValue* Value::CreateStringValue(const std::string& in_value) {
+  return new StringValue(in_value);
+}
+
+// static
+StringValue* Value::CreateStringValue(const string16& in_value) {
+  return new StringValue(in_value);
+}
+
+bool Value::GetAsBoolean(bool* out_value) const {
+  return false;
+}
+
+bool Value::GetAsInteger(int* out_value) const {
+  return false;
+}
+
+bool Value::GetAsDouble(double* out_value) const {
+  return false;
+}
+
+bool Value::GetAsString(std::string* out_value) const {
+  return false;
+}
+
+bool Value::GetAsString(string16* out_value) const {
+  return false;
+}
+
+bool Value::GetAsList(ListValue** out_value) {
+  return false;
+}
+
+bool Value::GetAsList(const ListValue** out_value) const {
+  return false;
+}
+
+bool Value::GetAsDictionary(DictionaryValue** out_value) {
+  return false;
+}
+
+bool Value::GetAsDictionary(const DictionaryValue** out_value) const {
+  return false;
+}
+
+Value* Value::DeepCopy() const {
+  // This method should only be getting called for null Values--all subclasses
+  // need to provide their own implementation;.
+  DCHECK(IsType(TYPE_NULL));
+  return CreateNullValue();
+}
+
+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) {
+}
+
+///////////////////// 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 (!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 CreateBooleanValue(boolean_value_);
+
+    case TYPE_INTEGER:
+      return CreateIntegerValue(integer_value_);
+
+    case TYPE_DOUBLE:
+      return CreateDoubleValue(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() {
+}
+
+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;
+}
+
+StringValue* StringValue::DeepCopy() const {
+  return CreateStringValue(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() {
+  DCHECK(buffer_);
+  if (buffer_)
+    delete[] buffer_;
+}
+
+// static
+BinaryValue* BinaryValue::Create(char* buffer, size_t size) {
+  if (!buffer)
+    return NULL;
+
+  return new BinaryValue(buffer, size);
+}
+
+// static
+BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer,
+                                                 size_t size) {
+  if (!buffer)
+    return NULL;
+
+  char* buffer_copy = new char[size];
+  memcpy(buffer_copy, buffer, size);
+  return new BinaryValue(buffer_copy, size);
+}
+
+BinaryValue* BinaryValue::DeepCopy() const {
+  return CreateWithCopiedBuffer(buffer_, size_);
+}
+
+bool BinaryValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+  const BinaryValue* other_binary = static_cast<const BinaryValue*>(other);
+  if (other_binary->size_ != size_)
+    return false;
+  return !memcmp(buffer_, other_binary->buffer_, size_);
+}
+
+BinaryValue::BinaryValue(char* buffer, size_t size)
+  : Value(TYPE_BINARY),
+    buffer_(buffer),
+    size_(size) {
+  DCHECK(buffer_);
+}
+
+///////////////////// DictionaryValue ////////////////////
+
+DictionaryValue::DictionaryValue()
+    : Value(TYPE_DICTIONARY) {
+}
+
+DictionaryValue::~DictionaryValue() {
+  Clear();
+}
+
+bool DictionaryValue::GetAsDictionary(DictionaryValue** out_value) {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+bool DictionaryValue::GetAsDictionary(const DictionaryValue** out_value) const {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+bool DictionaryValue::HasKey(const std::string& key) const {
+  DCHECK(IsStringUTF8(key));
+  ValueMap::const_iterator current_entry = dictionary_.find(key);
+  DCHECK((current_entry == dictionary_.end()) || current_entry->second);
+  return current_entry != dictionary_.end();
+}
+
+void DictionaryValue::Clear() {
+  ValueMap::iterator dict_iterator = dictionary_.begin();
+  while (dict_iterator != dictionary_.end()) {
+    delete dict_iterator->second;
+    ++dict_iterator;
+  }
+
+  dictionary_.clear();
+}
+
+void DictionaryValue::Set(const std::string& path, Value* in_value) {
+  DCHECK(IsStringUTF8(path));
+  DCHECK(in_value);
+
+  std::string current_path(path);
+  DictionaryValue* current_dictionary = this;
+  for (size_t delimiter_position = current_path.find('.');
+       delimiter_position != std::string::npos;
+       delimiter_position = current_path.find('.')) {
+    // Assume that we're indexing into a dictionary.
+    std::string key(current_path, 0, delimiter_position);
+    DictionaryValue* child_dictionary = NULL;
+    if (!current_dictionary->GetDictionary(key, &child_dictionary)) {
+      child_dictionary = new DictionaryValue;
+      current_dictionary->SetWithoutPathExpansion(key, child_dictionary);
+    }
+
+    current_dictionary = child_dictionary;
+    current_path.erase(0, delimiter_position + 1);
+  }
+
+  current_dictionary->SetWithoutPathExpansion(current_path, in_value);
+}
+
+void DictionaryValue::SetBoolean(const std::string& path, bool in_value) {
+  Set(path, CreateBooleanValue(in_value));
+}
+
+void DictionaryValue::SetInteger(const std::string& path, int in_value) {
+  Set(path, CreateIntegerValue(in_value));
+}
+
+void DictionaryValue::SetDouble(const std::string& path, double in_value) {
+  Set(path, CreateDoubleValue(in_value));
+}
+
+void DictionaryValue::SetString(const std::string& path,
+                                const std::string& in_value) {
+  Set(path, CreateStringValue(in_value));
+}
+
+void DictionaryValue::SetString(const std::string& path,
+                                const string16& in_value) {
+  Set(path, CreateStringValue(in_value));
+}
+
+void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
+                                              Value* in_value) {
+  // If there's an existing value here, we need to delete it, because
+  // we own all our children.
+  std::pair<ValueMap::iterator, bool> ins_res =
+      dictionary_.insert(std::make_pair(key, in_value));
+  if (!ins_res.second) {
+    DCHECK_NE(ins_res.first->second, in_value);  // This would be bogus
+    delete ins_res.first->second;
+    ins_res.first->second = in_value;
+  }
+}
+
+void DictionaryValue::SetBooleanWithoutPathExpansion(
+    const std::string& path, bool in_value) {
+  SetWithoutPathExpansion(path, CreateBooleanValue(in_value));
+}
+
+void DictionaryValue::SetIntegerWithoutPathExpansion(
+    const std::string& path, int in_value) {
+  SetWithoutPathExpansion(path, CreateIntegerValue(in_value));
+}
+
+void DictionaryValue::SetDoubleWithoutPathExpansion(
+    const std::string& path, double in_value) {
+  SetWithoutPathExpansion(path, CreateDoubleValue(in_value));
+}
+
+void DictionaryValue::SetStringWithoutPathExpansion(
+    const std::string& path, const std::string& in_value) {
+  SetWithoutPathExpansion(path, CreateStringValue(in_value));
+}
+
+void DictionaryValue::SetStringWithoutPathExpansion(
+    const std::string& path, const string16& in_value) {
+  SetWithoutPathExpansion(path, CreateStringValue(in_value));
+}
+
+bool DictionaryValue::Get(
+    const std::string& path, const Value** out_value) const {
+  DCHECK(IsStringUTF8(path));
+  std::string current_path(path);
+  const DictionaryValue* current_dictionary = this;
+  for (size_t delimiter_position = current_path.find('.');
+       delimiter_position != std::string::npos;
+       delimiter_position = current_path.find('.')) {
+    const DictionaryValue* child_dictionary = NULL;
+    if (!current_dictionary->GetDictionary(
+            current_path.substr(0, delimiter_position), &child_dictionary))
+      return false;
+
+    current_dictionary = child_dictionary;
+    current_path.erase(0, delimiter_position + 1);
+  }
+
+  return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
+}
+
+bool DictionaryValue::Get(const std::string& path, Value** out_value)  {
+  return static_cast<const DictionaryValue&>(*this).Get(
+      path,
+      const_cast<const Value**>(out_value));
+}
+
+bool DictionaryValue::GetBoolean(const std::string& path,
+                                 bool* bool_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsBoolean(bool_value);
+}
+
+bool DictionaryValue::GetInteger(const std::string& path,
+                                 int* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsInteger(out_value);
+}
+
+bool DictionaryValue::GetDouble(const std::string& path,
+                                double* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsDouble(out_value);
+}
+
+bool DictionaryValue::GetString(const std::string& path,
+                                std::string* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetString(const std::string& path,
+                                string16* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetStringASCII(const std::string& path,
+                                     std::string* out_value) const {
+  std::string out;
+  if (!GetString(path, &out))
+    return false;
+
+  if (!IsStringASCII(out)) {
+    NOTREACHED();
+    return false;
+  }
+
+  out_value->assign(out);
+  return true;
+}
+
+bool DictionaryValue::GetBinary(const std::string& path,
+                                const BinaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(path, &value);
+  if (!result || !value->IsType(TYPE_BINARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const BinaryValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetBinary(const std::string& path,
+                                BinaryValue** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetBinary(
+      path,
+      const_cast<const BinaryValue**>(out_value));
+}
+
+bool DictionaryValue::GetDictionary(const std::string& path,
+                                    const DictionaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(path, &value);
+  if (!result || !value->IsType(TYPE_DICTIONARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const DictionaryValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetDictionary(const std::string& path,
+                                    DictionaryValue** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetDictionary(
+      path,
+      const_cast<const DictionaryValue**>(out_value));
+}
+
+bool DictionaryValue::GetList(const std::string& path,
+                              const ListValue** out_value) const {
+  const Value* value;
+  bool result = Get(path, &value);
+  if (!result || !value->IsType(TYPE_LIST))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const ListValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetList(const std::string& path, ListValue** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetList(
+      path,
+      const_cast<const ListValue**>(out_value));
+}
+
+bool DictionaryValue::GetWithoutPathExpansion(const std::string& key,
+                                              const Value** out_value) const {
+  DCHECK(IsStringUTF8(key));
+  ValueMap::const_iterator entry_iterator = dictionary_.find(key);
+  if (entry_iterator == dictionary_.end())
+    return false;
+
+  const Value* entry = entry_iterator->second;
+  if (out_value)
+    *out_value = entry;
+  return true;
+}
+
+bool DictionaryValue::GetWithoutPathExpansion(const std::string& key,
+                                              Value** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetWithoutPathExpansion(
+      key,
+      const_cast<const Value**>(out_value));
+}
+
+bool DictionaryValue::GetBooleanWithoutPathExpansion(const std::string& key,
+                                                     bool* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsBoolean(out_value);
+}
+
+bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::string& key,
+                                                     int* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsInteger(out_value);
+}
+
+bool DictionaryValue::GetDoubleWithoutPathExpansion(const std::string& key,
+                                                    double* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsDouble(out_value);
+}
+
+bool DictionaryValue::GetStringWithoutPathExpansion(
+    const std::string& key,
+    std::string* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetStringWithoutPathExpansion(const std::string& key,
+                                                    string16* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetDictionaryWithoutPathExpansion(
+    const std::string& key,
+    const DictionaryValue** out_value) const {
+  const Value* value;
+  bool result = GetWithoutPathExpansion(key, &value);
+  if (!result || !value->IsType(TYPE_DICTIONARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const DictionaryValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetDictionaryWithoutPathExpansion(
+    const std::string& key,
+    DictionaryValue** out_value) {
+  const DictionaryValue& const_this =
+      static_cast<const DictionaryValue&>(*this);
+  return const_this.GetDictionaryWithoutPathExpansion(
+          key,
+          const_cast<const DictionaryValue**>(out_value));
+}
+
+bool DictionaryValue::GetListWithoutPathExpansion(
+    const std::string& key,
+    const ListValue** out_value) const {
+  const Value* value;
+  bool result = GetWithoutPathExpansion(key, &value);
+  if (!result || !value->IsType(TYPE_LIST))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const ListValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetListWithoutPathExpansion(const std::string& key,
+                                                  ListValue** out_value) {
+  return
+      static_cast<const DictionaryValue&>(*this).GetListWithoutPathExpansion(
+          key,
+          const_cast<const ListValue**>(out_value));
+}
+
+bool DictionaryValue::Remove(const std::string& path, 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,
+                                                 Value** out_value) {
+  DCHECK(IsStringUTF8(key));
+  ValueMap::iterator entry_iterator = dictionary_.find(key);
+  if (entry_iterator == dictionary_.end())
+    return false;
+
+  Value* entry = entry_iterator->second;
+  if (out_value)
+    *out_value = entry;
+  else
+    delete entry;
+  dictionary_.erase(entry_iterator);
+  return true;
+}
+
+DictionaryValue* DictionaryValue::DeepCopyWithoutEmptyChildren() {
+  Value* copy = CopyWithoutEmptyChildren(this);
+  return copy ? static_cast<DictionaryValue*>(copy) : new DictionaryValue;
+}
+
+void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
+  for (DictionaryValue::key_iterator key(dictionary->begin_keys());
+       key != dictionary->end_keys(); ++key) {
+    const Value* merge_value;
+    if (dictionary->GetWithoutPathExpansion(*key, &merge_value)) {
+      // Check whether we have to merge dictionaries.
+      if (merge_value->IsType(Value::TYPE_DICTIONARY)) {
+        DictionaryValue* sub_dict;
+        if (GetDictionaryWithoutPathExpansion(*key, &sub_dict)) {
+          sub_dict->MergeDictionary(
+              static_cast<const DictionaryValue*>(merge_value));
+          continue;
+        }
+      }
+      // All other cases: Make a copy and hook it up.
+      SetWithoutPathExpansion(*key, merge_value->DeepCopy());
+    }
+  }
+}
+
+void DictionaryValue::Swap(DictionaryValue* other) {
+  dictionary_.swap(other->dictionary_);
+}
+
+DictionaryValue::key_iterator::key_iterator(ValueMap::const_iterator itr) {
+  itr_ = itr;
+}
+
+DictionaryValue::key_iterator::key_iterator(const key_iterator& rhs) {
+  itr_ = rhs.itr_;
+}
+
+DictionaryValue::Iterator::Iterator(const DictionaryValue& target)
+    : target_(target),
+      it_(target.dictionary_.begin()) {}
+
+DictionaryValue* DictionaryValue::DeepCopy() const {
+  DictionaryValue* result = new DictionaryValue;
+
+  for (ValueMap::const_iterator current_entry(dictionary_.begin());
+       current_entry != dictionary_.end(); ++current_entry) {
+    result->SetWithoutPathExpansion(current_entry->first,
+                                    current_entry->second->DeepCopy());
+  }
+
+  return result;
+}
+
+bool DictionaryValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+
+  const DictionaryValue* other_dict =
+      static_cast<const DictionaryValue*>(other);
+  key_iterator lhs_it(begin_keys());
+  key_iterator rhs_it(other_dict->begin_keys());
+  while (lhs_it != end_keys() && rhs_it != other_dict->end_keys()) {
+    const Value* lhs;
+    const Value* rhs;
+    if (*lhs_it != *rhs_it ||
+        !GetWithoutPathExpansion(*lhs_it, &lhs) ||
+        !other_dict->GetWithoutPathExpansion(*rhs_it, &rhs) ||
+        !lhs->Equals(rhs)) {
+      return false;
+    }
+    ++lhs_it;
+    ++rhs_it;
+  }
+  if (lhs_it != end_keys() || rhs_it != other_dict->end_keys())
+    return false;
+
+  return true;
+}
+
+///////////////////// ListValue ////////////////////
+
+ListValue::ListValue() : Value(TYPE_LIST) {
+}
+
+ListValue::~ListValue() {
+  Clear();
+}
+
+void ListValue::Clear() {
+  for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i)
+    delete *i;
+  list_.clear();
+}
+
+bool ListValue::Set(size_t index, Value* in_value) {
+  if (!in_value)
+    return false;
+
+  if (index >= list_.size()) {
+    // Pad out any intermediate indexes with null settings
+    while (index > list_.size())
+      Append(CreateNullValue());
+    Append(in_value);
+  } else {
+    DCHECK(list_[index] != in_value);
+    delete list_[index];
+    list_[index] = in_value;
+  }
+  return true;
+}
+
+bool ListValue::Get(size_t index, const Value** out_value) const {
+  if (index >= list_.size())
+    return false;
+
+  if (out_value)
+    *out_value = list_[index];
+
+  return true;
+}
+
+bool ListValue::Get(size_t index, Value** out_value) {
+  return static_cast<const ListValue&>(*this).Get(
+      index,
+      const_cast<const Value**>(out_value));
+}
+
+bool ListValue::GetBoolean(size_t index, bool* bool_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsBoolean(bool_value);
+}
+
+bool ListValue::GetInteger(size_t index, int* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsInteger(out_value);
+}
+
+bool ListValue::GetDouble(size_t index, double* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsDouble(out_value);
+}
+
+bool ListValue::GetString(size_t index, std::string* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool ListValue::GetString(size_t index, string16* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool ListValue::GetBinary(size_t index, const BinaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(index, &value);
+  if (!result || !value->IsType(TYPE_BINARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const BinaryValue*>(value);
+
+  return true;
+}
+
+bool ListValue::GetBinary(size_t index, BinaryValue** out_value) {
+  return static_cast<const ListValue&>(*this).GetBinary(
+      index,
+      const_cast<const BinaryValue**>(out_value));
+}
+
+bool ListValue::GetDictionary(size_t index,
+                              const DictionaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(index, &value);
+  if (!result || !value->IsType(TYPE_DICTIONARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const DictionaryValue*>(value);
+
+  return true;
+}
+
+bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) {
+  return static_cast<const ListValue&>(*this).GetDictionary(
+      index,
+      const_cast<const DictionaryValue**>(out_value));
+}
+
+bool ListValue::GetList(size_t index, const ListValue** out_value) const {
+  const Value* value;
+  bool result = Get(index, &value);
+  if (!result || !value->IsType(TYPE_LIST))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const ListValue*>(value);
+
+  return true;
+}
+
+bool ListValue::GetList(size_t index, ListValue** out_value) {
+  return static_cast<const ListValue&>(*this).GetList(
+      index,
+      const_cast<const ListValue**>(out_value));
+}
+
+bool ListValue::Remove(size_t index, Value** out_value) {
+  if (index >= list_.size())
+    return false;
+
+  if (out_value)
+    *out_value = list_[index];
+  else
+    delete list_[index];
+
+  list_.erase(list_.begin() + index);
+  return true;
+}
+
+bool ListValue::Remove(const Value& value, size_t* index) {
+  for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) {
+    if ((*i)->Equals(&value)) {
+      size_t previous_index = i - list_.begin();
+      delete *i;
+      list_.erase(i);
+
+      if (index)
+        *index = previous_index;
+      return true;
+    }
+  }
+  return false;
+}
+
+void ListValue::Erase(iterator iter, Value** out_value) {
+  if (out_value)
+    *out_value = *iter;
+  else
+    delete *iter;
+
+  list_.erase(iter);
+}
+
+void ListValue::Append(Value* in_value) {
+  DCHECK(in_value);
+  list_.push_back(in_value);
+}
+
+void ListValue::AppendBoolean(bool in_value) {
+  Append(CreateBooleanValue(in_value));
+}
+
+void ListValue::AppendInteger(int in_value) {
+  Append(CreateIntegerValue(in_value));
+}
+
+void ListValue::AppendDouble(double in_value) {
+  Append(CreateDoubleValue(in_value));
+}
+
+void ListValue::AppendString(const std::string& in_value) {
+  Append(CreateStringValue(in_value));
+}
+
+void ListValue::AppendString(const string16& in_value) {
+  Append(CreateStringValue(in_value));
+}
+
+void ListValue::AppendStrings(const std::vector<std::string>& in_values) {
+  for (std::vector<std::string>::const_iterator it = in_values.begin();
+       it != in_values.end(); ++it) {
+    AppendString(*it);
+  }
+}
+
+void ListValue::AppendStrings(const std::vector<string16>& in_values) {
+  for (std::vector<string16>::const_iterator it = in_values.begin();
+       it != in_values.end(); ++it) {
+    AppendString(*it);
+  }
+}
+
+bool ListValue::AppendIfNotPresent(Value* in_value) {
+  DCHECK(in_value);
+  for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) {
+    if ((*i)->Equals(in_value)) {
+      delete in_value;
+      return false;
+    }
+  }
+  list_.push_back(in_value);
+  return true;
+}
+
+bool ListValue::Insert(size_t index, Value* in_value) {
+  DCHECK(in_value);
+  if (index > list_.size())
+    return false;
+
+  list_.insert(list_.begin() + index, in_value);
+  return true;
+}
+
+ListValue::const_iterator ListValue::Find(const Value& value) const {
+  return std::find_if(list_.begin(), list_.end(), ValueEquals(&value));
+}
+
+void ListValue::Swap(ListValue* other) {
+  list_.swap(other->list_);
+}
+
+bool ListValue::GetAsList(ListValue** out_value) {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+bool ListValue::GetAsList(const ListValue** out_value) const {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+ListValue* ListValue::DeepCopy() const {
+  ListValue* result = new ListValue;
+
+  for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i)
+    result->Append((*i)->DeepCopy());
+
+  return result;
+}
+
+bool ListValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+
+  const ListValue* other_list =
+      static_cast<const ListValue*>(other);
+  const_iterator lhs_it, rhs_it;
+  for (lhs_it = begin(), rhs_it = other_list->begin();
+       lhs_it != end() && rhs_it != other_list->end();
+       ++lhs_it, ++rhs_it) {
+    if (!(*lhs_it)->Equals(*rhs_it))
+      return false;
+  }
+  if (lhs_it != end() || rhs_it != other_list->end())
+    return false;
+
+  return true;
+}
+
+ValueSerializer::~ValueSerializer() {
+}
+
+std::ostream& operator<<(std::ostream& out, const Value& value) {
+  std::string json;
+  JSONWriter::WriteWithOptions(&value,
+                               JSONWriter::OPTIONS_PRETTY_PRINT,
+                               &json);
+  return out << json;
+}
+
+}  // namespace base
diff --git a/base/values.h b/base/values.h
new file mode 100644
index 0000000..d7263df
--- /dev/null
+++ b/base/values.h
@@ -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.
+
+// This file specifies a recursive data storage class called Value intended for
+// storing setting and other persistable data.  It includes the ability to
+// specify (recursive) lists and dictionaries, so it's fairly expressive.
+// However, the API is optimized for the common case, namely storing a
+// hierarchical tree of simple values.  Given a DictionaryValue root, you can
+// easily do things like:
+//
+// root->SetString("global.pages.homepage", "http://goateleporter.com");
+// std::string homepage = "http://google.com";  // default/fallback value
+// root->GetString("global.pages.homepage", &homepage);
+//
+// where "global" and "pages" are also DictionaryValues, and "homepage" is a
+// string setting.  If some elements of the path didn't exist yet, the
+// SetString() method would create the missing elements and attach them to root
+// before attaching the homepage value.
+
+#ifndef BASE_VALUES_H_
+#define BASE_VALUES_H_
+
+#include <iterator>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/string16.h"
+
+// This file declares "using base::Value", etc. at the bottom, so that
+// current code can use these classes without the base namespace. In
+// new code, please always use base::Value, etc. or add your own
+// "using" declaration.
+// http://crbug.com/88666
+namespace base {
+
+class BinaryValue;
+class DictionaryValue;
+class FundamentalValue;
+class ListValue;
+class StringValue;
+class Value;
+
+typedef std::vector<Value*> ValueVector;
+typedef std::map<std::string, Value*> ValueMap;
+
+// The Value class is the base class for Values. A Value can be instantiated
+// via the Create*Value() factory methods, or by directly creating instances of
+// the subclasses.
+class BASE_EXPORT Value {
+ public:
+  enum Type {
+    TYPE_NULL = 0,
+    TYPE_BOOLEAN,
+    TYPE_INTEGER,
+    TYPE_DOUBLE,
+    TYPE_STRING,
+    TYPE_BINARY,
+    TYPE_DICTIONARY,
+    TYPE_LIST
+  };
+
+  virtual ~Value();
+
+  // Convenience methods for creating Value objects for various
+  // kinds of values without thinking about which class implements them.
+  // These can always be expected to return a valid Value*.
+  static Value* CreateNullValue();
+  static FundamentalValue* CreateBooleanValue(bool in_value);
+  static FundamentalValue* CreateIntegerValue(int in_value);
+  static FundamentalValue* CreateDoubleValue(double in_value);
+  static StringValue* CreateStringValue(const std::string& in_value);
+  static StringValue* CreateStringValue(const string16& in_value);
+
+  // 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 settings.
+  // If the current setting 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 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;
+
+  // 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;
+
+  // 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:
+  // This isn't safe for end-users (they should use the Create*Value()
+  // static methods above), but it's useful for subclasses.
+  explicit Value(Type type);
+
+ private:
+  Value();
+
+  Type type_;
+
+  DISALLOW_COPY_AND_ASSIGN(Value);
+};
+
+// 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);
+  virtual ~FundamentalValue();
+
+  // Overridden from Value:
+  virtual bool GetAsBoolean(bool* out_value) const OVERRIDE;
+  virtual bool GetAsInteger(int* out_value) const OVERRIDE;
+  virtual bool GetAsDouble(double* out_value) const OVERRIDE;
+  virtual FundamentalValue* DeepCopy() const OVERRIDE;
+  virtual bool Equals(const Value* other) const OVERRIDE;
+
+ private:
+  union {
+    bool boolean_value_;
+    int integer_value_;
+    double double_value_;
+  };
+
+  DISALLOW_COPY_AND_ASSIGN(FundamentalValue);
+};
+
+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);
+
+  virtual ~StringValue();
+
+  // Overridden from Value:
+  virtual bool GetAsString(std::string* out_value) const OVERRIDE;
+  virtual bool GetAsString(string16* out_value) const OVERRIDE;
+  virtual StringValue* DeepCopy() const OVERRIDE;
+  virtual bool Equals(const Value* other) const OVERRIDE;
+
+ private:
+  std::string value_;
+
+  DISALLOW_COPY_AND_ASSIGN(StringValue);
+};
+
+class BASE_EXPORT BinaryValue: public Value {
+ public:
+  virtual ~BinaryValue();
+
+  // Creates a Value to represent a binary buffer.  The new object takes
+  // ownership of the pointer passed in, if successful.
+  // Returns NULL if buffer is NULL.
+  static BinaryValue* Create(char* buffer, size_t size);
+
+  // 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.
+  // Returns NULL if buffer is NULL.
+  static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size);
+
+  size_t GetSize() const { return size_; }
+  char* GetBuffer() { return buffer_; }
+  const char* GetBuffer() const { return buffer_; }
+
+  // Overridden from Value:
+  virtual BinaryValue* DeepCopy() const OVERRIDE;
+  virtual bool Equals(const Value* other) const OVERRIDE;
+
+ private:
+  // Constructor is private so that only objects with valid buffer pointers
+  // and size values can be created.
+  BinaryValue(char* buffer, size_t size);
+
+  char* buffer_;
+  size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(BinaryValue);
+};
+
+// DictionaryValue provides a key-value dictionary with (optional) "path"
+// parsing for recursive access; see the comment at the top of the file. Keys
+// are |std::string|s and should be UTF-8 encoded.
+class BASE_EXPORT DictionaryValue : public Value {
+ public:
+  DictionaryValue();
+  virtual ~DictionaryValue();
+
+  // Overridden from Value:
+  virtual bool GetAsDictionary(DictionaryValue** out_value) OVERRIDE;
+  virtual 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.
+  // Note that the dictionary takes ownership of the value referenced by
+  // |in_value|, and therefore |in_value| must be non-NULL.
+  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, 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.
+  bool Get(const std::string& path, const Value** out_value) const;
+  bool Get(const std::string& path, Value** out_value);
+
+  // These are convenience forms of Get().  The value will be retrieved
+  // and the return value will be true if the path is valid and the value at
+  // the end of the path can be returned in the form specified.
+  bool GetBoolean(const std::string& path, bool* out_value) const;
+  bool GetInteger(const std::string& path, int* out_value) const;
+  bool GetDouble(const std::string& path, double* out_value) const;
+  bool GetString(const std::string& path, std::string* out_value) const;
+  bool GetString(const std::string& path, string16* out_value) const;
+  bool GetStringASCII(const std::string& path, std::string* out_value) const;
+  bool GetBinary(const std::string& path, const BinaryValue** out_value) const;
+  bool GetBinary(const std::string& path, BinaryValue** out_value);
+  bool GetDictionary(const std::string& path,
+                     const DictionaryValue** out_value) const;
+  bool GetDictionary(const std::string& path, DictionaryValue** out_value);
+  bool GetList(const std::string& path, const ListValue** out_value) const;
+  bool GetList(const std::string& path, ListValue** out_value);
+
+  // Like Get(), but without special treatment of '.'.  This allows e.g. URLs to
+  // be used as paths.
+  bool GetWithoutPathExpansion(const std::string& key,
+                               const Value** out_value) const;
+  bool GetWithoutPathExpansion(const std::string& key, Value** out_value);
+  bool GetBooleanWithoutPathExpansion(const std::string& key,
+                                      bool* out_value) const;
+  bool GetIntegerWithoutPathExpansion(const std::string& key,
+                                      int* out_value) const;
+  bool GetDoubleWithoutPathExpansion(const std::string& key,
+                                     double* out_value) const;
+  bool GetStringWithoutPathExpansion(const std::string& key,
+                                     std::string* out_value) const;
+  bool GetStringWithoutPathExpansion(const std::string& key,
+                                     string16* out_value) const;
+  bool GetDictionaryWithoutPathExpansion(
+      const std::string& key,
+      const DictionaryValue** out_value) const;
+  bool GetDictionaryWithoutPathExpansion(const std::string& key,
+                                         DictionaryValue** out_value);
+  bool GetListWithoutPathExpansion(const std::string& key,
+                                   const ListValue** out_value) const;
+  bool GetListWithoutPathExpansion(const std::string& key,
+                                   ListValue** out_value);
+
+  // Removes the Value with the specified path from this dictionary (or one
+  // of its child dictionaries, if the path is more than just a local key).
+  // If |out_value| is non-NULL, the removed Value 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 |path| is a valid path; otherwise
+  // it will return false and the DictionaryValue object will be unchanged.
+  virtual bool Remove(const std::string& path, 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,
+                                          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.
+  DictionaryValue* DeepCopyWithoutEmptyChildren();
+
+  // 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 for the keys in the dictionary.
+  // It can't be used to modify the dictionary.
+  //
+  // YOU SHOULD ALWAYS USE THE XXXWithoutPathExpansion() APIs WITH THESE, NOT
+  // THE NORMAL XXX() APIs.  This makes sure things will work correctly if any
+  // keys have '.'s in them.
+  class BASE_EXPORT key_iterator
+      : private std::iterator<std::input_iterator_tag, const std::string> {
+   public:
+    explicit key_iterator(ValueMap::const_iterator itr);
+    // Not explicit, because this is a copy constructor.
+    key_iterator(const key_iterator& rhs);
+    key_iterator operator++() {
+      ++itr_;
+      return *this;
+    }
+    const std::string& operator*() { return itr_->first; }
+    bool operator!=(const key_iterator& other) { return itr_ != other.itr_; }
+    bool operator==(const key_iterator& other) { return itr_ == other.itr_; }
+
+   private:
+    ValueMap::const_iterator itr_;
+  };
+
+  key_iterator begin_keys() const { return key_iterator(dictionary_.begin()); }
+  key_iterator end_keys() const { return key_iterator(dictionary_.end()); }
+
+  // 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);
+
+    bool HasNext() const { return it_ != target_.dictionary_.end(); }
+    void Advance() { ++it_; }
+
+    const std::string& key() const { return it_->first; }
+    const Value& value() const { return *it_->second; }
+
+   private:
+    const DictionaryValue& target_;
+    ValueMap::const_iterator it_;
+  };
+
+  // Overridden from Value:
+  virtual DictionaryValue* DeepCopy() const OVERRIDE;
+  virtual bool Equals(const Value* other) const OVERRIDE;
+
+ private:
+  ValueMap dictionary_;
+
+  DISALLOW_COPY_AND_ASSIGN(DictionaryValue);
+};
+
+// This type of Value represents a list of other Value values.
+class BASE_EXPORT ListValue : public Value {
+ public:
+  typedef ValueVector::iterator iterator;
+  typedef ValueVector::const_iterator const_iterator;
+
+  ListValue();
+  virtual ~ListValue();
+
+  // 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);
+
+  // 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|.
+  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.
+  bool GetBoolean(size_t index, bool* out_value) const;
+  bool GetInteger(size_t index, int* out_value) const;
+  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, 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.
+  void Erase(iterator iter, Value** out_value);
+
+  // Appends a Value to the end of the list.
+  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:
+  virtual bool GetAsList(ListValue** out_value) OVERRIDE;
+  virtual bool GetAsList(const ListValue** out_value) const OVERRIDE;
+  virtual ListValue* DeepCopy() const OVERRIDE;
+  virtual bool Equals(const Value* other) const OVERRIDE;
+
+ private:
+  ValueVector list_;
+
+  DISALLOW_COPY_AND_ASSIGN(ListValue);
+};
+
+// This interface is implemented by classes that know how to serialize and
+// deserialize Value objects.
+class BASE_EXPORT ValueSerializer {
+ public:
+  virtual ~ValueSerializer();
+
+  virtual bool Serialize(const Value& root) = 0;
+
+  // This method deserializes the subclass-specific format into a Value object.
+  // If the return value is non-NULL, the caller takes ownership of returned
+  // Value. If the return value is NULL, and if error_code is non-NULL,
+  // error_code will be set with the underlying error.
+  // If |error_message| is non-null, it will be filled in with a formatted
+  // error message including the location of the error if appropriate.
+  virtual Value* Deserialize(int* error_code, std::string* error_str) = 0;
+};
+
+// Stream operator so Values can be used in assertion statements.
+BASE_EXPORT std::ostream& operator<<(std::ostream& out, const Value& value);
+
+}  // namespace base
+
+// http://crbug.com/88666
+using base::DictionaryValue;
+using base::ListValue;
+using base::StringValue;
+using base::Value;
+
+#endif  // BASE_VALUES_H_
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
new file mode 100644
index 0000000..9b92949
--- /dev/null
+++ b/base/values_unittest.cc
@@ -0,0 +1,789 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(ValuesTest, Basic) {
+  // Test basic dictionary getting/setting
+  DictionaryValue settings;
+  std::string homepage = "http://google.com";
+  ASSERT_FALSE(settings.GetString("global.homepage", &homepage));
+  ASSERT_EQ(std::string("http://google.com"), homepage);
+
+  ASSERT_FALSE(settings.Get("global", NULL));
+  settings.Set("global", Value::CreateBooleanValue(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));
+
+  toolbar_bookmarks = new ListValue;
+  settings.Set("global.toolbar.bookmarks", toolbar_bookmarks);
+  ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
+
+  DictionaryValue* new_bookmark = new DictionaryValue;
+  new_bookmark->SetString("name", "Froogle");
+  new_bookmark->SetString("url", "http://froogle.com");
+  toolbar_bookmarks->Append(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) {
+  scoped_ptr<ListValue> mixed_list(new ListValue());
+  mixed_list->Set(0, Value::CreateBooleanValue(true));
+  mixed_list->Set(1, Value::CreateIntegerValue(42));
+  mixed_list->Set(2, Value::CreateDoubleValue(88.8));
+  mixed_list->Set(3, Value::CreateStringValue("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.
+  scoped_ptr<Value> sought_value(Value::CreateIntegerValue(42));
+  scoped_ptr<Value> not_found_value(Value::CreateBooleanValue(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) {
+  char* buffer = NULL;
+  // Passing a null buffer pointer doesn't yield a BinaryValue
+  scoped_ptr<BinaryValue> binary(BinaryValue::Create(buffer, 0));
+  ASSERT_FALSE(binary.get());
+
+  // If you want to represent an empty binary value, use a zero-length buffer.
+  buffer = new char[1];
+  ASSERT_TRUE(buffer);
+  binary.reset(BinaryValue::Create(buffer, 0));
+  ASSERT_TRUE(binary.get());
+  ASSERT_TRUE(binary->GetBuffer());
+  ASSERT_EQ(buffer, binary->GetBuffer());
+  ASSERT_EQ(0U, binary->GetSize());
+
+  // Test the common case of a non-empty buffer
+  buffer = new char[15];
+  binary.reset(BinaryValue::Create(buffer, 15));
+  ASSERT_TRUE(binary.get());
+  ASSERT_TRUE(binary->GetBuffer());
+  ASSERT_EQ(buffer, binary->GetBuffer());
+  ASSERT_EQ(15U, binary->GetSize());
+
+  char stack_buffer[42];
+  memset(stack_buffer, '!', 42);
+  binary.reset(BinaryValue::CreateWithCopiedBuffer(stack_buffer, 42));
+  ASSERT_TRUE(binary.get());
+  ASSERT_TRUE(binary->GetBuffer());
+  ASSERT_NE(stack_buffer, binary->GetBuffer());
+  ASSERT_EQ(42U, binary->GetSize());
+  ASSERT_EQ(0, memcmp(stack_buffer, binary->GetBuffer(), binary->GetSize()));
+}
+
+TEST(ValuesTest, StringValue) {
+  // Test overloaded CreateStringValue.
+  scoped_ptr<Value> narrow_value(Value::CreateStringValue("narrow"));
+  ASSERT_TRUE(narrow_value.get());
+  ASSERT_TRUE(narrow_value->IsType(Value::TYPE_STRING));
+  scoped_ptr<Value> utf16_value(
+      Value::CreateStringValue(ASCIIToUTF16("utf16")));
+  ASSERT_TRUE(utf16_value.get());
+  ASSERT_TRUE(utf16_value->IsType(Value::TYPE_STRING));
+
+  // Test overloaded GetString.
+  std::string narrow = "http://google.com";
+  string16 utf16 = ASCIIToUTF16("http://google.com");
+  ASSERT_TRUE(narrow_value->GetAsString(&narrow));
+  ASSERT_TRUE(narrow_value->GetAsString(&utf16));
+  ASSERT_EQ(std::string("narrow"), narrow);
+  ASSERT_EQ(ASCIIToUTF16("narrow"), utf16);
+
+  ASSERT_TRUE(utf16_value->GetAsString(&narrow));
+  ASSERT_TRUE(utf16_value->GetAsString(&utf16));
+  ASSERT_EQ(std::string("utf16"), narrow);
+  ASSERT_EQ(ASCIIToUTF16("utf16"), utf16);
+}
+
+// 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;
+  }
+
+  virtual ~DeletionTestValue() {
+    *deletion_flag_ = true;
+  }
+
+ private:
+  bool* deletion_flag_;
+};
+
+TEST(ValuesTest, ListDeletion) {
+  bool deletion_flag = true;
+
+  {
+    ListValue list;
+    list.Append(new DeletionTestValue(&deletion_flag));
+    EXPECT_FALSE(deletion_flag);
+  }
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    ListValue list;
+    list.Append(new DeletionTestValue(&deletion_flag));
+    EXPECT_FALSE(deletion_flag);
+    list.Clear();
+    EXPECT_TRUE(deletion_flag);
+  }
+
+  {
+    ListValue list;
+    list.Append(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;
+  Value* removed_item = NULL;
+
+  {
+    ListValue list;
+    list.Append(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);
+  delete removed_item;
+  removed_item = NULL;
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    ListValue list;
+    list.Append(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;
+    DeletionTestValue* value = new DeletionTestValue(&deletion_flag);
+    list.Append(value);
+    EXPECT_FALSE(deletion_flag);
+    size_t index = 0;
+    list.Remove(*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, new DeletionTestValue(&deletion_flag));
+    EXPECT_FALSE(deletion_flag);
+  }
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, new DeletionTestValue(&deletion_flag));
+    EXPECT_FALSE(deletion_flag);
+    dict.Clear();
+    EXPECT_TRUE(deletion_flag);
+  }
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, 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;
+  Value* removed_item = NULL;
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, 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);
+  delete removed_item;
+  removed_item = NULL;
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, 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());
+}
+
+TEST(ValuesTest, DeepCopy) {
+  DictionaryValue original_dict;
+  Value* original_null = Value::CreateNullValue();
+  original_dict.Set("null", original_null);
+  FundamentalValue* original_bool = Value::CreateBooleanValue(true);
+  original_dict.Set("bool", original_bool);
+  FundamentalValue* original_int = Value::CreateIntegerValue(42);
+  original_dict.Set("int", original_int);
+  FundamentalValue* original_double = Value::CreateDoubleValue(3.14);
+  original_dict.Set("double", original_double);
+  StringValue* original_string = Value::CreateStringValue("hello");
+  original_dict.Set("string", original_string);
+  StringValue* original_string16 =
+      Value::CreateStringValue(ASCIIToUTF16("hello16"));
+  original_dict.Set("string16", original_string16);
+
+  char* original_buffer = new char[42];
+  memset(original_buffer, '!', 42);
+  BinaryValue* original_binary = BinaryValue::Create(original_buffer, 42);
+  original_dict.Set("binary", original_binary);
+
+  ListValue* original_list = new ListValue();
+  FundamentalValue* original_list_element_0 = Value::CreateIntegerValue(0);
+  original_list->Append(original_list_element_0);
+  FundamentalValue* original_list_element_1 = Value::CreateIntegerValue(1);
+  original_list->Append(original_list_element_1);
+  original_dict.Set("list", original_list);
+
+  DictionaryValue* original_nested_dictionary = new DictionaryValue();
+  original_nested_dictionary->Set("key", Value::CreateStringValue("value"));
+  original_dict.Set("dictionary", original_nested_dictionary);
+
+  scoped_ptr<DictionaryValue> copy_dict(original_dict.DeepCopy());
+  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) {
+  Value* null1 = Value::CreateNullValue();
+  Value* null2 = Value::CreateNullValue();
+  EXPECT_NE(null1, null2);
+  EXPECT_TRUE(null1->Equals(null2));
+
+  Value* boolean = Value::CreateBooleanValue(false);
+  EXPECT_FALSE(null1->Equals(boolean));
+  delete null1;
+  delete null2;
+  delete boolean;
+
+  DictionaryValue dv;
+  dv.SetBoolean("a", false);
+  dv.SetInteger("b", 2);
+  dv.SetDouble("c", 2.5);
+  dv.SetString("d1", "string");
+  dv.SetString("d2", ASCIIToUTF16("http://google.com"));
+  dv.Set("e", Value::CreateNullValue());
+
+  scoped_ptr<DictionaryValue> copy;
+  copy.reset(dv.DeepCopy());
+  EXPECT_TRUE(dv.Equals(copy.get()));
+
+  ListValue* list = new ListValue;
+  list->Append(Value::CreateNullValue());
+  list->Append(new DictionaryValue);
+  dv.Set("f", list);
+
+  EXPECT_FALSE(dv.Equals(copy.get()));
+  copy->Set("f", list->DeepCopy());
+  EXPECT_TRUE(dv.Equals(copy.get()));
+
+  list->Append(Value::CreateBooleanValue(true));
+  EXPECT_FALSE(dv.Equals(copy.get()));
+
+  // Check if Equals detects differences in only the keys.
+  copy.reset(dv.DeepCopy());
+  EXPECT_TRUE(dv.Equals(copy.get()));
+  copy->Remove("a", NULL);
+  copy->SetBoolean("aa", false);
+  EXPECT_FALSE(dv.Equals(copy.get()));
+}
+
+TEST(ValuesTest, StaticEquals) {
+  scoped_ptr<Value> null1(Value::CreateNullValue());
+  scoped_ptr<Value> null2(Value::CreateNullValue());
+  EXPECT_TRUE(Value::Equals(null1.get(), null2.get()));
+  EXPECT_TRUE(Value::Equals(NULL, NULL));
+
+  scoped_ptr<Value> i42(Value::CreateIntegerValue(42));
+  scoped_ptr<Value> j42(Value::CreateIntegerValue(42));
+  scoped_ptr<Value> i17(Value::CreateIntegerValue(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;
+  Value* original_null = Value::CreateNullValue();
+  original_dict.Set("null", original_null);
+  FundamentalValue* original_bool = Value::CreateBooleanValue(true);
+  original_dict.Set("bool", original_bool);
+  FundamentalValue* original_int = Value::CreateIntegerValue(42);
+  original_dict.Set("int", original_int);
+  FundamentalValue* original_double = Value::CreateDoubleValue(3.14);
+  original_dict.Set("double", original_double);
+  StringValue* original_string = Value::CreateStringValue("hello");
+  original_dict.Set("string", original_string);
+  StringValue* original_string16 =
+      Value::CreateStringValue(ASCIIToUTF16("hello16"));
+  original_dict.Set("string16", original_string16);
+
+  char* original_buffer = new char[42];
+  memset(original_buffer, '!', 42);
+  BinaryValue* original_binary = BinaryValue::Create(original_buffer, 42);
+  original_dict.Set("binary", original_binary);
+
+  ListValue* original_list = new ListValue();
+  FundamentalValue* original_list_element_0 = Value::CreateIntegerValue(0);
+  original_list->Append(original_list_element_0);
+  FundamentalValue* original_list_element_1 = Value::CreateIntegerValue(1);
+  original_list->Append(original_list_element_1);
+  original_dict.Set("list", original_list);
+
+  Value* original_dict_value = &original_dict;
+  Value* original_bool_value = original_bool;
+  Value* original_int_value = original_int;
+  Value* original_double_value = original_double;
+  Value* original_string_value = original_string;
+  Value* original_string16_value = original_string16;
+  Value* original_binary_value = original_binary;
+  Value* original_list_value = original_list;
+
+  scoped_ptr<Value> copy_dict_value(original_dict_value->DeepCopy());
+  scoped_ptr<Value> copy_bool_value(original_bool_value->DeepCopy());
+  scoped_ptr<Value> copy_int_value(original_int_value->DeepCopy());
+  scoped_ptr<Value> copy_double_value(original_double_value->DeepCopy());
+  scoped_ptr<Value> copy_string_value(original_string_value->DeepCopy());
+  scoped_ptr<Value> copy_string16_value(original_string16_value->DeepCopy());
+  scoped_ptr<Value> copy_binary_value(original_binary_value->DeepCopy());
+  scoped_ptr<Value> copy_list_value(original_list_value->DeepCopy());
+
+  EXPECT_TRUE(original_dict_value->Equals(copy_dict_value.get()));
+  EXPECT_TRUE(original_bool_value->Equals(copy_bool_value.get()));
+  EXPECT_TRUE(original_int_value->Equals(copy_int_value.get()));
+  EXPECT_TRUE(original_double_value->Equals(copy_double_value.get()));
+  EXPECT_TRUE(original_string_value->Equals(copy_string_value.get()));
+  EXPECT_TRUE(original_string16_value->Equals(copy_string16_value.get()));
+  EXPECT_TRUE(original_binary_value->Equals(copy_binary_value.get()));
+  EXPECT_TRUE(original_list_value->Equals(copy_list_value.get()));
+}
+
+TEST(ValuesTest, RemoveEmptyChildren) {
+  scoped_ptr<DictionaryValue> root(new DictionaryValue);
+  // Remove empty lists and dictionaries.
+  root->Set("empty_dict", new DictionaryValue);
+  root->Set("empty_list", new ListValue);
+  root->SetWithoutPathExpansion("a.b.c.d.e", new DictionaryValue);
+  root.reset(root->DeepCopyWithoutEmptyChildren());
+  EXPECT_TRUE(root->empty());
+
+  // Make sure we don't prune too much.
+  root->SetBoolean("bool", true);
+  root->Set("empty_dict", new DictionaryValue);
+  root->SetString("empty_string", "");
+  root.reset(root->DeepCopyWithoutEmptyChildren());
+  EXPECT_EQ(2U, root->size());
+
+  // Should do nothing.
+  root.reset(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", new DictionaryValue);
+    root.reset(root->DeepCopyWithoutEmptyChildren());
+    EXPECT_EQ(2U, root->size());
+  }
+  {
+    DictionaryValue* inner = new DictionaryValue;
+    root->Set("dict_with_emtpy_children", inner);
+    inner->Set("empty_dict", new DictionaryValue);
+    inner->Set("empty_list", new ListValue);
+    root.reset(root->DeepCopyWithoutEmptyChildren());
+    EXPECT_EQ(2U, root->size());
+  }
+  {
+    ListValue* inner = new ListValue;
+    root->Set("list_with_empty_children", inner);
+    inner->Append(new DictionaryValue);
+    inner->Append(new ListValue);
+    root.reset(root->DeepCopyWithoutEmptyChildren());
+    EXPECT_EQ(2U, root->size());
+  }
+
+  // Nested with siblings.
+  {
+    ListValue* inner = new ListValue;
+    root->Set("list_with_empty_children", inner);
+    inner->Append(new DictionaryValue);
+    inner->Append(new ListValue);
+    DictionaryValue* inner2 = new DictionaryValue;
+    root->Set("dict_with_empty_children", inner2);
+    inner2->Set("empty_dict", new DictionaryValue);
+    inner2->Set("empty_list", new ListValue);
+    root.reset(root->DeepCopyWithoutEmptyChildren());
+    EXPECT_EQ(2U, root->size());
+  }
+
+  // Make sure nested values don't get pruned.
+  {
+    ListValue* inner = new ListValue;
+    root->Set("list_with_empty_children", inner);
+    ListValue* inner2 = new ListValue;
+    inner->Append(new DictionaryValue);
+    inner->Append(inner2);
+    inner2->Append(Value::CreateStringValue("hello"));
+    root.reset(root->DeepCopyWithoutEmptyChildren());
+    EXPECT_EQ(3U, root->size());
+    EXPECT_TRUE(root->GetList("list_with_empty_children", &inner));
+    EXPECT_EQ(1U, inner->GetSize());  // Dictionary was pruned.
+    EXPECT_TRUE(inner->GetList(0, &inner2));
+    EXPECT_EQ(1U, inner2->GetSize());
+  }
+}
+
+TEST(ValuesTest, MergeDictionary) {
+  scoped_ptr<DictionaryValue> base(new DictionaryValue);
+  base->SetString("base_key", "base_key_value_base");
+  base->SetString("collide_key", "collide_key_value_base");
+  DictionaryValue* base_sub_dict = new DictionaryValue;
+  base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base");
+  base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base");
+  base->Set("sub_dict_key", base_sub_dict);
+
+  scoped_ptr<DictionaryValue> merge(new DictionaryValue);
+  merge->SetString("merge_key", "merge_key_value_merge");
+  merge->SetString("collide_key", "collide_key_value_merge");
+  DictionaryValue* merge_sub_dict = new DictionaryValue;
+  merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge");
+  merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge");
+  merge->Set("sub_dict_key", merge_sub_dict);
+
+  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) {
+  DictionaryValue* child = new DictionaryValue;
+  child->SetString("test", "value");
+  EXPECT_EQ(1U, child->size());
+
+  std::string value;
+  EXPECT_TRUE(child->GetString("test", &value));
+  EXPECT_EQ("value", value);
+
+  scoped_ptr<DictionaryValue> base(new DictionaryValue);
+  base->Set("dict", child);
+  EXPECT_EQ(1U, base->size());
+
+  DictionaryValue* ptr;
+  EXPECT_TRUE(base->GetDictionary("dict", &ptr));
+  EXPECT_EQ(child, ptr);
+
+  scoped_ptr<DictionaryValue> merged(new DictionaryValue);
+  merged->MergeDictionary(base.get());
+  EXPECT_EQ(1U, merged->size());
+  EXPECT_TRUE(merged->GetDictionary("dict", &ptr));
+  EXPECT_NE(child, ptr);
+  EXPECT_TRUE(ptr->GetString("test", &value));
+  EXPECT_EQ("value", value);
+
+  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.HasNext(); it.Advance()) {
+    ADD_FAILURE();
+  }
+
+  StringValue value1("value1");
+  dict.Set("key1", value1.DeepCopy());
+  bool seen1 = false;
+  for (DictionaryValue::Iterator it(dict); it.HasNext(); 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.DeepCopy());
+  bool seen2 = seen1 = false;
+  for (DictionaryValue::Iterator it(dict); it.HasNext(); 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);
+}
+
+}  // namespace base
diff --git a/base/version.cc b/base/version.cc
new file mode 100644
index 0000000..b7db4b5
--- /dev/null
+++ b/base/version.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/version.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+
+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<uint16>* parsed) {
+  std::vector<std::string> numbers;
+  base::SplitString(version_str, '.', &numbers);
+  if (numbers.empty())
+    return false;
+
+  for (std::vector<std::string>::const_iterator it = numbers.begin();
+       it != numbers.end(); ++it) {
+    int num;
+    if (!base::StringToInt(*it, &num))
+      return false;
+
+    if (num < 0)
+      return false;
+
+    const uint16 max = 0xFFFF;
+    if (num > max)
+      return false;
+
+    // This throws out things like +3, or 032.
+    if (base::IntToString(num) != *it)
+      return false;
+
+    parsed->push_back(static_cast<uint16>(num));
+  }
+  return true;
+}
+
+// Compares version components in |components1| with components in
+// |components2|. Returns -1, 0 or 1 if |components1| is greater than, equal to,
+// or less than |components2|, respectively.
+int CompareVersionComponents(const std::vector<uint16>& components1,
+                             const std::vector<uint16>& components2) {
+  const size_t count = std::min(components1.size(), components2.size());
+  for (size_t i = 0; i < count; ++i) {
+    if (components1[i] > components2[i])
+      return 1;
+    if (components1[i] < components2[i])
+      return -1;
+  }
+  if (components1.size() > components2.size()) {
+    for (size_t i = count; i < components1.size(); ++i) {
+      if (components1[i] > 0)
+        return 1;
+    }
+  } else if (components1.size() < components2.size()) {
+    for (size_t i = count; i < components2.size(); ++i) {
+      if (components2[i] > 0)
+        return -1;
+    }
+  }
+  return 0;
+}
+
+}  // namespace
+
+Version::Version() {
+}
+
+Version::~Version() {
+}
+
+Version::Version(const std::string& version_str) {
+  std::vector<uint16> parsed;
+  if (!ParseVersionNumbers(version_str, &parsed))
+    return;
+
+  components_.swap(parsed);
+}
+
+bool Version::IsValid() const {
+  return (!components_.empty());
+}
+
+// static
+bool Version::IsValidWildcardString(const std::string& wildcard_string) {
+  std::string version_string = wildcard_string;
+  if (EndsWith(wildcard_string.c_str(), ".*", false))
+    version_string = wildcard_string.substr(0, wildcard_string.size() - 2);
+
+  Version version(version_string);
+  return version.IsValid();
+}
+
+bool Version::IsOlderThan(const std::string& version_str) const {
+  Version proposed_ver(version_str);
+  if (!proposed_ver.IsValid())
+    return false;
+  return (CompareTo(proposed_ver) < 0);
+}
+
+int Version::CompareToWildcardString(const std::string& wildcard_string) const {
+  DCHECK(IsValid());
+  DCHECK(Version::IsValidWildcardString(wildcard_string));
+
+  // Default behavior if the string doesn't end with a wildcard.
+  if (!EndsWith(wildcard_string.c_str(), ".*", false)) {
+    Version version(wildcard_string);
+    DCHECK(version.IsValid());
+    return CompareTo(version);
+  }
+
+  std::vector<uint16> parsed;
+  const bool success = ParseVersionNumbers(
+      wildcard_string.substr(0, wildcard_string.length() - 2), &parsed);
+  DCHECK(success);
+  const int comparison = CompareVersionComponents(components_, parsed);
+  // If the version is smaller than the wildcard version's |parsed| vector,
+  // then the wildcard has no effect (e.g. comparing 1.2.3 and 1.3.*) and the
+  // version is still smaller. Same logic for equality (e.g. comparing 1.2.2 to
+  // 1.2.2.* is 0 regardless of the wildcard). Under this logic,
+  // 1.2.0.0.0.0 compared to 1.2.* is 0.
+  if (comparison == -1 || comparison == 0)
+    return comparison;
+
+  // Catch the case where the digits of |parsed| are found in |components_|,
+  // which means that the two are equal since |parsed| has a trailing "*".
+  // (e.g. 1.2.3 vs. 1.2.* will return 0). All other cases return 1 since
+  // components is greater (e.g. 3.2.3 vs 1.*).
+  DCHECK_GT(parsed.size(), 0UL);
+  const size_t min_num_comp = std::min(components_.size(), parsed.size());
+  for (size_t i = 0; i < min_num_comp; ++i) {
+    if (components_[i] != parsed[i])
+      return 1;
+  }
+  return 0;
+}
+
+bool Version::Equals(const Version& that) const {
+  DCHECK(IsValid());
+  DCHECK(that.IsValid());
+  return (CompareTo(that) == 0);
+}
+
+int Version::CompareTo(const Version& other) const {
+  DCHECK(IsValid());
+  DCHECK(other.IsValid());
+  return CompareVersionComponents(components_, other.components_);
+}
+
+const std::string Version::GetString() const {
+  DCHECK(IsValid());
+  std::string version_str;
+  size_t count = components_.size();
+  for (size_t i = 0; i < count - 1; ++i) {
+    version_str.append(base::IntToString(components_[i]));
+    version_str.append(".");
+  }
+  version_str.append(base::IntToString(components_[count - 1]));
+  return version_str;
+}
diff --git a/base/version.h b/base/version.h
new file mode 100644
index 0000000..ab7145e
--- /dev/null
+++ b/base/version.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 BASE_VERSION_H_
+#define BASE_VERSION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+// Version represents a dotted version number, like "1.2.3.4", supporting
+// parsing and comparison.
+class BASE_EXPORT Version {
+ public:
+  // The only thing you can legally do to a default constructed
+  // Version object is assign to it.
+  Version();
+
+  ~Version();
+
+  // Initializes from a decimal dotted version number, like "0.1.1".
+  // Each component is limited to a uint16. Call IsValid() to learn
+  // the outcome.
+  explicit Version(const std::string& version_str);
+
+  // Returns true if the object contains a valid version number.
+  bool IsValid() const;
+
+  // Returns true if the version wildcard string is valid. The version wildcard
+  // string may end with ".*" (e.g. 1.2.*, 1.*). Any other arrangement with "*"
+  // is invalid (e.g. 1.*.3 or 1.2.3*). This functions defaults to standard
+  // Version behavior (IsValid) if no wildcard is present.
+  static bool IsValidWildcardString(const std::string& wildcard_string);
+
+  // Commonly used pattern. Given a valid version object, compare if a
+  // |version_str| results in a newer version. Returns true if the
+  // string represents valid version and if the version is greater than
+  // than the version of this object.
+  bool IsOlderThan(const std::string& version_str) const;
+
+  bool Equals(const Version& other) const;
+
+  // Returns -1, 0, 1 for <, ==, >.
+  int CompareTo(const Version& other) const;
+
+  // Given a valid version object, compare if a |wildcard_string| results in a
+  // newer version. This function will default to CompareTo if the string does
+  // not end in wildcard sequence ".*". IsValidWildcard(wildcard_string) must be
+  // true before using this function.
+  int CompareToWildcardString(const std::string& wildcard_string) const;
+
+  // Return the string representation of this version.
+  const std::string GetString() const;
+
+  const std::vector<uint16>& components() const { return components_; }
+
+ private:
+  std::vector<uint16> components_;
+};
+
+#endif  // BASE_VERSION_H_
diff --git a/base/version_unittest.cc b/base/version_unittest.cc
new file mode 100644
index 0000000..15f3052
--- /dev/null
+++ b/base/version_unittest.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "base/version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class VersionTest : public testing::Test {
+};
+
+TEST_F(VersionTest, DefaultConstructor) {
+  Version v;
+  EXPECT_FALSE(v.IsValid());
+}
+
+TEST_F(VersionTest, ValueSemantics) {
+  Version v1("1.2.3.4");
+  EXPECT_TRUE(v1.IsValid());
+  Version v3;
+  EXPECT_FALSE(v3.IsValid());
+  {
+    Version v2(v1);
+    v3 = v2;
+    EXPECT_TRUE(v2.IsValid());
+    EXPECT_TRUE(v1.Equals(v2));
+  }
+  EXPECT_TRUE(v3.Equals(v1));
+}
+
+TEST_F(VersionTest, GetVersionFromString) {
+  static const struct version_string {
+    const char* input;
+    size_t parts;
+    bool success;
+  } cases[] = {
+    {"", 0, false},
+    {" ", 0, false},
+    {"\t", 0, false},
+    {"\n", 0, false},
+    {"  ", 0, false},
+    {".", 0, false},
+    {" . ", 0, false},
+    {"0", 1, true},
+    {"0.0", 2, true},
+    {"65537.0", 0, false},
+    {"-1.0", 0, false},
+    {"1.-1.0", 0, false},
+    {"+1.0", 0, false},
+    {"1.+1.0", 0, false},
+    {"1.0a", 0, false},
+    {"1.2.3.4.5.6.7.8.9.0", 10, true},
+    {"02.1", 0, false},
+    {"f.1", 0, false},
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(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());
+  }
+}
+
+TEST_F(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},
+  };
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+    Version lhs(cases[i].lhs);
+    Version rhs(cases[i].rhs);
+    EXPECT_EQ(lhs.CompareTo(rhs), cases[i].expected) <<
+        cases[i].lhs << " ? " << cases[i].rhs;
+
+    EXPECT_EQ(lhs.IsOlderThan(cases[i].rhs), (cases[i].expected == -1));
+  }
+}
+
+TEST_F(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_UNSAFE(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_F(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_UNSAFE(cases); ++i) {
+    EXPECT_EQ(Version::IsValidWildcardString(cases[i].version),
+        cases[i].expected) << cases[i].version << "?" << cases[i].expected;
+  }
+}
diff --git a/base/vlog.cc b/base/vlog.cc
new file mode 100644
index 0000000..332de38
--- /dev/null
+++ b/base/vlog.cc
@@ -0,0 +1,177 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/vlog.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/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);
+
+  typedef std::pair<std::string, std::string> KVPair;
+  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 << "\"";
+    }
+  }
+
+  std::vector<KVPair> kv_pairs;
+  if (!base::SplitStringIntoKeyValuePairs(
+          vmodule_switch, '=', ',', &kv_pairs)) {
+    DLOG(WARNING) << "Could not fully parse vmodule switch \""
+                  << vmodule_switch << "\"";
+  }
+  for (std::vector<KVPair>::const_iterator it = kv_pairs.begin();
+       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
diff --git a/base/vlog.h b/base/vlog.h
new file mode 100644
index 0000000..987730f
--- /dev/null
+++ b/base/vlog.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_VLOG_H_
+#define BASE_VLOG_H_
+
+#include <cstddef>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/string_piece.h"
+
+namespace logging {
+
+// A helper class containing all the settings for vlogging.
+class BASE_EXPORT VlogInfo {
+ public:
+  static const int kDefaultVlogLevel;
+
+  // |v_switch| gives the default maximal active V-logging level; 0 is
+  // the default.  Normally positive values are used for V-logging
+  // levels.
+  //
+  // |vmodule_switch| gives the per-module maximal V-logging levels to
+  // override the value given by |v_switch|.
+  // E.g. "my_module=2,foo*=3" would change the logging level for all
+  // code in source files "my_module.*" and "foo*.*" ("-inl" suffixes
+  // are also disregarded for this matching).
+  //
+  // |log_severity| points to an int that stores the log level. If a valid
+  // |v_switch| is provided, it will set the log level, and the default
+  // vlog severity will be read from there..
+  //
+  // Any pattern containing a forward or backward slash will be tested
+  // against the whole pathname and not just the module.  E.g.,
+  // "*/foo/bar/*=2" would change the logging level for all code in
+  // source files under a "foo/bar" directory.
+  VlogInfo(const std::string& v_switch,
+           const std::string& vmodule_switch,
+           int* min_log_level);
+  ~VlogInfo();
+
+  // Returns the vlog level for a given file (usually taken from
+  // __FILE__).
+  int GetVlogLevel(const base::StringPiece& file) const;
+
+ private:
+  void SetMaxVlogLevel(int level);
+  int GetMaxVlogLevel() const;
+
+  // VmodulePattern holds all the information for each pattern parsed
+  // from |vmodule_switch|.
+  struct VmodulePattern;
+  std::vector<VmodulePattern> vmodule_levels_;
+  int* min_log_level_;
+
+  DISALLOW_COPY_AND_ASSIGN(VlogInfo);
+};
+
+// Returns true if the string passed in matches the vlog pattern.  The
+// vlog pattern string can contain wildcards like * and ?.  ? matches
+// exactly one character while * matches 0 or more characters.  Also,
+// as a special case, a / or \ character matches either / or \.
+//
+// Examples:
+//   "kh?n" matches "khan" but not "khn" or "khaan"
+//   "kh*n" matches "khn", "khan", or even "khaaaaan"
+//   "/foo\bar" matches "/foo/bar", "\foo\bar", or "/foo\bar"
+//     (disregarding C escaping rules)
+BASE_EXPORT bool MatchVlogPattern(const base::StringPiece& string,
+                                  const base::StringPiece& vlog_pattern);
+
+}  // namespace logging
+
+#endif  // BASE_VLOG_H_
diff --git a/base/vlog_unittest.cc b/base/vlog_unittest.cc
new file mode 100644
index 0000000..f583f44
--- /dev/null
+++ b/base/vlog_unittest.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/vlog.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace logging {
+
+namespace {
+
+class VlogTest : public testing::Test {
+};
+
+TEST_F(VlogTest, NoVmodule) {
+  int min_log_level = 0;
+  EXPECT_EQ(0, VlogInfo("", "", &min_log_level).GetVlogLevel("test1"));
+  EXPECT_EQ(0, VlogInfo("0", "", &min_log_level).GetVlogLevel("test2"));
+  EXPECT_EQ(0, VlogInfo("blah", "", &min_log_level).GetVlogLevel("test3"));
+  EXPECT_EQ(0, VlogInfo("0blah1", "", &min_log_level).GetVlogLevel("test4"));
+  EXPECT_EQ(1, VlogInfo("1", "", &min_log_level).GetVlogLevel("test5"));
+  EXPECT_EQ(5, VlogInfo("5", "", &min_log_level).GetVlogLevel("test6"));
+}
+
+TEST_F(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_F(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_F(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("", kVModuleSwitch, &min_log_level);
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar.cc"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("bar.cc"));
+  EXPECT_EQ(1, vlog_info.GetVlogLevel("foo/bar.cc"));
+
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("baz/grault/qux.h"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/baz/grault/qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/blah/qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault\\qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault//blah\\qux.cc"));
+
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar/baz/quux.cc"));
+  EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo/bar/baz/quux/grault.cc"));
+  EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo\\bar/baz\\quux/grault.cc"));
+
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("foo/bar/test-inl.cc"));
+  EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/test-inl.h"));
+  EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/baz/blah-inl.h"));
+}
+
+}  // namespace
+
+}  // namespace logging
diff --git a/base/win/OWNERS b/base/win/OWNERS
new file mode 100644
index 0000000..3aae3d6
--- /dev/null
+++ b/base/win/OWNERS
@@ -0,0 +1 @@
+cpu@chromium.org
diff --git a/base/win/dllmain.cc b/base/win/dllmain.cc
new file mode 100644
index 0000000..15437e0
--- /dev/null
+++ b/base/win/dllmain.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.
+
+// Windows doesn't support pthread_key_create's destr_function, and in fact
+// it's a bit tricky to get code to run when a thread exits.  This is
+// cargo-cult magic from http://www.codeproject.com/threads/tls.asp.
+// We are trying to be compatible with both a LoadLibrary style invocation, as
+// well as static linking. This code only needs to be included if we use
+// LoadLibrary, but it hooks into the "standard" set of TLS callbacks that are
+// provided for static linking.
+
+// This code is deliberately written to match the style of calls seen in
+// base/threading/thread_local_storage_win.cc.  Please keep the two in sync if
+// coding conventions are changed.
+
+// WARNING: Do *NOT* try to include this in the construction of the base
+// library, even though it potentially drives code in
+// base/threading/thread_local_storage_win.cc.  If you do, some users will end
+// up getting duplicate definition of DllMain() in some of their later links.
+
+// Force a reference to _tls_used to make the linker create the TLS directory
+// if it's not already there (that is, even if __declspec(thread) is not used).
+// Force a reference to p_thread_callback_dllmain_typical_entry to prevent whole
+// program optimization from discarding the variables.
+
+#include <windows.h>
+
+#include "base/compiler_specific.h"
+#include "base/win/win_util.h"
+
+// Indicate if another service is scanning the callbacks.  When this becomes
+// set to true, then DllMain() will stop supporting the callback service. This
+// value is set to true the first time any of our callbacks are called, as that
+// shows that some other service is handling callbacks.
+static bool linker_notifications_are_active = false;
+
+// This will be our mostly no-op callback that we'll list.  We won't
+// deliberately call it, and if it is called, that means we don't need to do any
+// of the callbacks anymore.  We expect such a call to arrive via a
+// THREAD_ATTACH message, long before we'd have to perform our THREAD_DETACH
+// callbacks.
+static void NTAPI on_callback(PVOID h, DWORD reason, PVOID reserved);
+
+#ifdef _WIN64
+
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:p_thread_callback_dllmain_typical_entry")
+
+#else  // _WIN64
+
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_p_thread_callback_dllmain_typical_entry")
+
+#endif  // _WIN64
+
+// Explicitly depend on tlssup.cc variable to bracket the list of TLS callbacks.
+extern "C" PIMAGE_TLS_CALLBACK __xl_a;
+extern "C" PIMAGE_TLS_CALLBACK __xl_z;
+
+// extern "C" suppresses C++ name mangling so we know the symbol names for the
+// linker /INCLUDE:symbol pragmas above.
+extern "C" {
+#ifdef _WIN64
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma data_seg(push, old_seg)
+// Use a typical possible name in the .CRT$XL? list of segments.
+#pragma const_seg(".CRT$XLB")
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry;
+const PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry = on_callback;
+#pragma data_seg(pop, old_seg)
+
+#else  // _WIN64
+
+#pragma data_seg(push, old_seg)
+// Use a typical possible name in the .CRT$XL? list of segments.
+#pragma data_seg(".CRT$XLB")
+PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry = on_callback;
+#pragma data_seg(pop, old_seg)
+
+#endif  // _WIN64
+}  // extern "C"
+
+NOINLINE static void CrashOnProcessDetach() {
+  *((int*)0) = 0x356;
+}
+
+// Make DllMain call the listed callbacks.  This way any third parties that are
+// linked in will also be called.
+BOOL WINAPI DllMain(PVOID h, DWORD reason, PVOID reserved) {
+  if (DLL_PROCESS_DETACH == reason && base::win::ShouldCrashOnProcessDetach())
+    CrashOnProcessDetach();
+
+  if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason)
+    return true;  // We won't service THREAD_ATTACH calls.
+
+  if (linker_notifications_are_active)
+    return true;  // Some other service is doing this work.
+
+  for (PIMAGE_TLS_CALLBACK* it = &__xl_a; it < &__xl_z; ++it) {
+    if (*it == NULL || *it == on_callback)
+      continue;  // Don't bother to call our own callback.
+    (*it)(h, reason, reserved);
+  }
+  return true;
+}
+
+static void NTAPI on_callback(PVOID h, DWORD reason, PVOID reserved) {
+  // Do nothing.  We were just a place holder in the list used to test that we
+  // call all items.
+  // If we are called, it means that some other system is scanning the callbacks
+  // and we don't need to do so in DllMain().
+  linker_notifications_are_active = true;
+  // Note: If some other routine some how plays this same game... we could both
+  // decide not to do the scanning <sigh>, but this trick should suppress
+  // duplicate calls on Vista, where the runtime takes care of the callbacks,
+  // and allow us to do the callbacks on XP, where we are currently devoid of
+  // callbacks (due to an explicit LoadLibrary call).
+}
diff --git a/base/win/enum_variant.cc b/base/win/enum_variant.cc
new file mode 100644
index 0000000..2975560
--- /dev/null
+++ b/base/win/enum_variant.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/enum_variant.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+EnumVariant::EnumVariant(unsigned long count)
+    : items_(new VARIANT[count]),
+      count_(count),
+      current_index_(0) {
+}
+
+EnumVariant::~EnumVariant() {
+}
+
+VARIANT* EnumVariant::ItemAt(unsigned long index) {
+  DCHECK(index < count_);
+  return &items_[index];
+}
+
+ULONG STDMETHODCALLTYPE EnumVariant::AddRef() {
+  return IUnknownImpl::AddRef();
+}
+
+ULONG STDMETHODCALLTYPE EnumVariant::Release() {
+  return IUnknownImpl::Release();
+}
+
+STDMETHODIMP EnumVariant::QueryInterface(REFIID riid, void** ppv) {
+  if (riid == IID_IEnumVARIANT) {
+    *ppv = static_cast<IEnumVARIANT*>(this);
+    AddRef();
+    return S_OK;
+  }
+
+  return IUnknownImpl::QueryInterface(riid, ppv);
+}
+
+STDMETHODIMP EnumVariant::Next(ULONG requested_count,
+                               VARIANT* out_elements,
+                               ULONG* out_elements_received) {
+  unsigned long count = std::min(requested_count, count_ - current_index_);
+  for (unsigned long i = 0; i < count; ++i)
+    out_elements[i] = items_[current_index_ + i];
+  current_index_ += count;
+  *out_elements_received = count;
+
+  return (count == requested_count ? S_OK : S_FALSE);
+}
+
+STDMETHODIMP EnumVariant::Skip(ULONG skip_count) {
+  unsigned long count = skip_count;
+  if (current_index_ + count > count_)
+    count = count_ - current_index_;
+
+  current_index_ += count;
+  return (count == skip_count ? S_OK : S_FALSE);
+}
+
+STDMETHODIMP EnumVariant::Reset() {
+  current_index_ = 0;
+  return S_OK;
+}
+
+STDMETHODIMP EnumVariant::Clone(IEnumVARIANT** out_cloned_object) {
+  EnumVariant* other = new EnumVariant(count_);
+  if (count_ > 0)
+    memcpy(other->ItemAt(0), &items_[0], count_ * sizeof(VARIANT));
+  other->Skip(current_index_);
+  other->AddRef();
+  *out_cloned_object = other;
+  return S_OK;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/enum_variant.h b/base/win/enum_variant.h
new file mode 100644
index 0000000..7cee91d
--- /dev/null
+++ b/base/win/enum_variant.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_ENUM_VARIANT_H_
+#define BASE_WIN_ENUM_VARIANT_H_
+
+#include <unknwn.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/win/iunknown_impl.h"
+
+namespace base {
+namespace win {
+
+// A simple implementation of IEnumVARIANT.
+class BASE_EXPORT EnumVariant
+  : public IEnumVARIANT,
+    public IUnknownImpl {
+ public:
+  // The constructor allocates an array of size |count|. Then use
+  // ItemAt to set the value of each item in the array to initialize it.
+  explicit EnumVariant(unsigned long count);
+
+  // Returns a mutable pointer to the item at position |index|.
+  VARIANT* ItemAt(unsigned long index);
+
+  // IUnknown.
+  ULONG STDMETHODCALLTYPE AddRef() OVERRIDE;
+  ULONG STDMETHODCALLTYPE Release() OVERRIDE;
+  STDMETHODIMP QueryInterface(REFIID riid, void** ppv) OVERRIDE;
+
+  // IEnumVARIANT.
+  STDMETHODIMP Next(ULONG requested_count,
+                    VARIANT* out_elements,
+                    ULONG* out_elements_received);
+  STDMETHODIMP Skip(ULONG skip_count);
+  STDMETHODIMP Reset();
+  STDMETHODIMP Clone(IEnumVARIANT** out_cloned_object);
+
+ private:
+  ~EnumVariant();
+
+  scoped_array<VARIANT> items_;
+  unsigned long count_;
+  unsigned long current_index_;
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_ENUM_VARIANT_H_
diff --git a/base/win/enum_variant_unittest.cc b/base/win/enum_variant_unittest.cc
new file mode 100644
index 0000000..99645a2
--- /dev/null
+++ b/base/win/enum_variant_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/enum_variant.h"
+
+#include "base/win/scoped_com_initializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+TEST(EnumVariantTest, EmptyEnumVariant) {
+  ScopedCOMInitializer com_initializer;
+
+  EnumVariant* ev = new EnumVariant(0);
+  ev->AddRef();
+
+  IUnknown* iunknown;
+  EXPECT_TRUE(SUCCEEDED(
+      ev->QueryInterface(IID_IUnknown, reinterpret_cast<void**>(&iunknown))));
+  iunknown->Release();
+
+  IEnumVARIANT* ienumvariant;
+  EXPECT_TRUE(SUCCEEDED(
+      ev->QueryInterface(IID_IEnumVARIANT,
+                         reinterpret_cast<void**>(&ienumvariant))));
+  EXPECT_EQ(ev, ienumvariant);
+  ienumvariant->Release();
+
+  VARIANT out_element;
+  ULONG out_received = 0;
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(0, out_received);
+
+  EXPECT_EQ(S_FALSE, ev->Skip(1));
+
+  EXPECT_EQ(S_OK, ev->Reset());
+
+  IEnumVARIANT* ev2 = NULL;
+  EXPECT_EQ(S_OK, ev->Clone(&ev2));
+
+  EXPECT_NE(static_cast<IEnumVARIANT*>(NULL), ev2);
+  EXPECT_NE(ev, ev2);
+  EXPECT_EQ(S_FALSE, ev2->Skip(1));
+  EXPECT_EQ(S_OK, ev2->Reset());
+
+  ULONG ev2_finalrefcount = ev2->Release();
+  EXPECT_EQ(0, ev2_finalrefcount);
+
+  ULONG ev_finalrefcount = ev->Release();
+  EXPECT_EQ(0, ev_finalrefcount);
+}
+
+TEST(EnumVariantTest, SimpleEnumVariant) {
+  ScopedCOMInitializer com_initializer;
+
+  EnumVariant* ev = new EnumVariant(3);
+  ev->AddRef();
+  ev->ItemAt(0)->vt = VT_I4;
+  ev->ItemAt(0)->lVal = 10;
+  ev->ItemAt(1)->vt = VT_I4;
+  ev->ItemAt(1)->lVal = 20;
+  ev->ItemAt(2)->vt = VT_I4;
+  ev->ItemAt(2)->lVal = 30;
+
+  // Get elements one at a time.
+  VARIANT out_element;
+  ULONG out_received = 0;
+  EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(1, out_received);
+  EXPECT_EQ(VT_I4, out_element.vt);
+  EXPECT_EQ(10, out_element.lVal);
+  EXPECT_EQ(S_OK, ev->Skip(1));
+  EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(1, out_received);
+  EXPECT_EQ(VT_I4, out_element.vt);
+  EXPECT_EQ(30, out_element.lVal);
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+
+  // Reset and get all elements at once.
+  VARIANT out_elements[3];
+  EXPECT_EQ(S_OK, ev->Reset());
+  EXPECT_EQ(S_OK, ev->Next(3, out_elements, &out_received));
+  EXPECT_EQ(3, out_received);
+  EXPECT_EQ(VT_I4, out_elements[0].vt);
+  EXPECT_EQ(10, out_elements[0].lVal);
+  EXPECT_EQ(VT_I4, out_elements[1].vt);
+  EXPECT_EQ(20, out_elements[1].lVal);
+  EXPECT_EQ(VT_I4, out_elements[2].vt);
+  EXPECT_EQ(30, out_elements[2].lVal);
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+
+  // Clone it.
+  IEnumVARIANT* ev2 = NULL;
+  EXPECT_EQ(S_OK, ev->Clone(&ev2));
+  EXPECT_TRUE(ev2 != NULL);
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(S_OK, ev2->Reset());
+  EXPECT_EQ(S_OK, ev2->Next(3, out_elements, &out_received));
+  EXPECT_EQ(3, out_received);
+  EXPECT_EQ(VT_I4, out_elements[0].vt);
+  EXPECT_EQ(10, out_elements[0].lVal);
+  EXPECT_EQ(VT_I4, out_elements[1].vt);
+  EXPECT_EQ(20, out_elements[1].lVal);
+  EXPECT_EQ(VT_I4, out_elements[2].vt);
+  EXPECT_EQ(30, out_elements[2].lVal);
+  EXPECT_EQ(S_FALSE, ev2->Next(1, &out_element, &out_received));
+
+  ULONG ev2_finalrefcount = ev2->Release();
+  EXPECT_EQ(0, ev2_finalrefcount);
+
+  ULONG ev_finalrefcount = ev->Release();
+  EXPECT_EQ(0, ev_finalrefcount);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_consumer.h b/base/win/event_trace_consumer.h
new file mode 100644
index 0000000..c1b42b4
--- /dev/null
+++ b/base/win/event_trace_consumer.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Declaration of a Windows event trace consumer base class.
+#ifndef BASE_WIN_EVENT_TRACE_CONSUMER_H_
+#define BASE_WIN_EVENT_TRACE_CONSUMER_H_
+
+#include <windows.h>
+#include <wmistr.h>
+#include <evntrace.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// This class is a base class that makes it easier to consume events
+// from realtime or file sessions. Concrete consumers need to sublass
+// 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],
+                             trace_handles_.size(),
+                             NULL,
+                             NULL);
+  return HRESULT_FROM_WIN32(err);
+}
+
+template <class ImplClass> inline
+HRESULT EtwTraceConsumerBase<ImplClass>::Close() {
+  HRESULT hr = S_OK;
+  for (size_t i = 0; i < trace_handles_.size(); ++i) {
+    if (NULL != trace_handles_[i]) {
+      ULONG ret = ::CloseTrace(trace_handles_[i]);
+      trace_handles_[i] = NULL;
+
+      if (FAILED(HRESULT_FROM_WIN32(ret)))
+        hr = HRESULT_FROM_WIN32(ret);
+    }
+  }
+  trace_handles_.clear();
+
+  return hr;
+}
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_EVENT_TRACE_CONSUMER_H_
diff --git a/base/win/event_trace_consumer_unittest.cc b/base/win/event_trace_consumer_unittest.cc
new file mode 100644
index 0000000..327e1c7
--- /dev/null
+++ b/base/win/event_trace_consumer_unittest.cc
@@ -0,0 +1,383 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for event trace consumer base class.
+#include "base/win/event_trace_consumer.h"
+
+#include <list>
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/process.h"
+#include "base/scoped_temp_dir.h"
+#include "base/stringprintf.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
+#include "base/win/scoped_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include <initguid.h>  // NOLINT - has to be last
+
+namespace {
+
+using base::win::EtwMofEvent;
+using base::win::EtwTraceController;
+using base::win::EtwTraceConsumerBase;
+using base::win::EtwTraceProperties;
+using base::win::EtwTraceProvider;
+
+typedef std::list<EVENT_TRACE> EventQueue;
+
+class TestConsumer: public EtwTraceConsumerBase<TestConsumer> {
+ public:
+  TestConsumer() {
+    sank_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
+    ClearQueue();
+  }
+
+  ~TestConsumer() {
+    ClearQueue();
+    sank_event_.Close();
+  }
+
+  void ClearQueue() {
+    EventQueue::const_iterator it(events_.begin()), end(events_.end());
+
+    for (; it != end; ++it) {
+      delete [] it->MofData;
+    }
+
+    events_.clear();
+  }
+
+  static void EnqueueEvent(EVENT_TRACE* event) {
+    events_.push_back(*event);
+    EVENT_TRACE& back = events_.back();
+
+    if (NULL != event->MofData && 0 != event->MofLength) {
+      back.MofData = new char[event->MofLength];
+      memcpy(back.MofData, event->MofData, event->MofLength);
+    }
+  }
+
+  static void ProcessEvent(EVENT_TRACE* event) {
+    EnqueueEvent(event);
+    ::SetEvent(sank_event_.Get());
+  }
+
+  static base::win::ScopedHandle sank_event_;
+  static EventQueue events_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestConsumer);
+};
+
+base::win::ScopedHandle TestConsumer::sank_event_;
+EventQueue TestConsumer::events_;
+
+class EtwTraceConsumerBaseTest: public testing::Test {
+ public:
+  EtwTraceConsumerBaseTest()
+      : session_name_(base::StringPrintf(L"TestSession-%d",
+                                         base::Process::Current().pid())) {
+  }
+
+  virtual void SetUp() {
+    // Cleanup any potentially dangling sessions.
+    EtwTraceProperties ignore;
+    EtwTraceController::Stop(session_name_.c_str(), &ignore);
+
+    // Allocate a new GUID for each provider test.
+    ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
+  }
+
+  virtual void TearDown() {
+    // Cleanup any potentially danging sessions.
+    EtwTraceProperties ignore;
+    EtwTraceController::Stop(session_name_.c_str(), &ignore);
+  }
+
+ protected:
+  GUID test_provider_;
+  std::wstring session_name_;
+};
+
+}  // namespace
+
+TEST_F(EtwTraceConsumerBaseTest, Initialize) {
+  TestConsumer consumer_;
+}
+
+TEST_F(EtwTraceConsumerBaseTest, OpenRealtimeSucceedsWhenNoSession) {
+  TestConsumer consumer_;
+
+  ASSERT_HRESULT_SUCCEEDED(
+      consumer_.OpenRealtimeSession(session_name_.c_str()));
+}
+
+TEST_F(EtwTraceConsumerBaseTest, ConsumerImmediateFailureWhenNoSession) {
+  TestConsumer consumer_;
+
+  ASSERT_HRESULT_SUCCEEDED(
+      consumer_.OpenRealtimeSession(session_name_.c_str()));
+  ASSERT_HRESULT_FAILED(consumer_.Consume());
+}
+
+namespace {
+
+class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
+ public:
+  virtual void SetUp() {
+    EtwTraceConsumerBaseTest::SetUp();
+
+    ASSERT_HRESULT_SUCCEEDED(
+        consumer_.OpenRealtimeSession(session_name_.c_str()));
+  }
+
+  virtual void TearDown() {
+    consumer_.Close();
+
+    EtwTraceConsumerBaseTest::TearDown();
+  }
+
+  DWORD ConsumerThread() {
+    ::SetEvent(consumer_ready_.Get());
+
+    HRESULT hr = consumer_.Consume();
+    return hr;
+  }
+
+  static DWORD WINAPI ConsumerThreadMainProc(void* arg) {
+    return reinterpret_cast<EtwTraceConsumerRealtimeTest*>(arg)->
+        ConsumerThread();
+  }
+
+  HRESULT StartConsumerThread() {
+    consumer_ready_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
+    EXPECT_TRUE(consumer_ready_ != NULL);
+    consumer_thread_.Set(::CreateThread(NULL, 0, ConsumerThreadMainProc,
+        this, 0, NULL));
+    if (NULL == consumer_thread_.Get())
+      return HRESULT_FROM_WIN32(::GetLastError());
+
+    HRESULT hr = S_OK;
+    HANDLE events[] = { consumer_ready_, consumer_thread_ };
+    DWORD result = ::WaitForMultipleObjects(arraysize(events), events,
+                                            FALSE, INFINITE);
+    switch (result) {
+      case WAIT_OBJECT_0:
+        // The event was set, the consumer_ is ready.
+        return S_OK;
+      case WAIT_OBJECT_0 + 1: {
+          // The thread finished. This may race with the event, so check
+          // explicitly for the event here, before concluding there's trouble.
+          if (WAIT_OBJECT_0 == ::WaitForSingleObject(consumer_ready_, 0))
+            return S_OK;
+          DWORD exit_code = 0;
+          if (::GetExitCodeThread(consumer_thread_, &exit_code))
+            return exit_code;
+          else
+            return HRESULT_FROM_WIN32(::GetLastError());
+          break;
+        }
+      default:
+        return E_UNEXPECTED;
+        break;
+    }
+
+    return hr;
+  }
+
+  // Waits for consumer_ thread to exit, and returns its exit code.
+  HRESULT JoinConsumerThread() {
+    if (WAIT_OBJECT_0 != ::WaitForSingleObject(consumer_thread_, INFINITE))
+      return HRESULT_FROM_WIN32(::GetLastError());
+
+    DWORD exit_code = 0;
+    if (::GetExitCodeThread(consumer_thread_, &exit_code))
+      return exit_code;
+
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  TestConsumer consumer_;
+  base::win::ScopedHandle consumer_ready_;
+  base::win::ScopedHandle consumer_thread_;
+};
+
+}  // namespace
+
+TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) {
+  EtwTraceController controller;
+
+  HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
+                                               100 * 1024);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  // Start the consumer_.
+  ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
+
+  // Wait around for the consumer_ thread a bit.
+  ASSERT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(consumer_thread_, 50));
+
+  ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+
+  // The consumer_ returns success on session stop.
+  ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
+}
+
+namespace {
+
+// {57E47923-A549-476f-86CA-503D57F59E62}
+DEFINE_GUID(kTestEventType,
+  0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
+
+}  // namespace
+
+TEST_F(EtwTraceConsumerRealtimeTest, ConsumeEvent) {
+  EtwTraceController controller;
+  HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
+                                               100 * 1024);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
+      TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
+
+  EtwTraceProvider provider(test_provider_);
+  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+
+  // Start the consumer_.
+  ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
+
+  ASSERT_EQ(0, TestConsumer::events_.size());
+
+  EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
+  EXPECT_EQ(ERROR_SUCCESS, provider.Log(&event.header));
+
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(TestConsumer::sank_event_,
+                                                 INFINITE));
+  ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+  ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
+  ASSERT_NE(0u, TestConsumer::events_.size());
+}
+
+namespace {
+
+// We run events through a file session to assert that
+// the content comes through.
+class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest {
+ public:
+  EtwTraceConsumerDataTest() {
+  }
+
+  virtual void SetUp() {
+    EtwTraceConsumerBaseTest::SetUp();
+
+    EtwTraceProperties prop;
+    EtwTraceController::Stop(session_name_.c_str(), &prop);
+
+    // Create a temp dir for this test.
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    // Construct a temp file name in our dir.
+    temp_file_ = temp_dir_.path().Append(L"test.etl");
+  }
+
+  virtual void TearDown() {
+    EXPECT_TRUE(file_util::Delete(temp_file_, false));
+
+    EtwTraceConsumerBaseTest::TearDown();
+  }
+
+  HRESULT LogEventToTempSession(PEVENT_TRACE_HEADER header) {
+    EtwTraceController controller;
+
+    // Set up a file session.
+    HRESULT hr = controller.StartFileSession(session_name_.c_str(),
+                                             temp_file_.value().c_str());
+    if (FAILED(hr))
+      return hr;
+
+    // Enable our provider.
+    EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
+        TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
+
+    EtwTraceProvider provider(test_provider_);
+    // Then register our provider, means we get a session handle immediately.
+    EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+    // Trace the event, it goes to the temp file.
+    EXPECT_EQ(ERROR_SUCCESS, provider.Log(header));
+    EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_));
+    EXPECT_HRESULT_SUCCEEDED(provider.Unregister());
+    EXPECT_HRESULT_SUCCEEDED(controller.Flush(NULL));
+    EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+
+    return S_OK;
+  }
+
+  HRESULT ConsumeEventFromTempSession() {
+    // Now consume the event(s).
+    TestConsumer consumer_;
+    HRESULT hr = consumer_.OpenFileSession(temp_file_.value().c_str());
+    if (SUCCEEDED(hr))
+      hr = consumer_.Consume();
+    consumer_.Close();
+    // And nab the result.
+    events_.swap(TestConsumer::events_);
+    return hr;
+  }
+
+  HRESULT RoundTripEvent(PEVENT_TRACE_HEADER header, PEVENT_TRACE* trace) {
+    file_util::Delete(temp_file_, false);
+
+    HRESULT hr = LogEventToTempSession(header);
+    if (SUCCEEDED(hr))
+      hr = ConsumeEventFromTempSession();
+
+    if (FAILED(hr))
+      return hr;
+
+    // We should now have the event in the queue.
+    if (events_.empty())
+      return E_FAIL;
+
+    *trace = &events_.back();
+    return S_OK;
+  }
+
+  EventQueue events_;
+  ScopedTempDir temp_dir_;
+  FilePath temp_file_;
+};
+
+}  // namespace
+
+
+TEST_F(EtwTraceConsumerDataTest, RoundTrip) {
+  EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
+
+  static const char kData[] = "This is but test data";
+  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(kData);
+  event.fields[0].Length = sizeof(kData);
+
+  PEVENT_TRACE trace = NULL;
+  HRESULT hr = RoundTripEvent(&event.header, &trace);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+  ASSERT_HRESULT_SUCCEEDED(hr) << "RoundTripEvent failed";
+  ASSERT_TRUE(NULL != trace);
+  ASSERT_EQ(sizeof(kData), trace->MofLength);
+  ASSERT_STREQ(kData, reinterpret_cast<const char*>(trace->MofData));
+}
diff --git a/base/win/event_trace_controller.cc b/base/win/event_trace_controller.cc
new file mode 100644
index 0000000..0391fbc
--- /dev/null
+++ b/base/win/event_trace_controller.cc
@@ -0,0 +1,173 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of a Windows event trace controller class.
+#include "base/win/event_trace_controller.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+EtwTraceProperties::EtwTraceProperties() {
+  memset(buffer_, 0, sizeof(buffer_));
+  EVENT_TRACE_PROPERTIES* prop = get();
+
+  prop->Wnode.BufferSize = sizeof(buffer_);
+  prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
+  prop->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
+  prop->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) +
+                            sizeof(wchar_t) * kMaxStringLen;
+}
+
+HRESULT EtwTraceProperties::SetLoggerName(const wchar_t* logger_name) {
+  size_t len = wcslen(logger_name) + 1;
+  if (kMaxStringLen < len)
+    return E_INVALIDARG;
+
+  memcpy(buffer_ + get()->LoggerNameOffset,
+         logger_name,
+         sizeof(wchar_t) * len);
+  return S_OK;
+}
+
+HRESULT EtwTraceProperties::SetLoggerFileName(const wchar_t* logger_file_name) {
+  size_t len = wcslen(logger_file_name) + 1;
+  if (kMaxStringLen < len)
+    return E_INVALIDARG;
+
+  memcpy(buffer_ + get()->LogFileNameOffset,
+         logger_file_name,
+         sizeof(wchar_t) * len);
+  return S_OK;
+}
+
+EtwTraceController::EtwTraceController() : session_(NULL) {
+}
+
+EtwTraceController::~EtwTraceController() {
+  Stop(NULL);
+}
+
+HRESULT EtwTraceController::Start(const wchar_t* session_name,
+    EtwTraceProperties* prop) {
+  DCHECK(NULL == session_ && session_name_.empty());
+  EtwTraceProperties ignore;
+  if (prop == NULL)
+    prop = &ignore;
+
+  HRESULT hr = Start(session_name, prop, &session_);
+  if (SUCCEEDED(hr))
+    session_name_ = session_name;
+
+  return hr;
+}
+
+HRESULT EtwTraceController::StartFileSession(const wchar_t* session_name,
+      const wchar_t* logfile_path, bool realtime) {
+  DCHECK(NULL == session_ && session_name_.empty());
+
+  EtwTraceProperties prop;
+  prop.SetLoggerFileName(logfile_path);
+  EVENT_TRACE_PROPERTIES& p = *prop.get();
+  p.Wnode.ClientContext = 1;  // QPC timer accuracy.
+  p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;  // Sequential log.
+  if (realtime)
+    p.LogFileMode |= EVENT_TRACE_REAL_TIME_MODE;
+
+  p.MaximumFileSize = 100;  // 100M file size.
+  p.FlushTimer = 30;  // 30 seconds flush lag.
+  return Start(session_name, &prop);
+}
+
+HRESULT EtwTraceController::StartRealtimeSession(const wchar_t* session_name,
+    size_t buffer_size) {
+  DCHECK(NULL == session_ && session_name_.empty());
+  EtwTraceProperties prop;
+  EVENT_TRACE_PROPERTIES& p = *prop.get();
+  p.LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY;
+  p.FlushTimer = 1;  // flush every second.
+  p.BufferSize = 16;  // 16 K buffers.
+  p.LogFileNameOffset = 0;
+  return Start(session_name, &prop);
+}
+
+HRESULT EtwTraceController::EnableProvider(REFGUID provider, UCHAR level,
+    ULONG flags) {
+  ULONG error = ::EnableTrace(TRUE, flags, level, &provider, session_);
+  return HRESULT_FROM_WIN32(error);
+}
+
+HRESULT EtwTraceController::DisableProvider(REFGUID provider) {
+  ULONG error = ::EnableTrace(FALSE, 0, 0, &provider, session_);
+  return HRESULT_FROM_WIN32(error);
+}
+
+HRESULT EtwTraceController::Stop(EtwTraceProperties* properties) {
+  EtwTraceProperties ignore;
+  if (properties == NULL)
+    properties = &ignore;
+
+  ULONG error = ::ControlTrace(session_, NULL, properties->get(),
+    EVENT_TRACE_CONTROL_STOP);
+  if (ERROR_SUCCESS != error)
+    return HRESULT_FROM_WIN32(error);
+
+  session_ = NULL;
+  session_name_.clear();
+  return S_OK;
+}
+
+HRESULT EtwTraceController::Flush(EtwTraceProperties* properties) {
+  EtwTraceProperties ignore;
+  if (properties == NULL)
+    properties = &ignore;
+
+  ULONG error = ::ControlTrace(session_, NULL, properties->get(),
+                               EVENT_TRACE_CONTROL_FLUSH);
+  if (ERROR_SUCCESS != error)
+    return HRESULT_FROM_WIN32(error);
+
+  return S_OK;
+}
+
+HRESULT EtwTraceController::Start(const wchar_t* session_name,
+    EtwTraceProperties* properties, TRACEHANDLE* session_handle) {
+  DCHECK(properties != NULL);
+  ULONG err = ::StartTrace(session_handle, session_name, properties->get());
+  return HRESULT_FROM_WIN32(err);
+}
+
+HRESULT EtwTraceController::Query(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_QUERY);
+  return HRESULT_FROM_WIN32(err);
+};
+
+HRESULT EtwTraceController::Update(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  DCHECK(properties != NULL);
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_UPDATE);
+  return HRESULT_FROM_WIN32(err);
+}
+
+HRESULT EtwTraceController::Stop(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  DCHECK(properties != NULL);
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_STOP);
+  return HRESULT_FROM_WIN32(err);
+}
+
+HRESULT EtwTraceController::Flush(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  DCHECK(properties != NULL);
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_FLUSH);
+  return HRESULT_FROM_WIN32(err);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_controller.h b/base/win/event_trace_controller.h
new file mode 100644
index 0000000..69e755b
--- /dev/null
+++ b/base/win/event_trace_controller.h
@@ -0,0 +1,151 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Declaration of a Windows event trace controller class.
+// The controller takes care of creating and manipulating event trace
+// sessions.
+//
+// Event tracing for Windows is a system-provided service that provides
+// logging control and high-performance transport for generic, binary trace
+// events. Event trace providers register with the system by their name,
+// which is a GUID, and can from that point forward receive callbacks that
+// start or end tracing and that change their trace level and enable mask.
+//
+// A trace controller can create an event tracing session, which either
+// sends events to a binary file, or to a realtime consumer, or both.
+//
+// A trace consumer consumes events from zero or one realtime session,
+// as well as potentially from multiple binary trace files.
+#ifndef BASE_WIN_EVENT_TRACE_CONTROLLER_H_
+#define BASE_WIN_EVENT_TRACE_CONTROLLER_H_
+
+#include <windows.h>
+#include <wmistr.h>
+#include <evntrace.h>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Utility class to make it easier to work with EVENT_TRACE_PROPERTIES.
+// The EVENT_TRACE_PROPERTIES structure contains information about an
+// event tracing session.
+class BASE_EXPORT EtwTraceProperties {
+ public:
+  EtwTraceProperties();
+
+  EVENT_TRACE_PROPERTIES* get() {
+    return &properties_;
+  }
+
+  const EVENT_TRACE_PROPERTIES* get() const {
+    return reinterpret_cast<const EVENT_TRACE_PROPERTIES*>(&properties_);
+  }
+
+  const wchar_t* GetLoggerName() const {
+    return reinterpret_cast<const wchar_t *>(buffer_ + get()->LoggerNameOffset);
+  }
+
+  // Copies logger_name to the properties structure.
+  HRESULT SetLoggerName(const wchar_t* logger_name);
+  const wchar_t* GetLoggerFileName() const {
+    return reinterpret_cast<const wchar_t*>(buffer_ + get()->LogFileNameOffset);
+  }
+
+  // Copies logger_file_name to the properties structure.
+  HRESULT SetLoggerFileName(const wchar_t* logger_file_name);
+
+  // Max string len for name and session name is 1024 per documentation.
+  static const size_t kMaxStringLen = 1024;
+  // Properties buffer allocates space for header and for
+  // max length for name and session name.
+  static const size_t kBufSize = sizeof(EVENT_TRACE_PROPERTIES)
+      + 2 * sizeof(wchar_t) * (kMaxStringLen);
+
+ private:
+  // The EVENT_TRACE_PROPERTIES structure needs to be overlaid on a
+  // larger buffer to allow storing the logger name and logger file
+  // name contiguously with the structure.
+  union {
+   public:
+    // Our properties header.
+    EVENT_TRACE_PROPERTIES properties_;
+    // The actual size of the buffer is forced by this member.
+    char buffer_[kBufSize];
+  };
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceProperties);
+};
+
+// This class implements an ETW controller, which knows how to start and
+// stop event tracing sessions, as well as controlling ETW provider
+// log levels and enable bit masks under the session.
+class BASE_EXPORT EtwTraceController {
+ public:
+  EtwTraceController();
+  ~EtwTraceController();
+
+  // Start a session with given name and properties.
+  HRESULT Start(const wchar_t* session_name, EtwTraceProperties* prop);
+
+  // Starts a session tracing to a file with some default properties.
+  HRESULT StartFileSession(const wchar_t* session_name,
+                           const wchar_t* logfile_path,
+                           bool realtime = false);
+
+  // Starts a realtime session with some default properties.
+  HRESULT StartRealtimeSession(const wchar_t* session_name,
+                               size_t buffer_size);
+
+  // Enables "provider" at "level" for this session.
+  // This will cause all providers registered with the GUID
+  // "provider" to start tracing at the new level, systemwide.
+  HRESULT EnableProvider(const GUID& provider, UCHAR level,
+                         ULONG flags = 0xFFFFFFFF);
+  // Disables "provider".
+  HRESULT DisableProvider(const GUID& provider);
+
+  // Stops our session and retrieve the new properties of the session,
+  // properties may be NULL.
+  HRESULT Stop(EtwTraceProperties* properties);
+
+  // Flushes our session and retrieve the current properties,
+  // properties may be NULL.
+  HRESULT Flush(EtwTraceProperties* properties);
+
+  // Static utility functions for controlling
+  // sessions we don't necessarily own.
+  static HRESULT Start(const wchar_t* session_name,
+                       EtwTraceProperties* properties,
+                       TRACEHANDLE* session_handle);
+
+  static HRESULT Query(const wchar_t* session_name,
+                       EtwTraceProperties* properties);
+
+  static HRESULT Update(const wchar_t* session_name,
+                        EtwTraceProperties* properties);
+
+  static HRESULT Stop(const wchar_t* session_name,
+                      EtwTraceProperties* properties);
+  static HRESULT Flush(const wchar_t* session_name,
+                       EtwTraceProperties* properties);
+
+  // Accessors.
+  TRACEHANDLE session() const { return session_; }
+  const wchar_t* session_name() const { return session_name_.c_str(); }
+
+ private:
+  std::wstring session_name_;
+  TRACEHANDLE session_;
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceController);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_EVENT_TRACE_CONTROLLER_H_
diff --git a/base/win/event_trace_controller_unittest.cc b/base/win/event_trace_controller_unittest.cc
new file mode 100644
index 0000000..2e3a403
--- /dev/null
+++ b/base/win/event_trace_controller_unittest.cc
@@ -0,0 +1,236 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for event trace controller.
+
+#include <objbase.h>
+#include <initguid.h>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/process.h"
+#include "base/scoped_temp_dir.h"
+#include "base/stringprintf.h"
+#include "base/sys_info.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
+#include "base/win/scoped_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using base::win::EtwTraceController;
+using base::win::EtwTraceProvider;
+using base::win::EtwTraceProperties;
+
+DEFINE_GUID(kGuidNull,
+    0x0000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0);
+
+const ULONG kTestProviderFlags = 0xCAFEBABE;
+
+class TestingProvider: public EtwTraceProvider {
+ public:
+  explicit TestingProvider(const GUID& provider_name)
+      : EtwTraceProvider(provider_name) {
+    callback_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
+  }
+
+  void WaitForCallback() {
+    ::WaitForSingleObject(callback_event_.Get(), INFINITE);
+    ::ResetEvent(callback_event_.Get());
+  }
+
+ private:
+  virtual void OnEventsEnabled() {
+    ::SetEvent(callback_event_.Get());
+  }
+  virtual void PostEventsDisabled() {
+    ::SetEvent(callback_event_.Get());
+  }
+
+  base::win::ScopedHandle callback_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingProvider);
+};
+
+}  // namespace
+
+TEST(EtwTracePropertiesTest, Initialization) {
+  EtwTraceProperties prop;
+
+  EVENT_TRACE_PROPERTIES* p = prop.get();
+  EXPECT_NE(0u, p->Wnode.BufferSize);
+  EXPECT_EQ(0u, p->Wnode.ProviderId);
+  EXPECT_EQ(0u, p->Wnode.HistoricalContext);
+
+  EXPECT_TRUE(kGuidNull == p->Wnode.Guid);
+  EXPECT_EQ(0, p->Wnode.ClientContext);
+  EXPECT_EQ(WNODE_FLAG_TRACED_GUID, p->Wnode.Flags);
+
+  EXPECT_EQ(0, p->BufferSize);
+  EXPECT_EQ(0, p->MinimumBuffers);
+  EXPECT_EQ(0, p->MaximumBuffers);
+  EXPECT_EQ(0, p->MaximumFileSize);
+  EXPECT_EQ(0, p->LogFileMode);
+  EXPECT_EQ(0, p->FlushTimer);
+  EXPECT_EQ(0, p->EnableFlags);
+  EXPECT_EQ(0, p->AgeLimit);
+
+  EXPECT_EQ(0, p->NumberOfBuffers);
+  EXPECT_EQ(0, p->FreeBuffers);
+  EXPECT_EQ(0, p->EventsLost);
+  EXPECT_EQ(0, p->BuffersWritten);
+  EXPECT_EQ(0, p->LogBuffersLost);
+  EXPECT_EQ(0, p->RealTimeBuffersLost);
+  EXPECT_EQ(0, p->LoggerThreadId);
+  EXPECT_NE(0u, p->LogFileNameOffset);
+  EXPECT_NE(0u, p->LoggerNameOffset);
+}
+
+TEST(EtwTracePropertiesTest, Strings) {
+  EtwTraceProperties prop;
+
+  ASSERT_STREQ(L"", prop.GetLoggerFileName());
+  ASSERT_STREQ(L"", prop.GetLoggerName());
+
+  std::wstring name(1023, L'A');
+  ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerFileName(name.c_str()));
+  ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerName(name.c_str()));
+  ASSERT_STREQ(name.c_str(), prop.GetLoggerFileName());
+  ASSERT_STREQ(name.c_str(), prop.GetLoggerName());
+
+  std::wstring name2(1024, L'A');
+  ASSERT_HRESULT_FAILED(prop.SetLoggerFileName(name2.c_str()));
+  ASSERT_HRESULT_FAILED(prop.SetLoggerName(name2.c_str()));
+}
+
+namespace {
+
+class EtwTraceControllerTest : public testing::Test {
+ public:
+  EtwTraceControllerTest() : session_name_(
+      base::StringPrintf(L"TestSession-%d", base::Process::Current().pid())) {
+  }
+
+  virtual void SetUp() {
+    EtwTraceProperties ignore;
+    EtwTraceController::Stop(session_name_.c_str(), &ignore);
+
+    // Allocate a new provider name GUID for each test.
+    ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
+  }
+
+  virtual void TearDown() {
+    EtwTraceProperties prop;
+    EtwTraceController::Stop(session_name_.c_str(), &prop);
+  }
+
+ protected:
+  GUID test_provider_;
+  std::wstring session_name_;
+};
+
+}  // namespace
+
+TEST_F(EtwTraceControllerTest, Initialize) {
+  EtwTraceController controller;
+
+  EXPECT_EQ(NULL, controller.session());
+  EXPECT_STREQ(L"", controller.session_name());
+}
+
+
+TEST_F(EtwTraceControllerTest, StartRealTimeSession) {
+  EtwTraceController controller;
+
+  HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
+                                               100 * 1024);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  EXPECT_TRUE(NULL != controller.session());
+  EXPECT_STREQ(session_name_.c_str(), controller.session_name());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+  EXPECT_EQ(NULL, controller.session());
+  EXPECT_STREQ(L"", controller.session_name());
+}
+
+TEST_F(EtwTraceControllerTest, StartFileSession) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath temp;
+  ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir.path(), &temp));
+
+  EtwTraceController controller;
+  HRESULT hr = controller.StartFileSession(session_name_.c_str(),
+                                           temp.value().c_str());
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    file_util::Delete(temp, false);
+    return;
+  }
+
+  EXPECT_TRUE(NULL != controller.session());
+  EXPECT_STREQ(session_name_.c_str(), controller.session_name());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+  EXPECT_EQ(NULL, controller.session());
+  EXPECT_STREQ(L"", controller.session_name());
+  file_util::Delete(temp, false);
+}
+
+TEST_F(EtwTraceControllerTest, EnableDisable) {
+  TestingProvider provider(test_provider_);
+
+  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_EQ(NULL, provider.session_handle());
+
+  EtwTraceController controller;
+  HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
+                                               100 * 1024);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
+                           TRACE_LEVEL_VERBOSE, kTestProviderFlags));
+
+  provider.WaitForCallback();
+
+  EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level());
+  EXPECT_EQ(kTestProviderFlags, provider.enable_flags());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_));
+
+  provider.WaitForCallback();
+
+  EXPECT_EQ(0, provider.enable_level());
+  EXPECT_EQ(0, provider.enable_flags());
+
+  EXPECT_EQ(ERROR_SUCCESS, provider.Unregister());
+
+  // Enable the provider again, before registering.
+  EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
+                           TRACE_LEVEL_VERBOSE, kTestProviderFlags));
+
+  // Register the provider again, the settings above
+  // should take immediate effect.
+  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+
+  EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level());
+  EXPECT_EQ(kTestProviderFlags, provider.enable_flags());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+
+  provider.WaitForCallback();
+
+  // Session should have wound down.
+  EXPECT_EQ(0, provider.enable_level());
+  EXPECT_EQ(0, provider.enable_flags());
+}
diff --git a/base/win/event_trace_provider.cc b/base/win/event_trace_provider.cc
new file mode 100644
index 0000000..8fcf67d
--- /dev/null
+++ b/base/win/event_trace_provider.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#include "base/win/event_trace_provider.h"
+#include <windows.h>
+#include <cguid.h>
+
+namespace base {
+namespace win {
+
+TRACE_GUID_REGISTRATION EtwTraceProvider::obligatory_guid_registration_ = {
+  &GUID_NULL,
+  NULL
+};
+
+EtwTraceProvider::EtwTraceProvider(const GUID& provider_name)
+    : provider_name_(provider_name), registration_handle_(NULL),
+      session_handle_(NULL), enable_flags_(0), enable_level_(0) {
+}
+
+EtwTraceProvider::EtwTraceProvider()
+    : provider_name_(GUID_NULL), registration_handle_(NULL),
+      session_handle_(NULL), enable_flags_(0), enable_level_(0) {
+}
+
+EtwTraceProvider::~EtwTraceProvider() {
+  Unregister();
+}
+
+ULONG EtwTraceProvider::EnableEvents(void* buffer) {
+  session_handle_ = ::GetTraceLoggerHandle(buffer);
+  if (NULL == session_handle_) {
+    return ::GetLastError();
+  }
+
+  enable_flags_ = ::GetTraceEnableFlags(session_handle_);
+  enable_level_ = ::GetTraceEnableLevel(session_handle_);
+
+  // Give subclasses a chance to digest the state change.
+  OnEventsEnabled();
+
+  return ERROR_SUCCESS;
+}
+
+ULONG EtwTraceProvider::DisableEvents() {
+  // Give subclasses a chance to digest the state change.
+  OnEventsDisabled();
+
+  enable_level_ = 0;
+  enable_flags_ = 0;
+  session_handle_ = NULL;
+
+  PostEventsDisabled();
+
+  return ERROR_SUCCESS;
+}
+
+ULONG EtwTraceProvider::Callback(WMIDPREQUESTCODE request, void* buffer) {
+  switch (request) {
+    case WMI_ENABLE_EVENTS:
+      return EnableEvents(buffer);
+    case WMI_DISABLE_EVENTS:
+      return DisableEvents();
+    default:
+      return ERROR_INVALID_PARAMETER;
+  }
+  // Not reached.
+}
+
+ULONG WINAPI EtwTraceProvider::ControlCallback(WMIDPREQUESTCODE request,
+    void* context, ULONG *reserved, void* buffer) {
+  EtwTraceProvider *provider = reinterpret_cast<EtwTraceProvider*>(context);
+
+  return provider->Callback(request, buffer);
+}
+
+ULONG EtwTraceProvider::Register() {
+  if (provider_name_ == GUID_NULL)
+    return ERROR_INVALID_NAME;
+
+  return ::RegisterTraceGuids(ControlCallback, this, &provider_name_,
+      1, &obligatory_guid_registration_, NULL, NULL, &registration_handle_);
+}
+
+ULONG EtwTraceProvider::Unregister() {
+  // If a session is active, notify subclasses that it's going away.
+  if (session_handle_ != NULL)
+    DisableEvents();
+
+  ULONG ret = ::UnregisterTraceGuids(registration_handle_);
+
+  registration_handle_ = NULL;
+
+  return ret;
+}
+
+ULONG EtwTraceProvider::Log(const EtwEventClass& event_class,
+    EtwEventType type, EtwEventLevel level, const char *message) {
+  if (NULL == session_handle_ || enable_level_ < level)
+    return ERROR_SUCCESS;  // No one listening.
+
+  EtwMofEvent<1> event(event_class, type, level);
+
+  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(message);
+  event.fields[0].Length = message ?
+      static_cast<ULONG>(sizeof(message[0]) * (1 + strlen(message))) : 0;
+
+  return ::TraceEvent(session_handle_, &event.header);
+}
+
+ULONG EtwTraceProvider::Log(const EtwEventClass& event_class,
+    EtwEventType type, EtwEventLevel level, const wchar_t *message) {
+  if (NULL == session_handle_ || enable_level_ < level)
+    return ERROR_SUCCESS;  // No one listening.
+
+  EtwMofEvent<1> event(event_class, type, level);
+
+  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(message);
+  event.fields[0].Length = message ?
+      static_cast<ULONG>(sizeof(message[0]) * (1 + wcslen(message))) : 0;
+
+  return ::TraceEvent(session_handle_, &event.header);
+}
+
+ULONG EtwTraceProvider::Log(EVENT_TRACE_HEADER* event) {
+  if (enable_level_ < event->Class.Level)
+    return ERROR_SUCCESS;
+
+  return ::TraceEvent(session_handle_, event);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_provider.h b/base/win/event_trace_provider.h
new file mode 100644
index 0000000..9f6e7c4
--- /dev/null
+++ b/base/win/event_trace_provider.h
@@ -0,0 +1,175 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Declaration of a Windows event trace provider class, to allow using
+// Windows Event Tracing for logging transport and control.
+#ifndef BASE_WIN_EVENT_TRACE_PROVIDER_H_
+#define BASE_WIN_EVENT_TRACE_PROVIDER_H_
+
+#include <windows.h>
+#include <wmistr.h>
+#include <evntrace.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+typedef GUID EtwEventClass;
+typedef UCHAR EtwEventType;
+typedef UCHAR EtwEventLevel;
+typedef USHORT EtwEventVersion;
+typedef ULONG EtwEventFlags;
+
+// Base class is a POD for correctness.
+template <size_t N> struct EtwMofEventBase {
+  EVENT_TRACE_HEADER header;
+  MOF_FIELD fields[N];
+};
+
+// Utility class to auto-initialize event trace header structures.
+template <size_t N> class EtwMofEvent: public EtwMofEventBase<N> {
+ public:
+  typedef EtwMofEventBase<N> Super;
+
+  EtwMofEvent() {
+    memset(static_cast<Super*>(this), 0, sizeof(Super));
+  }
+
+  EtwMofEvent(const EtwEventClass& event_class, EtwEventType type,
+              EtwEventLevel level) {
+    memset(static_cast<Super*>(this), 0, sizeof(Super));
+    header.Size = sizeof(Super);
+    header.Guid = event_class;
+    header.Class.Type = type;
+    header.Class.Level = level;
+    header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
+  }
+
+  EtwMofEvent(const EtwEventClass& event_class, EtwEventType type,
+              EtwEventVersion version, EtwEventLevel level) {
+    memset(static_cast<Super*>(this), 0, sizeof(Super));
+    header.Size = sizeof(Super);
+    header.Guid = event_class;
+    header.Class.Type = type;
+    header.Class.Version = version;
+    header.Class.Level = level;
+    header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
+  }
+
+  void SetField(int field, size_t size, const void *data) {
+    // DCHECK(field < N);
+    if ((field < N) && (size <= kuint32max)) {
+      fields[field].DataPtr = reinterpret_cast<ULONG64>(data);
+      fields[field].Length = static_cast<ULONG>(size);
+    }
+  }
+
+  EVENT_TRACE_HEADER* get() { return& header; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EtwMofEvent);
+};
+
+// Trace provider with Event Tracing for Windows. The trace provider
+// registers with ETW by its name which is a GUID. ETW calls back to
+// the object whenever the trace level or enable flags for this provider
+// name changes.
+// Users of this class can test whether logging is currently enabled at
+// a particular trace level, and whether particular enable flags are set,
+// before other resources are consumed to generate and issue the log
+// messages themselves.
+class BASE_EXPORT EtwTraceProvider {
+ public:
+  // Creates an event trace provider identified by provider_name, which
+  // will be the name registered with Event Tracing for Windows (ETW).
+  explicit EtwTraceProvider(const GUID& provider_name);
+
+  // Creates an unnamed event trace provider, the provider must be given
+  // a name before registration.
+  EtwTraceProvider();
+  virtual ~EtwTraceProvider();
+
+  // Registers the trace provider with Event Tracing for Windows.
+  // Note: from this point forward ETW may call the provider's control
+  //    callback. If the provider's name is enabled in some trace session
+  //    already, the callback may occur recursively from this call, so
+  //    call this only when you're ready to handle callbacks.
+  ULONG Register();
+  // Unregisters the trace provider with ETW.
+  ULONG Unregister();
+
+  // Accessors.
+  void set_provider_name(const GUID& provider_name) {
+    provider_name_ = provider_name;
+  }
+  const GUID& provider_name() const { return provider_name_; }
+  TRACEHANDLE registration_handle() const { return registration_handle_; }
+  TRACEHANDLE session_handle() const { return session_handle_; }
+  EtwEventFlags enable_flags() const { return enable_flags_; }
+  EtwEventLevel enable_level() const { return enable_level_; }
+
+  // Returns true iff logging should be performed for "level" and "flags".
+  // Note: flags is treated as a bitmask, and should normally have a single
+  //      bit set, to test whether to log for a particular sub "facility".
+  bool ShouldLog(EtwEventLevel level, EtwEventFlags flags) {
+    return NULL != session_handle_ && level >= enable_level_ &&
+        (0 != (flags & enable_flags_));
+  }
+
+  // Simple wrappers to log Unicode and ANSI strings.
+  // Do nothing if !ShouldLog(level, 0xFFFFFFFF).
+  ULONG Log(const EtwEventClass& event_class, EtwEventType type,
+            EtwEventLevel level, const char *message);
+  ULONG Log(const EtwEventClass& event_class, EtwEventType type,
+            EtwEventLevel level, const wchar_t *message);
+
+  // Log the provided event.
+  ULONG Log(EVENT_TRACE_HEADER* event);
+
+ protected:
+  // Called after events have been enabled, override in subclasses
+  // to set up state or log at the start of a session.
+  // Note: This function may be called ETW's thread and may be racy,
+  //    bring your own locking if needed.
+  virtual void OnEventsEnabled() {}
+
+  // Called just before events are disabled, override in subclasses
+  // to tear down state or log at the end of a session.
+  // Note: This function may be called ETW's thread and may be racy,
+  //    bring your own locking if needed.
+  virtual void OnEventsDisabled() {}
+
+  // Called just after events have been disabled, override in subclasses
+  // to tear down state at the end of a session. At this point it's
+  // to late to log anything to the session.
+  // Note: This function may be called ETW's thread and may be racy,
+  //    bring your own locking if needed.
+  virtual void PostEventsDisabled() {}
+
+ private:
+  ULONG EnableEvents(PVOID buffer);
+  ULONG DisableEvents();
+  ULONG Callback(WMIDPREQUESTCODE request, PVOID buffer);
+  static ULONG WINAPI ControlCallback(WMIDPREQUESTCODE request, PVOID context,
+                                      ULONG *reserved, PVOID buffer);
+
+  GUID provider_name_;
+  TRACEHANDLE registration_handle_;
+  TRACEHANDLE session_handle_;
+  EtwEventFlags enable_flags_;
+  EtwEventLevel enable_level_;
+
+  // We don't use this, but on XP we're obliged to pass one in to
+  // RegisterTraceGuids. Non-const, because that's how the API needs it.
+  static TRACE_GUID_REGISTRATION obligatory_guid_registration_;
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceProvider);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_EVENT_TRACE_PROVIDER_H_
diff --git a/base/win/event_trace_provider_unittest.cc b/base/win/event_trace_provider_unittest.cc
new file mode 100644
index 0000000..55b5ae6
--- /dev/null
+++ b/base/win/event_trace_provider_unittest.cc
@@ -0,0 +1,110 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for event trace provider.
+#include "base/win/event_trace_provider.h"
+#include <new>
+#include "testing/gtest/include/gtest/gtest.h"
+#include <initguid.h>  // NOLINT - has to be last
+
+namespace {
+
+using base::win::EtwTraceProvider;
+using base::win::EtwMofEvent;
+
+// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2}
+DEFINE_GUID(kTestProvider,
+  0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2);
+
+// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2}
+DEFINE_GUID(kTestEventClass,
+  0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2);
+
+}  // namespace
+
+TEST(EtwTraceProviderTest, ToleratesPreCreateInvocations) {
+  // Because the trace provider is used in logging, it's important that
+  // it be possible to use static provider instances without regard to
+  // whether they've been constructed or destructed.
+  // The interface of the class is designed to tolerate this usage.
+  char buf[sizeof(EtwTraceProvider)] = {0};
+  EtwTraceProvider& provider = reinterpret_cast<EtwTraceProvider&>(buf);
+
+  EXPECT_EQ(NULL, provider.registration_handle());
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+
+  EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff));
+
+  // We expect these not to crash.
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, "foo");
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, L"foo");
+
+  EtwMofEvent<1> dummy(kTestEventClass, 0, TRACE_LEVEL_FATAL);
+  DWORD data = 0;
+  dummy.SetField(0, sizeof(data), &data);
+  provider.Log(dummy.get());
+
+  // Placement-new the provider into our buffer.
+  new (buf) EtwTraceProvider(kTestProvider);
+
+  // Registration is now safe.
+  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+
+  // Destruct the instance, this should unregister it.
+  provider.EtwTraceProvider::~EtwTraceProvider();
+
+  // And post-destruction, all of the above should still be safe.
+  EXPECT_EQ(NULL, provider.registration_handle());
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+
+  EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff));
+
+  // We expect these not to crash.
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, "foo");
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, L"foo");
+  provider.Log(dummy.get());
+}
+
+TEST(EtwTraceProviderTest, Initialize) {
+  EtwTraceProvider provider(kTestProvider);
+
+  EXPECT_EQ(NULL, provider.registration_handle());
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+}
+
+TEST(EtwTraceProviderTest, Register) {
+  EtwTraceProvider provider(kTestProvider);
+
+  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_NE(NULL, provider.registration_handle());
+  ASSERT_EQ(ERROR_SUCCESS, provider.Unregister());
+  EXPECT_EQ(NULL, provider.registration_handle());
+}
+
+TEST(EtwTraceProviderTest, RegisterWithNoNameFails) {
+  EtwTraceProvider provider;
+
+  EXPECT_TRUE(provider.Register() != ERROR_SUCCESS);
+}
+
+TEST(EtwTraceProviderTest, Enable) {
+  EtwTraceProvider provider(kTestProvider);
+
+  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_NE(NULL, provider.registration_handle());
+
+  // No session so far.
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+
+  ASSERT_EQ(ERROR_SUCCESS, provider.Unregister());
+  EXPECT_EQ(NULL, provider.registration_handle());
+}
diff --git a/base/win/i18n.cc b/base/win/i18n.cc
new file mode 100644
index 0000000..9e523a1
--- /dev/null
+++ b/base/win/i18n.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/i18n.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace {
+
+// Keep this enum in sync with kLanguageFunctionNames.
+enum LanguageFunction {
+  SYSTEM_LANGUAGES,
+  USER_LANGUAGES,
+  PROCESS_LANGUAGES,
+  THREAD_LANGUAGES,
+  NUM_FUNCTIONS
+};
+
+const char kSystemLanguagesFunctionName[] = "GetSystemPreferredUILanguages";
+const char kUserLanguagesFunctionName[] = "GetUserPreferredUILanguages";
+const char kProcessLanguagesFunctionName[] = "GetProcessPreferredUILanguages";
+const char kThreadLanguagesFunctionName[] = "GetThreadPreferredUILanguages";
+
+// Keep this array in sync with enum LanguageFunction.
+const char *const kLanguageFunctionNames[] = {
+  &kSystemLanguagesFunctionName[0],
+  &kUserLanguagesFunctionName[0],
+  &kProcessLanguagesFunctionName[0],
+  &kThreadLanguagesFunctionName[0]
+};
+
+COMPILE_ASSERT(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames),
+               language_function_enum_and_names_out_of_sync);
+
+// Calls one of the MUI Get*PreferredUILanguages functions, placing the result
+// in |languages|.  |function| identifies the function to call and |flags| is
+// the function-specific flags (callers must not specify MUI_LANGUAGE_ID or
+// MUI_LANGUAGE_NAME).  Returns true if at least one language is placed in
+// |languages|.
+bool GetMUIPreferredUILanguageList(LanguageFunction function, ULONG flags,
+                                   std::vector<wchar_t>* languages) {
+  DCHECK(0 <= function && NUM_FUNCTIONS > function);
+  DCHECK_EQ(0U, (flags & (MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME)));
+  DCHECK(languages);
+
+  HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+  if (NULL != kernel32) {
+    typedef BOOL (WINAPI* GetPreferredUILanguages_Fn)(
+        DWORD, PULONG, PZZWSTR, PULONG);
+    GetPreferredUILanguages_Fn get_preferred_ui_languages =
+        reinterpret_cast<GetPreferredUILanguages_Fn>(
+            GetProcAddress(kernel32, kLanguageFunctionNames[function]));
+    if (NULL != get_preferred_ui_languages) {
+      const ULONG call_flags = flags | MUI_LANGUAGE_NAME;
+      ULONG language_count = 0;
+      ULONG buffer_length = 0;
+      if (get_preferred_ui_languages(call_flags, &language_count, NULL,
+                                     &buffer_length) &&
+          0 != buffer_length) {
+        languages->resize(buffer_length);
+        if (get_preferred_ui_languages(call_flags, &language_count,
+                                       &(*languages)[0], &buffer_length) &&
+            0 != language_count) {
+          DCHECK(languages->size() == buffer_length);
+          return true;
+        } else {
+          DPCHECK(0 == language_count)
+              << "Failed getting preferred UI languages.";
+        }
+      } else {
+        DPCHECK(0 == buffer_length)
+            << "Failed getting size of preferred UI languages.";
+      }
+    } else {
+      DVLOG(2) << "MUI not available.";
+    }
+  } else {
+    NOTREACHED() << "kernel32.dll not found.";
+  }
+
+  return false;
+}
+
+bool GetUserDefaultUILanguage(std::wstring* language, std::wstring* region) {
+  DCHECK(language);
+
+  LANGID lang_id = ::GetUserDefaultUILanguage();
+  if (LOCALE_CUSTOM_UI_DEFAULT != lang_id) {
+    const LCID locale_id = MAKELCID(lang_id, SORT_DEFAULT);
+    // max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9
+    wchar_t result_buffer[9];
+    int result_length =
+        GetLocaleInfo(locale_id, LOCALE_SISO639LANGNAME, &result_buffer[0],
+                      arraysize(result_buffer));
+    DPCHECK(0 != result_length) << "Failed getting language id";
+    if (1 < result_length) {
+      language->assign(&result_buffer[0], result_length - 1);
+      region->clear();
+      if (SUBLANG_NEUTRAL != SUBLANGID(lang_id)) {
+        result_length =
+            GetLocaleInfo(locale_id, LOCALE_SISO3166CTRYNAME, &result_buffer[0],
+                          arraysize(result_buffer));
+        DPCHECK(0 != result_length) << "Failed getting region id";
+        if (1 < result_length)
+          region->assign(&result_buffer[0], result_length - 1);
+      }
+      return true;
+    }
+  } else {
+    // This is entirely unexpected on pre-Vista, which is the only time we
+    // should try GetUserDefaultUILanguage anyway.
+    NOTREACHED() << "Cannot determine language for a supplemental locale.";
+  }
+  return false;
+}
+
+bool GetPreferredUILanguageList(LanguageFunction function, ULONG flags,
+                                std::vector<std::wstring>* languages) {
+  std::vector<wchar_t> buffer;
+  std::wstring language;
+  std::wstring region;
+
+  if (GetMUIPreferredUILanguageList(function, flags, &buffer)) {
+    std::vector<wchar_t>::const_iterator scan = buffer.begin();
+    language.assign(&*scan);
+    while (!language.empty()) {
+      languages->push_back(language);
+      scan += language.size() + 1;
+      language.assign(&*scan);
+    }
+  } else if (GetUserDefaultUILanguage(&language, &region)) {
+    // Mimic the MUI behavior of putting the neutral version of the lang after
+    // the regional one (e.g., "fr-CA, fr").
+    if (!region.empty())
+      languages->push_back(std::wstring(language)
+                               .append(1, L'-')
+                               .append(region));
+    languages->push_back(language);
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+namespace win {
+namespace i18n {
+
+bool GetUserPreferredUILanguageList(std::vector<std::wstring>* languages) {
+  DCHECK(languages);
+  return GetPreferredUILanguageList(USER_LANGUAGES, 0, languages);
+}
+
+bool GetThreadPreferredUILanguageList(std::vector<std::wstring>* languages) {
+  DCHECK(languages);
+  return GetPreferredUILanguageList(
+      THREAD_LANGUAGES, MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK,
+      languages);
+}
+
+}  // namespace i18n
+}  // namespace win
+}  // namespace base
diff --git a/base/win/i18n.h b/base/win/i18n.h
new file mode 100644
index 0000000..c0379c1
--- /dev/null
+++ b/base/win/i18n.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_I18N_H_
+#define BASE_WIN_I18N_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+namespace i18n {
+
+// Adds to |languages| the list of user preferred UI languages from MUI, if
+// available, falling-back on the user default UI language otherwise.  Returns
+// true if at least one language is added.
+BASE_EXPORT bool GetUserPreferredUILanguageList(
+    std::vector<std::wstring>* languages);
+
+// Adds to |languages| the list of thread, process, user, and system preferred
+// UI languages from MUI, if available, falling-back on the user default UI
+// language otherwise.  Returns true if at least one language is added.
+BASE_EXPORT bool GetThreadPreferredUILanguageList(
+    std::vector<std::wstring>* languages);
+
+}  // namespace i18n
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_I18N_H_
diff --git a/base/win/i18n_unittest.cc b/base/win/i18n_unittest.cc
new file mode 100644
index 0000000..781fc39
--- /dev/null
+++ b/base/win/i18n_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for Windows internationalization funcs.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/win/i18n.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+namespace i18n {
+
+// Tests that at least one user preferred UI language can be obtained.
+TEST(I18NTest, GetUserPreferredUILanguageList) {
+  std::vector<std::wstring> languages;
+  EXPECT_TRUE(GetUserPreferredUILanguageList(&languages));
+  EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0),
+            languages.size());
+  for (std::vector<std::wstring>::const_iterator scan = languages.begin(),
+          end = languages.end(); scan != end; ++scan) {
+    EXPECT_FALSE((*scan).empty());
+  }
+}
+
+// Tests that at least one thread preferred UI language can be obtained.
+TEST(I18NTest, GetThreadPreferredUILanguageList) {
+  std::vector<std::wstring> languages;
+  EXPECT_TRUE(GetThreadPreferredUILanguageList(&languages));
+  EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0),
+            languages.size());
+  for (std::vector<std::wstring>::const_iterator scan = languages.begin(),
+          end = languages.end(); scan != end; ++scan) {
+    EXPECT_FALSE((*scan).empty());
+  }
+}
+
+}  // namespace i18n
+}  // namespace win
+}  // namespace base
diff --git a/base/win/iat_patch_function.cc b/base/win/iat_patch_function.cc
new file mode 100644
index 0000000..a4a8902
--- /dev/null
+++ b/base/win/iat_patch_function.cc
@@ -0,0 +1,278 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/iat_patch_function.h"
+
+#include "base/logging.h"
+#include "base/win/pe_image.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct InterceptFunctionInformation {
+  bool finished_operation;
+  const char* imported_from_module;
+  const char* function_name;
+  void* new_function;
+  void** old_function;
+  IMAGE_THUNK_DATA** iat_thunk;
+  DWORD return_code;
+};
+
+void* GetIATFunction(IMAGE_THUNK_DATA* iat_thunk) {
+  if (NULL == iat_thunk) {
+    NOTREACHED();
+    return NULL;
+  }
+
+  // Works around the 64 bit portability warning:
+  // The Function member inside IMAGE_THUNK_DATA is really a pointer
+  // to the IAT function. IMAGE_THUNK_DATA correctly maps to IMAGE_THUNK_DATA32
+  // or IMAGE_THUNK_DATA64 for correct pointer size.
+  union FunctionThunk {
+    IMAGE_THUNK_DATA thunk;
+    void* pointer;
+  } iat_function;
+
+  iat_function.thunk = *iat_thunk;
+  return iat_function.pointer;
+}
+// Change the page protection (of code pages) to writable and copy
+// the data at the specified location
+//
+// Arguments:
+// old_code               Target location to copy
+// new_code               Source
+// length                 Number of bytes to copy
+//
+// Returns: Windows error code (winerror.h). NO_ERROR if successful
+DWORD ModifyCode(void* old_code, void* new_code, int length) {
+  if ((NULL == old_code) || (NULL == new_code) || (0 == length)) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  // Change the page protection so that we can write.
+  DWORD error = NO_ERROR;
+  DWORD old_page_protection = 0;
+  if (VirtualProtect(old_code,
+                     length,
+                     PAGE_READWRITE,
+                     &old_page_protection)) {
+
+    // Write the data.
+    CopyMemory(old_code, new_code, length);
+
+    // Restore the old page protection.
+    error = ERROR_SUCCESS;
+    VirtualProtect(old_code,
+                  length,
+                  old_page_protection,
+                  &old_page_protection);
+  } else {
+    error = GetLastError();
+    NOTREACHED();
+  }
+
+  return error;
+}
+
+bool InterceptEnumCallback(const base::win::PEImage& image, const char* module,
+                           DWORD ordinal, const char* name, DWORD hint,
+                           IMAGE_THUNK_DATA* iat, void* cookie) {
+  InterceptFunctionInformation* intercept_information =
+    reinterpret_cast<InterceptFunctionInformation*>(cookie);
+
+  if (NULL == intercept_information) {
+    NOTREACHED();
+    return false;
+  }
+
+  DCHECK(module);
+
+  if ((0 == lstrcmpiA(module, intercept_information->imported_from_module)) &&
+     (NULL != name) &&
+     (0 == lstrcmpiA(name, intercept_information->function_name))) {
+    // Save the old pointer.
+    if (NULL != intercept_information->old_function) {
+      *(intercept_information->old_function) = GetIATFunction(iat);
+    }
+
+    if (NULL != intercept_information->iat_thunk) {
+      *(intercept_information->iat_thunk) = iat;
+    }
+
+    // portability check
+    COMPILE_ASSERT(sizeof(iat->u1.Function) ==
+      sizeof(intercept_information->new_function), unknown_IAT_thunk_format);
+
+    // Patch the function.
+    intercept_information->return_code =
+      ModifyCode(&(iat->u1.Function),
+                 &(intercept_information->new_function),
+                 sizeof(intercept_information->new_function));
+
+    // Terminate further enumeration.
+    intercept_information->finished_operation = true;
+    return false;
+  }
+
+  return true;
+}
+
+// Helper to intercept a function in an import table of a specific
+// module.
+//
+// Arguments:
+// module_handle          Module to be intercepted
+// imported_from_module   Module that exports the symbol
+// function_name          Name of the API to be intercepted
+// new_function           Interceptor function
+// old_function           Receives the original function pointer
+// iat_thunk              Receives pointer to IAT_THUNK_DATA
+//                        for the API from the import table.
+//
+// Returns: Returns NO_ERROR on success or Windows error code
+//          as defined in winerror.h
+DWORD InterceptImportedFunction(HMODULE module_handle,
+                                const char* imported_from_module,
+                                const char* function_name, void* new_function,
+                                void** old_function,
+                                IMAGE_THUNK_DATA** iat_thunk) {
+  if ((NULL == module_handle) || (NULL == imported_from_module) ||
+     (NULL == function_name) || (NULL == new_function)) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  base::win::PEImage target_image(module_handle);
+  if (!target_image.VerifyMagic()) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  InterceptFunctionInformation intercept_information = {
+    false,
+    imported_from_module,
+    function_name,
+    new_function,
+    old_function,
+    iat_thunk,
+    ERROR_GEN_FAILURE};
+
+  // First go through the IAT. If we don't find the import we are looking
+  // for in IAT, search delay import table.
+  target_image.EnumAllImports(InterceptEnumCallback, &intercept_information);
+  if (!intercept_information.finished_operation) {
+    target_image.EnumAllDelayImports(InterceptEnumCallback,
+                                     &intercept_information);
+  }
+
+  return intercept_information.return_code;
+}
+
+// Restore intercepted IAT entry with the original function.
+//
+// Arguments:
+// intercept_function     Interceptor function
+// original_function      Receives the original function pointer
+//
+// Returns: Returns NO_ERROR on success or Windows error code
+//          as defined in winerror.h
+DWORD RestoreImportedFunction(void* intercept_function,
+                              void* original_function,
+                              IMAGE_THUNK_DATA* iat_thunk) {
+  if ((NULL == intercept_function) || (NULL == original_function) ||
+      (NULL == iat_thunk)) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  if (GetIATFunction(iat_thunk) != intercept_function) {
+    // Check if someone else has intercepted on top of us.
+    // We cannot unpatch in this case, just raise a red flag.
+    NOTREACHED();
+    return ERROR_INVALID_FUNCTION;
+  }
+
+  return ModifyCode(&(iat_thunk->u1.Function),
+                    &original_function,
+                    sizeof(original_function));
+}
+
+}  // namespace
+
+IATPatchFunction::IATPatchFunction()
+    : module_handle_(NULL),
+      original_function_(NULL),
+      iat_thunk_(NULL),
+      intercept_function_(NULL) {
+}
+
+IATPatchFunction::~IATPatchFunction() {
+  if (NULL != intercept_function_) {
+    DWORD error = Unpatch();
+    DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
+  }
+}
+
+DWORD IATPatchFunction::Patch(const wchar_t* module,
+                              const char* imported_from_module,
+                              const char* function_name,
+                              void* new_function) {
+  DCHECK_EQ(static_cast<void*>(NULL), original_function_);
+  DCHECK_EQ(static_cast<IMAGE_THUNK_DATA*>(NULL), iat_thunk_);
+  DCHECK_EQ(static_cast<void*>(NULL), intercept_function_);
+
+  HMODULE module_handle = LoadLibraryW(module);
+
+  if (module_handle == NULL) {
+    NOTREACHED();
+    return GetLastError();
+  }
+
+  DWORD error = InterceptImportedFunction(module_handle,
+                                          imported_from_module,
+                                          function_name,
+                                          new_function,
+                                          &original_function_,
+                                          &iat_thunk_);
+
+  if (NO_ERROR == error) {
+    DCHECK_NE(original_function_, intercept_function_);
+    module_handle_ = module_handle;
+    intercept_function_ = new_function;
+  } else {
+    FreeLibrary(module_handle);
+  }
+
+  return error;
+}
+
+DWORD IATPatchFunction::Unpatch() {
+  DWORD error = RestoreImportedFunction(intercept_function_,
+                                        original_function_,
+                                        iat_thunk_);
+  DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
+
+  // Hands off the intercept if we fail to unpatch.
+  // If IATPatchFunction::Unpatch fails during RestoreImportedFunction
+  // it means that we cannot safely unpatch the import address table
+  // patch. In this case its better to be hands off the intercept as
+  // trying to unpatch again in the destructor of IATPatchFunction is
+  // not going to be any safer
+  if (module_handle_)
+    FreeLibrary(module_handle_);
+  module_handle_ = NULL;
+  intercept_function_ = NULL;
+  original_function_ = NULL;
+  iat_thunk_ = NULL;
+
+  return error;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/iat_patch_function.h b/base/win/iat_patch_function.h
new file mode 100644
index 0000000..3ae1f3c
--- /dev/null
+++ b/base/win/iat_patch_function.h
@@ -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.
+
+#ifndef BASE_WIN_IAT_PATCH_FUNCTION_H_
+#define BASE_WIN_IAT_PATCH_FUNCTION_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// A class that encapsulates Import Address Table patching helpers and restores
+// the original function in the destructor.
+//
+// It will intercept functions for a specific DLL imported from another DLL.
+// This is the case when, for example, we want to intercept
+// CertDuplicateCertificateContext function (exported from crypt32.dll) called
+// by wininet.dll.
+class BASE_EXPORT IATPatchFunction {
+ public:
+  IATPatchFunction();
+  ~IATPatchFunction();
+
+  // Intercept a function in an import table of a specific
+  // module. Save the original function and the import
+  // table address. These values will be used later
+  // during Unpatch
+  //
+  // Arguments:
+  // module                 Module to be intercepted
+  // imported_from_module   Module that exports the 'function_name'
+  // function_name          Name of the API to be intercepted
+  //
+  // Returns: Windows error code (winerror.h). NO_ERROR if successful
+  //
+  // Note: Patching a function will make the IAT patch take some "ownership" on
+  // |module|.  It will LoadLibrary(module) to keep the DLL alive until a call
+  // to Unpatch(), which will call FreeLibrary() and allow the module to be
+  // unloaded.  The idea is to help prevent the DLL from going away while a
+  // patch is still active.
+  DWORD Patch(const wchar_t* module,
+              const char* imported_from_module,
+              const char* function_name,
+              void* new_function);
+
+  // Unpatch the IAT entry using internally saved original
+  // function.
+  //
+  // Returns: Windows error code (winerror.h). NO_ERROR if successful
+  DWORD Unpatch();
+
+  bool is_patched() const {
+    return (NULL != intercept_function_);
+  }
+
+ private:
+  HMODULE module_handle_;
+  void* intercept_function_;
+  void* original_function_;
+  IMAGE_THUNK_DATA* iat_thunk_;
+
+  DISALLOW_COPY_AND_ASSIGN(IATPatchFunction);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_IAT_PATCH_FUNCTION_H_
diff --git a/base/win/iunknown_impl.cc b/base/win/iunknown_impl.cc
new file mode 100644
index 0000000..9baa0f3
--- /dev/null
+++ b/base/win/iunknown_impl.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/iunknown_impl.h"
+
+namespace base {
+namespace win {
+
+IUnknownImpl::IUnknownImpl()
+    : ref_count_(0) {
+}
+
+IUnknownImpl::~IUnknownImpl() {
+}
+
+ULONG STDMETHODCALLTYPE IUnknownImpl::AddRef() {
+  base::AtomicRefCountInc(&ref_count_);
+  return 1;
+}
+
+ULONG STDMETHODCALLTYPE IUnknownImpl::Release() {
+  if (!base::AtomicRefCountDec(&ref_count_)) {
+    delete this;
+    return 0;
+  }
+  return 1;
+}
+
+STDMETHODIMP IUnknownImpl::QueryInterface(REFIID riid, void** ppv) {
+  if (riid == IID_IUnknown) {
+    *ppv = static_cast<IUnknown*>(this);
+    AddRef();
+    return S_OK;
+  }
+
+  *ppv = NULL;
+  return E_NOINTERFACE;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/iunknown_impl.h b/base/win/iunknown_impl.h
new file mode 100644
index 0000000..ff7e870
--- /dev/null
+++ b/base/win/iunknown_impl.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_IUNKNOWN_IMPL_H_
+#define BASE_WIN_IUNKNOWN_IMPL_H_
+
+#include <unknwn.h>
+
+#include "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace win {
+
+// IUnknown implementation for other classes to derive from.
+class BASE_EXPORT IUnknownImpl : public IUnknown {
+ public:
+  IUnknownImpl();
+
+  virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE;
+  virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE;
+
+  // Subclasses should extend this to return any interfaces they provide.
+  virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv) OVERRIDE;
+
+ protected:
+  virtual ~IUnknownImpl();
+
+ private:
+  AtomicRefCount ref_count_;
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_IUNKNOWN_IMPL_H_
diff --git a/base/win/iunknown_impl_unittest.cc b/base/win/iunknown_impl_unittest.cc
new file mode 100644
index 0000000..db86214
--- /dev/null
+++ b/base/win/iunknown_impl_unittest.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/iunknown_impl.h"
+
+#include "base/win/scoped_com_initializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+class TestIUnknownImplSubclass : public IUnknownImpl {
+ public:
+  TestIUnknownImplSubclass() {
+    ++instance_count;
+  }
+  virtual ~TestIUnknownImplSubclass() {
+    --instance_count;
+  }
+  static int instance_count;
+};
+
+// static
+int TestIUnknownImplSubclass::instance_count = 0;
+
+TEST(IUnknownImplTest, IUnknownImpl) {
+  ScopedCOMInitializer com_initializer;
+
+  EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count);
+  IUnknown* u = new TestIUnknownImplSubclass();
+
+  EXPECT_EQ(1, TestIUnknownImplSubclass::instance_count);
+
+  EXPECT_EQ(1, u->AddRef());
+  EXPECT_EQ(1, u->AddRef());
+
+  IUnknown* other = NULL;
+  EXPECT_EQ(E_NOINTERFACE, u->QueryInterface(
+      IID_IDispatch, reinterpret_cast<void**>(&other)));
+  EXPECT_EQ(S_OK, u->QueryInterface(
+      IID_IUnknown, reinterpret_cast<void**>(&other)));
+  other->Release();
+
+  EXPECT_EQ(1, u->Release());
+  EXPECT_EQ(0, u->Release());
+  EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/metro.cc b/base/win/metro.cc
new file mode 100644
index 0000000..22bc5e8
--- /dev/null
+++ b/base/win/metro.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/win/metro.h"
+
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+namespace {
+bool g_should_tsf_aware_required = false;
+}
+
+HMODULE GetMetroModule() {
+  const HMODULE kUninitialized = reinterpret_cast<HMODULE>(1);
+  static HMODULE metro_module = kUninitialized;
+
+  if (metro_module == kUninitialized) {
+    // Initialize the cache, note that the initialization is idempotent
+    // under the assumption that metro_driver is never unloaded, so the
+    // race to this assignment is safe.
+    metro_module = GetModuleHandleA("metro_driver.dll");
+    if (metro_module != NULL) {
+      // This must be a metro process if the metro_driver is loaded.
+      DCHECK(IsMetroProcess());
+    }
+  }
+
+  DCHECK(metro_module != kUninitialized);
+  return metro_module;
+}
+
+bool IsMetroProcess() {
+  enum ImmersiveState {
+    kImmersiveUnknown,
+    kImmersiveTrue,
+    kImmersiveFalse
+  };
+  // The immersive state of a process can never change.
+  // Look it up once and cache it here.
+  static ImmersiveState state = kImmersiveUnknown;
+
+  if (state == kImmersiveUnknown) {
+    if (IsProcessImmersive(::GetCurrentProcess())) {
+      state = kImmersiveTrue;
+    } else {
+      state = kImmersiveFalse;
+    }
+  }
+  DCHECK_NE(kImmersiveUnknown, state);
+  return state == kImmersiveTrue;
+}
+
+bool IsProcessImmersive(HANDLE process) {
+  typedef BOOL (WINAPI* IsImmersiveProcessFunc)(HANDLE process);
+  HMODULE user32 = ::GetModuleHandleA("user32.dll");
+  DCHECK(user32 != NULL);
+
+  IsImmersiveProcessFunc is_immersive_process =
+      reinterpret_cast<IsImmersiveProcessFunc>(
+          ::GetProcAddress(user32, "IsImmersiveProcess"));
+
+  if (is_immersive_process)
+    return is_immersive_process(process) ? true: false;
+  return false;
+}
+
+bool IsTSFAwareRequired() {
+  // Although this function is equal to IsMetroProcess at this moment,
+  // Chrome for Win7 and Vista may support TSF in the future.
+  return g_should_tsf_aware_required || IsMetroProcess();
+}
+
+void SetForceToUseTSF() {
+  g_should_tsf_aware_required = true;
+
+  // Since Windows 8 Metro mode disables CUAS (Cicero Unaware Application
+  // Support) via ImmDisableLegacyIME API, Chrome must be fully TSF-aware on
+  // Metro mode. For debugging purposes, explicitly call ImmDisableLegacyIME so
+  // that one can test TSF functionality even on Windows 8 desktop mode. Note
+  // that CUAS cannot be disabled on Windows Vista/7 where ImmDisableLegacyIME
+  // is not available.
+  typedef BOOL (* ImmDisableLegacyIMEFunc)();
+  HMODULE imm32 = ::GetModuleHandleA("imm32.dll");
+  if (imm32 == NULL)
+    return;
+
+  ImmDisableLegacyIMEFunc imm_disable_legacy_ime =
+      reinterpret_cast<ImmDisableLegacyIMEFunc>(
+          ::GetProcAddress(imm32, "ImmDisableLegacyIME"));
+
+  if (imm_disable_legacy_ime == NULL) {
+    // Unsupported API, just do nothing.
+    return;
+  }
+
+  if (!imm_disable_legacy_ime()) {
+    DVLOG(1) << "Failed to disable legacy IME.";
+  }
+}
+
+wchar_t* LocalAllocAndCopyString(const string16& src) {
+  size_t dest_size = (src.length() + 1) * sizeof(wchar_t);
+  wchar_t* dest = reinterpret_cast<wchar_t*>(LocalAlloc(LPTR, dest_size));
+  base::wcslcpy(dest, src.c_str(), dest_size);
+  return dest;
+}
+
+bool IsTouchEnabled() {
+  int value = GetSystemMetrics(SM_DIGITIZER);
+  return (value & (NID_READY | NID_INTEGRATED_TOUCH)) ==
+             (NID_READY | NID_INTEGRATED_TOUCH);
+}
+
+bool IsParentalControlActivityLoggingOn() {
+  // Query this info on Windows Vista and above.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return false;
+
+  static bool parental_control_logging_required = false;
+  static bool parental_control_status_determined = false;
+
+  if (parental_control_status_determined)
+    return parental_control_logging_required;
+
+  parental_control_status_determined = true;
+
+  ScopedComPtr<IWindowsParentalControlsCore> parent_controls;
+  HRESULT hr = parent_controls.CreateInstance(
+      __uuidof(WindowsParentalControls));
+  if (FAILED(hr))
+    return false;
+
+  ScopedComPtr<IWPCSettings> settings;
+  hr = parent_controls->GetUserSettings(NULL, settings.Receive());
+  if (FAILED(hr))
+    return false;
+
+  unsigned long restrictions = 0;
+  settings->GetRestrictions(&restrictions);
+
+  parental_control_logging_required =
+      (restrictions & WPCFLAG_LOGGING_REQUIRED) == WPCFLAG_LOGGING_REQUIRED;
+  return parental_control_logging_required;
+}
+
+// Metro driver exports for getting the launch type, initial url, initial
+// search term, etc.
+extern "C" {
+typedef const wchar_t* (*GetInitialUrl)();
+typedef const wchar_t* (*GetInitialSearchString)();
+typedef base::win::MetroLaunchType (*GetLaunchType)(
+    base::win::MetroPreviousExecutionState* previous_state);
+}
+
+MetroLaunchType GetMetroLaunchParams(string16* params) {
+  HMODULE metro = base::win::GetMetroModule();
+  if (!metro)
+    return base::win::METRO_LAUNCH_ERROR;
+
+  GetLaunchType get_launch_type = reinterpret_cast<GetLaunchType>(
+      ::GetProcAddress(metro, "GetLaunchType"));
+  DCHECK(get_launch_type);
+
+  base::win::MetroLaunchType launch_type = get_launch_type(NULL);
+
+  if ((launch_type == base::win::METRO_PROTOCOL) ||
+      (launch_type == base::win::METRO_LAUNCH)) {
+    GetInitialUrl initial_metro_url = reinterpret_cast<GetInitialUrl>(
+        ::GetProcAddress(metro, "GetInitialUrl"));
+    DCHECK(initial_metro_url);
+    *params = initial_metro_url();
+  } else if (launch_type == base::win::METRO_SEARCH) {
+    GetInitialSearchString initial_search_string =
+        reinterpret_cast<GetInitialSearchString>(
+            ::GetProcAddress(metro, "GetInitialSearchString"));
+    DCHECK(initial_search_string);
+    *params = initial_search_string();
+  }
+  return launch_type;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/metro.h b/base/win/metro.h
new file mode 100644
index 0000000..a43bbc3
--- /dev/null
+++ b/base/win/metro.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 BASE_WIN_METRO_H_
+#define BASE_WIN_METRO_H_
+
+#include <windows.h>
+#include <wpcapi.h>
+
+#include "base/base_export.h"
+#include "base/string16.h"
+
+namespace base {
+namespace win {
+
+// Identifies the type of the metro launch.
+enum MetroLaunchType {
+  METRO_LAUNCH,
+  METRO_SEARCH,
+  METRO_SHARE,
+  METRO_FILE,
+  METRO_PROTOCOL,
+  METRO_LAUNCH_ERROR,
+  METRO_LASTLAUNCHTYPE,
+};
+
+// In metro mode, this enum identifies the last execution state, i.e. whether
+// we crashed, terminated, etc.
+enum MetroPreviousExecutionState {
+  NOTRUNNING,
+  RUNNING,
+  SUSPENDED,
+  TERMINATED,
+  CLOSEDBYUSER,
+  LASTEXECUTIONSTATE,
+};
+
+// Contains information about the currently displayed tab in metro mode.
+struct CurrentTabInfo {
+  wchar_t* title;
+  wchar_t* url;
+};
+
+// Returns the handle to the metro dll loaded in the process. A NULL return
+// indicates that the metro dll was not loaded in the process.
+BASE_EXPORT HMODULE GetMetroModule();
+
+// Returns true if this process is running as an immersive program
+// in Windows Metro mode.
+BASE_EXPORT bool IsMetroProcess();
+
+// Returns true if the process identified by the handle passed in is an
+// immersive (Metro) process.
+BASE_EXPORT bool IsProcessImmersive(HANDLE process);
+
+// Returns true if this process is running under Text Services Framework (TSF)
+// and browser must be TSF-aware.
+BASE_EXPORT bool IsTSFAwareRequired();
+
+// Sets browser to use Text Services Framework (TSF) regardless of process
+// status. On Windows 8, this function also disables CUAS (Cicero Unaware
+// Application Support) to emulate Windows Metro mode in terms of IME
+// functionality. This should be beneficial in QA process because on can test
+// IME functionality in Windows 8 desktop mode.
+BASE_EXPORT void SetForceToUseTSF();
+
+// Allocates and returns the destination string via the LocalAlloc API after
+// copying the src to it.
+BASE_EXPORT wchar_t* LocalAllocAndCopyString(const string16& src);
+
+// Returns true if the screen supports touch.
+BASE_EXPORT bool IsTouchEnabled();
+
+// Returns true if Windows Parental control activity logging is enabled. This
+// feature is available on Windows Vista and beyond.
+// This function should ideally be called on the UI thread.
+BASE_EXPORT bool IsParentalControlActivityLoggingOn();
+
+// Returns the type of launch and the activation params. For example if the
+// the launch is for METRO_PROTOCOL then the params is a url.
+BASE_EXPORT MetroLaunchType GetMetroLaunchParams(string16* params);
+
+// Handler function for the buttons on a metro dialog box
+typedef void (*MetroDialogButtonPressedHandler)();
+
+// Handler function invoked when a metro style notification is clicked.
+typedef void (*MetroNotificationClickedHandler)(const wchar_t* context);
+
+// Function to display metro style notifications.
+typedef void (*MetroNotification)(const char* origin_url,
+                                  const char* icon_url,
+                                  const wchar_t* title,
+                                  const wchar_t* body,
+                                  const wchar_t* display_source,
+                                  const char* notification_id,
+                                  MetroNotificationClickedHandler handler,
+                                  const wchar_t* handler_context);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_METRO_H_
diff --git a/base/win/object_watcher.cc b/base/win/object_watcher.cc
new file mode 100644
index 0000000..ebe596f
--- /dev/null
+++ b/base/win/object_watcher.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/object_watcher.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+//-----------------------------------------------------------------------------
+
+ObjectWatcher::ObjectWatcher()
+    : weak_factory_(this),
+      object_(NULL),
+      wait_object_(NULL),
+      origin_loop_(NULL) {
+}
+
+ObjectWatcher::~ObjectWatcher() {
+  StopWatching();
+}
+
+bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
+  CHECK(delegate);
+  if (wait_object_) {
+    NOTREACHED() << "Already watching an object";
+    return false;
+  }
+
+  // Since our job is to just notice when an object is signaled and report the
+  // result back to this thread, we can just run on a Windows wait thread.
+  DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE;
+
+  // DoneWaiting can be synchronously called from RegisterWaitForSingleObject,
+  // so set up all state now.
+  callback_ = base::Bind(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(),
+                         delegate);
+  object_ = object;
+  origin_loop_ = MessageLoop::current();
+
+  if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting,
+                                   this, INFINITE, wait_flags)) {
+    NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError();
+    object_ = NULL;
+    wait_object_ = NULL;
+    return false;
+  }
+
+  // We need to know if the current message loop is going away so we can
+  // prevent the wait thread from trying to access a dead message loop.
+  MessageLoop::current()->AddDestructionObserver(this);
+  return true;
+}
+
+bool ObjectWatcher::StopWatching() {
+  if (!wait_object_)
+    return false;
+
+  // Make sure ObjectWatcher is used in a single-threaded fashion.
+  DCHECK(origin_loop_ == MessageLoop::current());
+
+  // Blocking call to cancel the wait. Any callbacks already in progress will
+  // finish before we return from this call.
+  if (!UnregisterWaitEx(wait_object_, INVALID_HANDLE_VALUE)) {
+    NOTREACHED() << "UnregisterWaitEx failed: " << GetLastError();
+    return false;
+  }
+
+  weak_factory_.InvalidateWeakPtrs();
+  object_ = NULL;
+  wait_object_ = NULL;
+
+  MessageLoop::current()->RemoveDestructionObserver(this);
+  return true;
+}
+
+HANDLE ObjectWatcher::GetWatchedObject() {
+  return object_;
+}
+
+// static
+void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
+  DCHECK(!timed_out);
+
+  // The destructor blocks on any callbacks that are in flight, so we know that
+  // that is always a pointer to a valid ObjectWater.
+  ObjectWatcher* that = static_cast<ObjectWatcher*>(param);
+  that->origin_loop_->PostTask(FROM_HERE, that->callback_);
+  that->callback_.Reset();
+}
+
+void ObjectWatcher::Signal(Delegate* delegate) {
+  // Signaling the delegate may result in our destruction or a nested call to
+  // StartWatching(). As a result, we save any state we need and clear previous
+  // watcher state before signaling the delegate.
+  HANDLE object = object_;
+  StopWatching();
+  delegate->OnObjectSignaled(object);
+}
+
+void ObjectWatcher::WillDestroyCurrentMessageLoop() {
+  // Need to shutdown the watch so that we don't try to access the MessageLoop
+  // after this point.
+  StopWatching();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/object_watcher.h b/base/win/object_watcher.h
new file mode 100644
index 0000000..742f2b0
--- /dev/null
+++ b/base/win/object_watcher.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_OBJECT_WATCHER_H_
+#define BASE_WIN_OBJECT_WATCHER_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop.h"
+
+namespace base {
+namespace win {
+
+// A class that provides a means to asynchronously wait for a Windows object to
+// become signaled.  It is an abstraction around RegisterWaitForSingleObject
+// that provides a notification callback, OnObjectSignaled, that runs back on
+// the origin thread (i.e., the thread that called StartWatching).
+//
+// This class acts like a smart pointer such that when it goes out-of-scope,
+// UnregisterWaitEx is automatically called, and any in-flight notification is
+// suppressed.
+//
+// Typical usage:
+//
+//   class MyClass : public base::ObjectWatcher::Delegate {
+//    public:
+//     void DoStuffWhenSignaled(HANDLE object) {
+//       watcher_.StartWatching(object, this);
+//     }
+//     virtual void OnObjectSignaled(HANDLE object) {
+//       // OK, time to do stuff!
+//     }
+//    private:
+//     base::ObjectWatcher watcher_;
+//   };
+//
+// In the above example, MyClass wants to "do stuff" when object becomes
+// signaled.  ObjectWatcher makes this task easy.  When MyClass goes out of
+// scope, the watcher_ will be destroyed, and there is no need to worry about
+// OnObjectSignaled being called on a deleted MyClass pointer.  Easy!
+// If the object is already signaled before being watched, OnObjectSignaled is
+// still called after (but not necessarily immediately after) watch is started.
+//
+class BASE_EXPORT ObjectWatcher : public MessageLoop::DestructionObserver {
+ public:
+  class BASE_EXPORT Delegate {
+   public:
+    virtual ~Delegate() {}
+    // Called from the MessageLoop when a signaled object is detected.  To
+    // continue watching the object, StartWatching must be called again.
+    virtual void OnObjectSignaled(HANDLE object) = 0;
+  };
+
+  ObjectWatcher();
+  ~ObjectWatcher();
+
+  // When the object is signaled, the given delegate is notified on the thread
+  // where StartWatching is called.  The ObjectWatcher is not responsible for
+  // deleting the delegate.
+  //
+  // Returns true if the watch was started.  Otherwise, false is returned.
+  //
+  bool StartWatching(HANDLE object, Delegate* delegate);
+
+  // Stops watching.  Does nothing if the watch has already completed.  If the
+  // watch is still active, then it is canceled, and the associated delegate is
+  // not notified.
+  //
+  // Returns true if the watch was canceled.  Otherwise, false is returned.
+  //
+  bool StopWatching();
+
+  // Returns the handle of the object being watched, or NULL if the object
+  // watcher is stopped.
+  HANDLE GetWatchedObject();
+
+ private:
+  // Called on a background thread when done waiting.
+  static void CALLBACK DoneWaiting(void* param, BOOLEAN timed_out);
+
+  void Signal(Delegate* delegate);
+
+  // MessageLoop::DestructionObserver implementation:
+  virtual void WillDestroyCurrentMessageLoop();
+
+  // Internal state.
+  WeakPtrFactory<ObjectWatcher> weak_factory_;
+  Closure callback_;
+  HANDLE object_;             // The object being watched
+  HANDLE wait_object_;        // Returned by RegisterWaitForSingleObject
+  MessageLoop* origin_loop_;  // Used to get back to the origin thread
+
+  DISALLOW_COPY_AND_ASSIGN(ObjectWatcher);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_OBJECT_WATCHER_H_
diff --git a/base/win/object_watcher_unittest.cc b/base/win/object_watcher_unittest.cc
new file mode 100644
index 0000000..e8484b9
--- /dev/null
+++ b/base/win/object_watcher_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <process.h>
+
+#include "base/message_loop.h"
+#include "base/win/object_watcher.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+class QuitDelegate : public ObjectWatcher::Delegate {
+ public:
+  virtual void OnObjectSignaled(HANDLE object) {
+    MessageLoop::current()->Quit();
+  }
+};
+
+class DecrementCountDelegate : public ObjectWatcher::Delegate {
+ public:
+  explicit DecrementCountDelegate(int* counter) : counter_(counter) {
+  }
+  virtual void OnObjectSignaled(HANDLE object) {
+    --(*counter_);
+  }
+ private:
+  int* counter_;
+};
+
+void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+  EXPECT_EQ(NULL, watcher.GetWatchedObject());
+
+  // A manual-reset event that is not yet signaled.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  QuitDelegate delegate;
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(event, watcher.GetWatchedObject());
+
+  SetEvent(event);
+
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(NULL, watcher.GetWatchedObject());
+  CloseHandle(event);
+}
+
+void RunTest_BasicCancel(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+
+  // A manual-reset event that is not yet signaled.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  QuitDelegate delegate;
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+
+  watcher.StopWatching();
+
+  CloseHandle(event);
+}
+
+void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+
+  int counter = 1;
+  DecrementCountDelegate delegate(&counter);
+
+  // A manual-reset event that is not yet signaled.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+
+  SetEvent(event);
+
+  // Let the background thread do its business
+  Sleep(30);
+
+  watcher.StopWatching();
+
+  MessageLoop::current()->RunUntilIdle();
+
+  // Our delegate should not have fired.
+  EXPECT_EQ(1, counter);
+
+  CloseHandle(event);
+}
+
+void RunTest_SignalBeforeWatch(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+
+  // A manual-reset event that is signaled before we begin watching.
+  HANDLE event = CreateEvent(NULL, TRUE, TRUE, NULL);
+
+  QuitDelegate delegate;
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(NULL, watcher.GetWatchedObject());
+  CloseHandle(event);
+}
+
+void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) {
+  // Simulate a MessageLoop that dies before an ObjectWatcher.  This ordinarily
+  // doesn't happen when people use the Thread class, but it can happen when
+  // people use the Singleton pattern or atexit.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);  // not signaled
+  {
+    ObjectWatcher watcher;
+    {
+      MessageLoop message_loop(message_loop_type);
+
+      QuitDelegate delegate;
+      watcher.StartWatching(event, &delegate);
+    }
+  }
+  CloseHandle(event);
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+
+TEST(ObjectWatcherTest, BasicSignal) {
+  RunTest_BasicSignal(MessageLoop::TYPE_DEFAULT);
+  RunTest_BasicSignal(MessageLoop::TYPE_IO);
+  RunTest_BasicSignal(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, BasicCancel) {
+  RunTest_BasicCancel(MessageLoop::TYPE_DEFAULT);
+  RunTest_BasicCancel(MessageLoop::TYPE_IO);
+  RunTest_BasicCancel(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, CancelAfterSet) {
+  RunTest_CancelAfterSet(MessageLoop::TYPE_DEFAULT);
+  RunTest_CancelAfterSet(MessageLoop::TYPE_IO);
+  RunTest_CancelAfterSet(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, SignalBeforeWatch) {
+  RunTest_SignalBeforeWatch(MessageLoop::TYPE_DEFAULT);
+  RunTest_SignalBeforeWatch(MessageLoop::TYPE_IO);
+  RunTest_SignalBeforeWatch(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, OutlivesMessageLoop) {
+  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_DEFAULT);
+  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_IO);
+  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_UI);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/pe_image.cc b/base/win/pe_image.cc
new file mode 100644
index 0000000..fcf03c1
--- /dev/null
+++ b/base/win/pe_image.cc
@@ -0,0 +1,570 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file implements PEImage, a generic class to manipulate PE files.
+// This file was adapted from GreenBorder's Code.
+
+#include "base/win/pe_image.h"
+
+namespace base {
+namespace win {
+
+#if defined(_WIN64) && !defined(NACL_WIN64)
+// TODO(rvargas): Bug 27218. Make sure this is ok.
+#error This code is not tested on x64. Please make sure all the base unit tests\
+ pass before doing any real work. The current unit tests don't test the\
+ differences between 32- and 64-bits implementations. Bugs may slip through.\
+ You need to improve the coverage before continuing.
+#endif
+
+// Structure to perform imports enumerations.
+struct EnumAllImportsStorage {
+  PEImage::EnumImportsFunction callback;
+  PVOID cookie;
+};
+
+namespace {
+
+  // Compare two strings byte by byte on an unsigned basis.
+  //   if s1 == s2, return 0
+  //   if s1 < s2, return negative
+  //   if s1 > s2, return positive
+  // Exception if inputs are invalid.
+  int StrCmpByByte(LPCSTR s1, LPCSTR s2) {
+    while (*s1 != '\0' && *s1 == *s2) {
+      ++s1;
+      ++s2;
+    }
+
+    return (*reinterpret_cast<const unsigned char*>(s1) -
+            *reinterpret_cast<const unsigned char*>(s2));
+  }
+
+}  // namespace
+
+// Callback used to enumerate imports. See EnumImportChunksFunction.
+bool ProcessImportChunk(const PEImage &image, LPCSTR module,
+                        PIMAGE_THUNK_DATA name_table,
+                        PIMAGE_THUNK_DATA iat, PVOID cookie) {
+  EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>(
+                                       cookie);
+
+  return image.EnumOneImportChunk(storage.callback, module, name_table, iat,
+                                  storage.cookie);
+}
+
+// Callback used to enumerate delay imports. See EnumDelayImportChunksFunction.
+bool ProcessDelayImportChunk(const PEImage &image,
+                             PImgDelayDescr delay_descriptor,
+                             LPCSTR module, PIMAGE_THUNK_DATA name_table,
+                             PIMAGE_THUNK_DATA iat, PIMAGE_THUNK_DATA bound_iat,
+                             PIMAGE_THUNK_DATA unload_iat, PVOID cookie) {
+  EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>(
+                                       cookie);
+
+  return image.EnumOneDelayImportChunk(storage.callback, delay_descriptor,
+                                       module, name_table, iat, bound_iat,
+                                       unload_iat, storage.cookie);
+}
+
+void PEImage::set_module(HMODULE module) {
+  module_ = module;
+}
+
+PIMAGE_DOS_HEADER PEImage::GetDosHeader() const {
+  return reinterpret_cast<PIMAGE_DOS_HEADER>(module_);
+}
+
+PIMAGE_NT_HEADERS PEImage::GetNTHeaders() const {
+  PIMAGE_DOS_HEADER dos_header = GetDosHeader();
+
+  return reinterpret_cast<PIMAGE_NT_HEADERS>(
+      reinterpret_cast<char*>(dos_header) + dos_header->e_lfanew);
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetSectionHeader(UINT section) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+  PIMAGE_SECTION_HEADER first_section = IMAGE_FIRST_SECTION(nt_headers);
+
+  if (section < nt_headers->FileHeader.NumberOfSections)
+    return first_section + section;
+  else
+    return NULL;
+}
+
+WORD PEImage::GetNumSections() const {
+  return GetNTHeaders()->FileHeader.NumberOfSections;
+}
+
+DWORD PEImage::GetImageDirectoryEntrySize(UINT directory) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+  return nt_headers->OptionalHeader.DataDirectory[directory].Size;
+}
+
+PVOID PEImage::GetImageDirectoryEntryAddr(UINT directory) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+  return RVAToAddr(
+      nt_headers->OptionalHeader.DataDirectory[directory].VirtualAddress);
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetImageSectionFromAddr(PVOID address) const {
+  PBYTE target = reinterpret_cast<PBYTE>(address);
+  PIMAGE_SECTION_HEADER section;
+
+  for (UINT i = 0; NULL != (section = GetSectionHeader(i)); i++) {
+    // Don't use the virtual RVAToAddr.
+    PBYTE start = reinterpret_cast<PBYTE>(
+                      PEImage::RVAToAddr(section->VirtualAddress));
+
+    DWORD size = section->Misc.VirtualSize;
+
+    if ((start <= target) && (start + size > target))
+      return section;
+  }
+
+  return NULL;
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName(
+    LPCSTR section_name) const {
+  if (NULL == section_name)
+    return NULL;
+
+  PIMAGE_SECTION_HEADER ret = NULL;
+  int num_sections = GetNumSections();
+
+  for (int i = 0; i < num_sections; i++) {
+    PIMAGE_SECTION_HEADER section = GetSectionHeader(i);
+    if (0 == _strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name,
+                       sizeof(section->Name))) {
+      ret = section;
+      break;
+    }
+  }
+
+  return ret;
+}
+
+PDWORD PEImage::GetExportEntry(LPCSTR name) const {
+  PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
+
+  if (NULL == exports)
+    return NULL;
+
+  WORD ordinal = 0;
+  if (!GetProcOrdinal(name, &ordinal))
+    return NULL;
+
+  PDWORD functions = reinterpret_cast<PDWORD>(
+                         RVAToAddr(exports->AddressOfFunctions));
+
+  return functions + ordinal - exports->Base;
+}
+
+FARPROC PEImage::GetProcAddress(LPCSTR function_name) const {
+  PDWORD export_entry = GetExportEntry(function_name);
+  if (NULL == export_entry)
+    return NULL;
+
+  PBYTE function = reinterpret_cast<PBYTE>(RVAToAddr(*export_entry));
+
+  PBYTE exports = reinterpret_cast<PBYTE>(
+      GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
+
+  // Check for forwarded exports as a special case.
+  if (exports <= function && exports + size > function)
+#pragma warning(push)
+#pragma warning(disable: 4312)
+    // This cast generates a warning because it is 32 bit specific.
+    return reinterpret_cast<FARPROC>(0xFFFFFFFF);
+#pragma warning(pop)
+
+  return reinterpret_cast<FARPROC>(function);
+}
+
+bool PEImage::GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const {
+  if (NULL == ordinal)
+    return false;
+
+  PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
+
+  if (NULL == exports)
+    return false;
+
+  if (IsOrdinal(function_name)) {
+    *ordinal = ToOrdinal(function_name);
+  } else {
+    PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
+    PDWORD lower = names;
+    PDWORD upper = names + exports->NumberOfNames;
+    int cmp = -1;
+
+    // Binary Search for the name.
+    while (lower != upper) {
+      PDWORD middle = lower + (upper - lower) / 2;
+      LPCSTR name = reinterpret_cast<LPCSTR>(RVAToAddr(*middle));
+
+      // This may be called by sandbox before MSVCRT dll loads, so can't use
+      // CRT function here.
+      cmp = StrCmpByByte(function_name, name);
+
+      if (cmp == 0) {
+        lower = middle;
+        break;
+      }
+
+      if (cmp > 0)
+        lower = middle + 1;
+      else
+        upper = middle;
+    }
+
+    if (cmp != 0)
+      return false;
+
+
+    PWORD ordinals = reinterpret_cast<PWORD>(
+                         RVAToAddr(exports->AddressOfNameOrdinals));
+
+    *ordinal = ordinals[lower - names] + static_cast<WORD>(exports->Base);
+  }
+
+  return true;
+}
+
+bool PEImage::EnumSections(EnumSectionsFunction callback, PVOID cookie) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+  UINT num_sections = nt_headers->FileHeader.NumberOfSections;
+  PIMAGE_SECTION_HEADER section = GetSectionHeader(0);
+
+  for (UINT i = 0; i < num_sections; i++, section++) {
+    PVOID section_start = RVAToAddr(section->VirtualAddress);
+    DWORD size = section->Misc.VirtualSize;
+
+    if (!callback(*this, section, section_start, size, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumExports(EnumExportsFunction callback, PVOID cookie) const {
+  PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT);
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
+
+  // Check if there are any exports at all.
+  if (NULL == directory || 0 == size)
+    return true;
+
+  PIMAGE_EXPORT_DIRECTORY exports = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
+                                        directory);
+  UINT ordinal_base = exports->Base;
+  UINT num_funcs = exports->NumberOfFunctions;
+  UINT num_names = exports->NumberOfNames;
+  PDWORD functions  = reinterpret_cast<PDWORD>(RVAToAddr(
+                          exports->AddressOfFunctions));
+  PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
+  PWORD ordinals = reinterpret_cast<PWORD>(RVAToAddr(
+                       exports->AddressOfNameOrdinals));
+
+  for (UINT count = 0; count < num_funcs; count++) {
+    PVOID func = RVAToAddr(functions[count]);
+    if (NULL == func)
+      continue;
+
+    // Check for a name.
+    LPCSTR name = NULL;
+    UINT hint;
+    for (hint = 0; hint < num_names; hint++) {
+      if (ordinals[hint] == count) {
+        name = reinterpret_cast<LPCSTR>(RVAToAddr(names[hint]));
+        break;
+      }
+    }
+
+    if (name == NULL)
+      hint = 0;
+
+    // Check for forwarded exports.
+    LPCSTR forward = NULL;
+    if (reinterpret_cast<char*>(func) >= reinterpret_cast<char*>(directory) &&
+        reinterpret_cast<char*>(func) <= reinterpret_cast<char*>(directory) +
+            size) {
+      forward = reinterpret_cast<LPCSTR>(func);
+      func = 0;
+    }
+
+    if (!callback(*this, ordinal_base + count, hint, name, func, forward,
+                  cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const {
+  PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_BASERELOC);
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_BASERELOC);
+  PIMAGE_BASE_RELOCATION base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
+      directory);
+
+  if (directory == NULL || size < sizeof(IMAGE_BASE_RELOCATION))
+    return true;
+
+  while (base->SizeOfBlock) {
+    PWORD reloc = reinterpret_cast<PWORD>(base + 1);
+    UINT num_relocs = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
+        sizeof(WORD);
+
+    for (UINT i = 0; i < num_relocs; i++, reloc++) {
+      WORD type = *reloc >> 12;
+      PVOID address = RVAToAddr(base->VirtualAddress + (*reloc & 0x0FFF));
+
+      if (!callback(*this, type, address, cookie))
+        return false;
+    }
+
+    base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
+               reinterpret_cast<char*>(base) + base->SizeOfBlock);
+  }
+
+  return true;
+}
+
+bool PEImage::EnumImportChunks(EnumImportChunksFunction callback,
+                               PVOID cookie) const {
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT);
+  PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk();
+
+  if (import == NULL || size < sizeof(IMAGE_IMPORT_DESCRIPTOR))
+    return true;
+
+  for (; import->FirstThunk; import++) {
+    LPCSTR module_name = reinterpret_cast<LPCSTR>(RVAToAddr(import->Name));
+    PIMAGE_THUNK_DATA name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                                       RVAToAddr(import->OriginalFirstThunk));
+    PIMAGE_THUNK_DATA iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                                RVAToAddr(import->FirstThunk));
+
+    if (!callback(*this, module_name, name_table, iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumOneImportChunk(EnumImportsFunction callback,
+                                 LPCSTR module_name,
+                                 PIMAGE_THUNK_DATA name_table,
+                                 PIMAGE_THUNK_DATA iat, PVOID cookie) const {
+  if (NULL == name_table)
+    return false;
+
+  for (; name_table && name_table->u1.Ordinal; name_table++, iat++) {
+    LPCSTR name = NULL;
+    WORD ordinal = 0;
+    WORD hint = 0;
+
+    if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
+      ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
+    } else {
+      PIMAGE_IMPORT_BY_NAME import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+          RVAToAddr(name_table->u1.ForwarderString));
+
+      hint = import->Hint;
+      name = reinterpret_cast<LPCSTR>(&import->Name);
+    }
+
+    if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumAllImports(EnumImportsFunction callback, PVOID cookie) const {
+  EnumAllImportsStorage temp = { callback, cookie };
+  return EnumImportChunks(ProcessImportChunk, &temp);
+}
+
+bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
+                                    PVOID cookie) const {
+  PVOID directory = GetImageDirectoryEntryAddr(
+                        IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
+  PImgDelayDescr delay_descriptor = reinterpret_cast<PImgDelayDescr>(directory);
+
+  if (directory == NULL || size == 0)
+    return true;
+
+  for (; delay_descriptor->rvaHmod; delay_descriptor++) {
+    PIMAGE_THUNK_DATA name_table;
+    PIMAGE_THUNK_DATA iat;
+    PIMAGE_THUNK_DATA bound_iat;    // address of the optional bound IAT
+    PIMAGE_THUNK_DATA unload_iat;   // address of optional copy of original IAT
+    LPCSTR module_name;
+
+    // check if VC7-style imports, using RVAs instead of
+    // VC6-style addresses.
+    bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
+
+    if (rvas) {
+      module_name = reinterpret_cast<LPCSTR>(
+                        RVAToAddr(delay_descriptor->rvaDLLName));
+      name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       RVAToAddr(delay_descriptor->rvaINT));
+      iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                RVAToAddr(delay_descriptor->rvaIAT));
+      bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                      RVAToAddr(delay_descriptor->rvaBoundIAT));
+      unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       RVAToAddr(delay_descriptor->rvaUnloadIAT));
+    } else {
+#pragma warning(push)
+#pragma warning(disable: 4312)
+      // These casts generate warnings because they are 32 bit specific.
+      module_name = reinterpret_cast<LPCSTR>(delay_descriptor->rvaDLLName);
+      name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       delay_descriptor->rvaINT);
+      iat = reinterpret_cast<PIMAGE_THUNK_DATA>(delay_descriptor->rvaIAT);
+      bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                      delay_descriptor->rvaBoundIAT);
+      unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       delay_descriptor->rvaUnloadIAT);
+#pragma warning(pop)
+    }
+
+    if (!callback(*this, delay_descriptor, module_name, name_table, iat,
+                  bound_iat, unload_iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback,
+                                      PImgDelayDescr delay_descriptor,
+                                      LPCSTR module_name,
+                                      PIMAGE_THUNK_DATA name_table,
+                                      PIMAGE_THUNK_DATA iat,
+                                      PIMAGE_THUNK_DATA bound_iat,
+                                      PIMAGE_THUNK_DATA unload_iat,
+                                      PVOID cookie) const {
+  UNREFERENCED_PARAMETER(bound_iat);
+  UNREFERENCED_PARAMETER(unload_iat);
+
+  for (; name_table->u1.Ordinal; name_table++, iat++) {
+    LPCSTR name = NULL;
+    WORD ordinal = 0;
+    WORD hint = 0;
+
+    if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
+      ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
+    } else {
+      PIMAGE_IMPORT_BY_NAME import;
+      bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
+
+      if (rvas) {
+        import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+                     RVAToAddr(name_table->u1.ForwarderString));
+      } else {
+#pragma warning(push)
+#pragma warning(disable: 4312)
+        // This cast generates a warning because it is 32 bit specific.
+        import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+                     name_table->u1.ForwarderString);
+#pragma warning(pop)
+      }
+
+      hint = import->Hint;
+      name = reinterpret_cast<LPCSTR>(&import->Name);
+    }
+
+    if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumAllDelayImports(EnumImportsFunction callback,
+                                  PVOID cookie) const {
+  EnumAllImportsStorage temp = { callback, cookie };
+  return EnumDelayImportChunks(ProcessDelayImportChunk, &temp);
+}
+
+bool PEImage::VerifyMagic() const {
+  PIMAGE_DOS_HEADER dos_header = GetDosHeader();
+
+  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
+    return false;
+
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+  if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
+    return false;
+
+  if (nt_headers->FileHeader.SizeOfOptionalHeader !=
+      sizeof(IMAGE_OPTIONAL_HEADER))
+    return false;
+
+  if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
+    return false;
+
+  return true;
+}
+
+bool PEImage::ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const {
+  LPVOID address = RVAToAddr(rva);
+  return ImageAddrToOnDiskOffset(address, on_disk_offset);
+}
+
+bool PEImage::ImageAddrToOnDiskOffset(LPVOID address,
+                                      DWORD *on_disk_offset) const {
+  if (NULL == address)
+    return false;
+
+  // Get the section that this address belongs to.
+  PIMAGE_SECTION_HEADER section_header = GetImageSectionFromAddr(address);
+  if (NULL == section_header)
+    return false;
+
+#pragma warning(push)
+#pragma warning(disable: 4311)
+  // These casts generate warnings because they are 32 bit specific.
+  // Don't follow the virtual RVAToAddr, use the one on the base.
+  DWORD offset_within_section = reinterpret_cast<DWORD>(address) -
+                                    reinterpret_cast<DWORD>(PEImage::RVAToAddr(
+                                        section_header->VirtualAddress));
+#pragma warning(pop)
+
+  *on_disk_offset = section_header->PointerToRawData + offset_within_section;
+  return true;
+}
+
+PVOID PEImage::RVAToAddr(DWORD rva) const {
+  if (rva == 0)
+    return NULL;
+
+  return reinterpret_cast<char*>(module_) + rva;
+}
+
+PVOID PEImageAsData::RVAToAddr(DWORD rva) const {
+  if (rva == 0)
+    return NULL;
+
+  PVOID in_memory = PEImage::RVAToAddr(rva);
+  DWORD disk_offset;
+
+  if (!ImageAddrToOnDiskOffset(in_memory, &disk_offset))
+    return NULL;
+
+  return PEImage::RVAToAddr(disk_offset);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/pe_image.h b/base/win/pe_image.h
new file mode 100644
index 0000000..878ef52
--- /dev/null
+++ b/base/win/pe_image.h
@@ -0,0 +1,268 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was adapted from GreenBorder's Code.
+// To understand what this class is about (for other than well known functions
+// as GetProcAddress), a good starting point is "An In-Depth Look into the
+// Win32 Portable Executable File Format" by Matt Pietrek:
+// http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx
+
+#ifndef BASE_WIN_PE_IMAGE_H_
+#define BASE_WIN_PE_IMAGE_H_
+
+#include <windows.h>
+
+#if defined(_WIN32_WINNT_WIN8)
+// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
+#undef FACILITY_VISUALCPP
+#endif
+#include <DelayIMP.h>
+
+namespace base {
+namespace win {
+
+// This class is a wrapper for the Portable Executable File Format (PE).
+// It's main purpose is to provide an easy way to work with imports and exports
+// from a file, mapped in memory as image.
+class PEImage {
+ public:
+  // Callback to enumerate sections.
+  // cookie is the value passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumSectionsFunction)(const PEImage &image,
+                                       PIMAGE_SECTION_HEADER header,
+                                       PVOID section_start, DWORD section_size,
+                                       PVOID cookie);
+
+  // Callback to enumerate exports.
+  // function is the actual address of the symbol. If forward is not null, it
+  // contains the dll and symbol to forward this export to. cookie is the value
+  // passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumExportsFunction)(const PEImage &image, DWORD ordinal,
+                                      DWORD hint, LPCSTR name, PVOID function,
+                                      LPCSTR forward, PVOID cookie);
+
+  // Callback to enumerate import blocks.
+  // name_table and iat point to the imports name table and address table for
+  // this block. cookie is the value passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumImportChunksFunction)(const PEImage &image, LPCSTR module,
+                                           PIMAGE_THUNK_DATA name_table,
+                                           PIMAGE_THUNK_DATA iat, PVOID cookie);
+
+  // Callback to enumerate imports.
+  // module is the dll that exports this symbol. cookie is the value passed to
+  // the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumImportsFunction)(const PEImage &image, LPCSTR module,
+                                      DWORD ordinal, LPCSTR name, DWORD hint,
+                                      PIMAGE_THUNK_DATA iat, PVOID cookie);
+
+  // Callback to enumerate dalayed import blocks.
+  // module is the dll that exports this block of symbols. cookie is the value
+  // passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumDelayImportChunksFunction)(const PEImage &image,
+                                                PImgDelayDescr delay_descriptor,
+                                                LPCSTR module,
+                                                PIMAGE_THUNK_DATA name_table,
+                                                PIMAGE_THUNK_DATA iat,
+                                                PIMAGE_THUNK_DATA bound_iat,
+                                                PIMAGE_THUNK_DATA unload_iat,
+                                                PVOID cookie);
+
+  // Callback to enumerate relocations.
+  // cookie is the value passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumRelocsFunction)(const PEImage &image, WORD type,
+                                     PVOID address, PVOID cookie);
+
+  explicit PEImage(HMODULE module) : module_(module) {}
+  explicit PEImage(const void* module) {
+    module_ = reinterpret_cast<HMODULE>(const_cast<void*>(module));
+  }
+
+  // Gets the HMODULE for this object.
+  HMODULE module() const;
+
+  // Sets this object's HMODULE.
+  void set_module(HMODULE module);
+
+  // Checks if this symbol is actually an ordinal.
+  static bool IsOrdinal(LPCSTR name);
+
+  // Converts a named symbol to the corresponding ordinal.
+  static WORD ToOrdinal(LPCSTR name);
+
+  // Returns the DOS_HEADER for this PE.
+  PIMAGE_DOS_HEADER GetDosHeader() const;
+
+  // Returns the NT_HEADER for this PE.
+  PIMAGE_NT_HEADERS GetNTHeaders() const;
+
+  // Returns number of sections of this PE.
+  WORD GetNumSections() const;
+
+  // Returns the header for a given section.
+  // returns NULL if there is no such section.
+  PIMAGE_SECTION_HEADER GetSectionHeader(UINT section) const;
+
+  // Returns the size of a given directory entry.
+  DWORD GetImageDirectoryEntrySize(UINT directory) const;
+
+  // Returns the address of a given directory entry.
+  PVOID GetImageDirectoryEntryAddr(UINT directory) const;
+
+  // Returns the section header for a given address.
+  // Use: s = image.GetImageSectionFromAddr(a);
+  // Post: 's' is the section header of the section that contains 'a'
+  //       or NULL if there is no such section.
+  PIMAGE_SECTION_HEADER GetImageSectionFromAddr(PVOID address) const;
+
+  // Returns the section header for a given section.
+  PIMAGE_SECTION_HEADER GetImageSectionHeaderByName(LPCSTR section_name) const;
+
+  // Returns the first block of imports.
+  PIMAGE_IMPORT_DESCRIPTOR GetFirstImportChunk() const;
+
+  // Returns the exports directory.
+  PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const;
+
+  // Returns a given export entry.
+  // Use: e = image.GetExportEntry(f);
+  // Pre: 'f' is either a zero terminated string or ordinal
+  // Post: 'e' is a pointer to the export directory entry
+  //       that contains 'f's export RVA, or NULL if 'f'
+  //       is not exported from this image
+  PDWORD GetExportEntry(LPCSTR name) const;
+
+  // Returns the address for a given exported symbol.
+  // Use: p = image.GetProcAddress(f);
+  // Pre: 'f' is either a zero terminated string or ordinal.
+  // Post: if 'f' is a non-forwarded export from image, 'p' is
+  //       the exported function. If 'f' is a forwarded export
+  //       then p is the special value 0xFFFFFFFF. In this case
+  //       RVAToAddr(*GetExportEntry) can be used to resolve
+  //       the string that describes the forward.
+  FARPROC GetProcAddress(LPCSTR function_name) const;
+
+  // Retrieves the ordinal for a given exported symbol.
+  // Returns true if the symbol was found.
+  bool GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const;
+
+  // Enumerates PE sections.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumSections(EnumSectionsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE exports.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumExports(EnumExportsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE imports.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumAllImports(EnumImportsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE import blocks.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumImportChunks(EnumImportChunksFunction callback, PVOID cookie) const;
+
+  // Enumerates the imports from a single PE import block.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumOneImportChunk(EnumImportsFunction callback, LPCSTR module_name,
+                          PIMAGE_THUNK_DATA name_table, PIMAGE_THUNK_DATA iat,
+                          PVOID cookie) const;
+
+
+  // Enumerates PE delay imports.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumAllDelayImports(EnumImportsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE delay import blocks.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
+                             PVOID cookie) const;
+
+  // Enumerates imports from a single PE delay import block.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumOneDelayImportChunk(EnumImportsFunction callback,
+                               PImgDelayDescr delay_descriptor,
+                               LPCSTR module_name,
+                               PIMAGE_THUNK_DATA name_table,
+                               PIMAGE_THUNK_DATA iat,
+                               PIMAGE_THUNK_DATA bound_iat,
+                               PIMAGE_THUNK_DATA unload_iat,
+                               PVOID cookie) const;
+
+  // Enumerates PE relocation entries.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const;
+
+  // Verifies the magic values on the PE file.
+  // Returns true if all values are correct.
+  bool VerifyMagic() const;
+
+  // Converts an rva value to the appropriate address.
+  virtual PVOID RVAToAddr(DWORD rva) const;
+
+  // Converts an rva value to an offset on disk.
+  // Returns true on success.
+  bool ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const;
+
+  // Converts an address to an offset on disk.
+  // Returns true on success.
+  bool ImageAddrToOnDiskOffset(LPVOID address, DWORD *on_disk_offset) const;
+
+ private:
+  HMODULE module_;
+};
+
+// This class is an extension to the PEImage class that allows working with PE
+// files mapped as data instead of as image file.
+class PEImageAsData : public PEImage {
+ public:
+  explicit PEImageAsData(HMODULE hModule) : PEImage(hModule) {}
+
+  virtual PVOID RVAToAddr(DWORD rva) const;
+};
+
+inline bool PEImage::IsOrdinal(LPCSTR name) {
+#pragma warning(push)
+#pragma warning(disable: 4311)
+  // This cast generates a warning because it is 32 bit specific.
+  return reinterpret_cast<DWORD>(name) <= 0xFFFF;
+#pragma warning(pop)
+}
+
+inline WORD PEImage::ToOrdinal(LPCSTR name) {
+  return reinterpret_cast<WORD>(name);
+}
+
+inline HMODULE PEImage::module() const {
+  return module_;
+}
+
+inline PIMAGE_IMPORT_DESCRIPTOR PEImage::GetFirstImportChunk() const {
+  return reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(
+             GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_IMPORT));
+}
+
+inline PIMAGE_EXPORT_DIRECTORY PEImage::GetExportDirectory() const {
+  return reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
+             GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
+}
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_PE_IMAGE_H_
diff --git a/base/win/pe_image_unittest.cc b/base/win/pe_image_unittest.cc
new file mode 100644
index 0000000..e308eae
--- /dev/null
+++ b/base/win/pe_image_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.
+
+// This file contains unit tests for PEImage.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "base/win/pe_image.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+// Just counts the number of invocations.
+bool ExportsCallback(const PEImage &image,
+                     DWORD ordinal,
+                     DWORD hint,
+                     LPCSTR name,
+                     PVOID function,
+                     LPCSTR forward,
+                     PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool ImportsCallback(const PEImage &image,
+                     LPCSTR module,
+                     DWORD ordinal,
+                     LPCSTR name,
+                     DWORD hint,
+                     PIMAGE_THUNK_DATA iat,
+                     PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool SectionsCallback(const PEImage &image,
+                       PIMAGE_SECTION_HEADER header,
+                       PVOID section_start,
+                       DWORD section_size,
+                       PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool RelocsCallback(const PEImage &image,
+                    WORD type,
+                    PVOID address,
+                    PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool ImportChunksCallback(const PEImage &image,
+                          LPCSTR module,
+                          PIMAGE_THUNK_DATA name_table,
+                          PIMAGE_THUNK_DATA iat,
+                          PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool DelayImportChunksCallback(const PEImage &image,
+                               PImgDelayDescr delay_descriptor,
+                               LPCSTR module,
+                               PIMAGE_THUNK_DATA name_table,
+                               PIMAGE_THUNK_DATA iat,
+                               PIMAGE_THUNK_DATA bound_iat,
+                               PIMAGE_THUNK_DATA unload_iat,
+                               PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Identifiers for the set of supported expectations.
+enum ExpectationSet {
+  WIN_2K_SET,
+  WIN_XP_SET,
+  WIN_VISTA_SET,
+  WIN_7_SET,
+  WIN_8_SET,
+  UNSUPPORTED_SET,
+};
+
+// We'll be using some known values for the tests.
+enum Value {
+  sections = 0,
+  imports_dlls,
+  delay_dlls,
+  exports,
+  imports,
+  delay_imports,
+  relocs
+};
+
+ExpectationSet GetExpectationSet(DWORD os) {
+  if (os == 50)
+    return WIN_2K_SET;
+  if (os == 51)
+    return WIN_XP_SET;
+  if (os == 60)
+    return WIN_VISTA_SET;
+  if (os == 61)
+    return WIN_7_SET;
+  if (os >= 62)
+    return WIN_8_SET;
+  return UNSUPPORTED_SET;
+}
+
+// Retrieves the expected value from advapi32.dll based on the OS.
+int GetExpectedValue(Value value, DWORD os) {
+  const int xp_delay_dlls = 2;
+  const int xp_exports = 675;
+  const int xp_imports = 422;
+  const int xp_delay_imports = 8;
+  const int xp_relocs = 9180;
+  const int vista_delay_dlls = 4;
+  const int vista_exports = 799;
+  const int vista_imports = 476;
+  const int vista_delay_imports = 24;
+  const int vista_relocs = 10188;
+  const int w2k_delay_dlls = 0;
+  const int w2k_exports = 566;
+  const int w2k_imports = 357;
+  const int w2k_delay_imports = 0;
+  const int w2k_relocs = 7388;
+  const int win7_delay_dlls = 7;
+  const int win7_exports = 806;
+  const int win7_imports = 568;
+  const int win7_delay_imports = 71;
+  const int win7_relocs = 7812;
+  const int win8_delay_dlls = 9;
+  const int win8_exports = 806;
+  const int win8_imports = 568;
+  const int win8_delay_imports = 113;
+  const int win8_relocs = 9478;
+  int win8_sections = 4;
+  int win8_import_dlls = 17;
+
+  base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
+  if (os_info->architecture() == base::win::OSInfo::X86_ARCHITECTURE) {
+    win8_sections = 5;
+    win8_import_dlls = 19;
+  }
+
+  // Contains the expected value, for each enumerated property (Value), and the
+  // OS version: [Value][os_version]
+  const int expected[][5] = {
+    {4, 4, 4, 4, win8_sections},
+    {3, 3, 3, 13, win8_import_dlls},
+    {w2k_delay_dlls, xp_delay_dlls, vista_delay_dlls, win7_delay_dlls,
+     win8_delay_dlls},
+    {w2k_exports, xp_exports, vista_exports, win7_exports, win8_exports},
+    {w2k_imports, xp_imports, vista_imports, win7_imports, win8_imports},
+    {w2k_delay_imports, xp_delay_imports,
+     vista_delay_imports, win7_delay_imports, win8_delay_imports},
+    {w2k_relocs, xp_relocs, vista_relocs, win7_relocs, win8_relocs}
+  };
+  COMPILE_ASSERT(arraysize(expected[0]) == UNSUPPORTED_SET,
+                 expected_value_set_mismatch);
+
+  if (value > relocs)
+    return 0;
+  ExpectationSet expected_set = GetExpectationSet(os);
+  if (expected_set >= arraysize(expected)) {
+    // This should never happen.  Log a failure if it does.
+    EXPECT_NE(UNSUPPORTED_SET, expected_set);
+    expected_set = WIN_2K_SET;
+  }
+
+  return expected[value][expected_set];
+}
+
+// Tests that we are able to enumerate stuff from a PE file, and that
+// the actual number of items found is within the expected range.
+TEST(PEImageTest, EnumeratesPE) {
+  HMODULE module = LoadLibrary(L"advapi32.dll");
+  ASSERT_TRUE(NULL != module);
+
+  PEImage pe(module);
+  int count = 0;
+  EXPECT_TRUE(pe.VerifyMagic());
+
+  DWORD os = pe.GetNTHeaders()->OptionalHeader.MajorOperatingSystemVersion;
+  os = os * 10 + pe.GetNTHeaders()->OptionalHeader.MinorOperatingSystemVersion;
+
+  // Skip this test for unsupported OS versions.
+  if (GetExpectationSet(os) == UNSUPPORTED_SET)
+    return;
+
+  pe.EnumSections(SectionsCallback, &count);
+  EXPECT_EQ(GetExpectedValue(sections, os), count);
+
+  count = 0;
+  pe.EnumImportChunks(ImportChunksCallback, &count);
+  EXPECT_EQ(GetExpectedValue(imports_dlls, os), count);
+
+  count = 0;
+  pe.EnumDelayImportChunks(DelayImportChunksCallback, &count);
+  EXPECT_EQ(GetExpectedValue(delay_dlls, os), count);
+
+  count = 0;
+  pe.EnumExports(ExportsCallback, &count);
+  EXPECT_GT(count, GetExpectedValue(exports, os) - 20);
+  EXPECT_LT(count, GetExpectedValue(exports, os) + 100);
+
+  count = 0;
+  pe.EnumAllImports(ImportsCallback, &count);
+  EXPECT_GT(count, GetExpectedValue(imports, os) - 20);
+  EXPECT_LT(count, GetExpectedValue(imports, os) + 100);
+
+  count = 0;
+  pe.EnumAllDelayImports(ImportsCallback, &count);
+  EXPECT_GT(count, GetExpectedValue(delay_imports, os) - 2);
+  EXPECT_LT(count, GetExpectedValue(delay_imports, os) + 8);
+
+  count = 0;
+  pe.EnumRelocs(RelocsCallback, &count);
+  EXPECT_GT(count, GetExpectedValue(relocs, os) - 150);
+  EXPECT_LT(count, GetExpectedValue(relocs, os) + 1500);
+
+  FreeLibrary(module);
+}
+
+// Tests that we can locate an specific exported symbol, by name and by ordinal.
+TEST(PEImageTest, RetrievesExports) {
+  HMODULE module = LoadLibrary(L"advapi32.dll");
+  ASSERT_TRUE(NULL != module);
+
+  PEImage pe(module);
+  WORD ordinal;
+
+  EXPECT_TRUE(pe.GetProcOrdinal("RegEnumKeyExW", &ordinal));
+
+  FARPROC address1 = pe.GetProcAddress("RegEnumKeyExW");
+  FARPROC address2 = pe.GetProcAddress(reinterpret_cast<char*>(ordinal));
+  EXPECT_TRUE(address1 != NULL);
+  EXPECT_TRUE(address2 != NULL);
+  EXPECT_TRUE(address1 == address2);
+
+  FreeLibrary(module);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/registry.cc b/base/win/registry.cc
new file mode 100644
index 0000000..83eb590
--- /dev/null
+++ b/base/win/registry.cc
@@ -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.
+
+#include "base/win/registry.h"
+
+#include <shlwapi.h>
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/threading/thread_restrictions.h"
+
+#pragma comment(lib, "shlwapi.lib")  // for SHDeleteKey
+
+namespace base {
+namespace win {
+
+namespace {
+
+// RegEnumValue() reports the number of characters from the name that were
+// written to the buffer, not how many there are. This constant is the maximum
+// name size, such that a buffer with this size should read any name.
+const DWORD MAX_REGISTRY_NAME_SIZE = 16384;
+
+// Registry values are read as BYTE* but can have wchar_t* data whose last
+// wchar_t is truncated. This function converts the reported |byte_size| to
+// a size in wchar_t that can store a truncated wchar_t if necessary.
+inline DWORD to_wchar_size(DWORD byte_size) {
+  return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
+}
+
+}  // namespace
+
+// RegKey ----------------------------------------------------------------------
+
+RegKey::RegKey()
+    : key_(NULL),
+      watch_event_(0) {
+}
+
+RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
+    : key_(NULL),
+      watch_event_(0) {
+  if (rootkey) {
+    if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
+      Create(rootkey, subkey, access);
+    else
+      Open(rootkey, subkey, access);
+  } else {
+    DCHECK(!subkey);
+  }
+}
+
+RegKey::~RegKey() {
+  Close();
+}
+
+LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+  DWORD disposition_value;
+  return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
+}
+
+LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
+                                   DWORD* disposition, REGSAM access) {
+  DCHECK(rootkey && subkey && access && disposition);
+  Close();
+
+  LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
+                               REG_OPTION_NON_VOLATILE, access, NULL, &key_,
+                               disposition);
+  return result;
+}
+
+LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
+  DCHECK(name && access);
+  HKEY subkey = NULL;
+  LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
+                               access, NULL, &subkey, NULL);
+  Close();
+
+  key_ = subkey;
+  return result;
+}
+
+LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+  DCHECK(rootkey && subkey && access);
+  Close();
+
+  LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
+  return result;
+}
+
+LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
+  DCHECK(relative_key_name && access);
+  HKEY subkey = NULL;
+  LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
+
+  // We have to close the current opened key before replacing it with the new
+  // one.
+  Close();
+
+  key_ = subkey;
+  return result;
+}
+
+void RegKey::Close() {
+  StopWatching();
+  if (key_) {
+    ::RegCloseKey(key_);
+    key_ = NULL;
+  }
+}
+
+bool RegKey::HasValue(const wchar_t* name) const {
+  return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS;
+}
+
+DWORD RegKey::GetValueCount() const {
+  DWORD count = 0;
+  LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
+                                NULL, NULL, NULL, NULL);
+  return (result == ERROR_SUCCESS) ? count : 0;
+}
+
+LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
+  wchar_t buf[256];
+  DWORD bufsize = arraysize(buf);
+  LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
+  if (r == ERROR_SUCCESS)
+    *name = buf;
+
+  return r;
+}
+
+LONG RegKey::DeleteKey(const wchar_t* name) {
+  DCHECK(key_);
+  DCHECK(name);
+  LONG result = SHDeleteKey(key_, name);
+  return result;
+}
+
+LONG RegKey::DeleteValue(const wchar_t* value_name) {
+  DCHECK(key_);
+  LONG result = RegDeleteValue(key_, value_name);
+  return result;
+}
+
+LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
+  DCHECK(out_value);
+  DWORD type = REG_DWORD;
+  DWORD size = sizeof(DWORD);
+  DWORD local_value = 0;
+  LONG result = ReadValue(name, &local_value, &size, &type);
+  if (result == ERROR_SUCCESS) {
+    if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD))
+      *out_value = local_value;
+    else
+      result = ERROR_CANTREAD;
+  }
+
+  return result;
+}
+
+LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
+  DCHECK(out_value);
+  DWORD type = REG_QWORD;
+  int64 local_value = 0;
+  DWORD size = sizeof(local_value);
+  LONG result = ReadValue(name, &local_value, &size, &type);
+  if (result == ERROR_SUCCESS) {
+    if ((type == REG_QWORD || type == REG_BINARY) &&
+        size == sizeof(local_value))
+      *out_value = local_value;
+    else
+      result = ERROR_CANTREAD;
+  }
+
+  return result;
+}
+
+LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
+  DCHECK(out_value);
+  const size_t kMaxStringLength = 1024;  // This is after expansion.
+  // Use the one of the other forms of ReadValue if 1024 is too small for you.
+  wchar_t raw_value[kMaxStringLength];
+  DWORD type = REG_SZ, size = sizeof(raw_value);
+  LONG result = ReadValue(name, raw_value, &size, &type);
+  if (result == ERROR_SUCCESS) {
+    if (type == REG_SZ) {
+      *out_value = raw_value;
+    } else if (type == REG_EXPAND_SZ) {
+      wchar_t expanded[kMaxStringLength];
+      size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
+      // Success: returns the number of wchar_t's copied
+      // Fail: buffer too small, returns the size required
+      // Fail: other, returns 0
+      if (size == 0 || size > kMaxStringLength) {
+        result = ERROR_MORE_DATA;
+      } else {
+        *out_value = expanded;
+      }
+    } else {
+      // Not a string. Oops.
+      result = ERROR_CANTREAD;
+    }
+  }
+
+  return result;
+}
+
+LONG RegKey::ReadValue(const wchar_t* name,
+                       void* data,
+                       DWORD* dsize,
+                       DWORD* dtype) const {
+  LONG result = RegQueryValueEx(key_, name, 0, dtype,
+                                reinterpret_cast<LPBYTE>(data), dsize);
+  return result;
+}
+
+LONG RegKey::ReadValues(const wchar_t* name,
+                        std::vector<std::wstring>* values) {
+  values->clear();
+
+  DWORD type = REG_MULTI_SZ;
+  DWORD size = 0;
+  LONG result = ReadValue(name, NULL, &size, &type);
+  if (FAILED(result) || size == 0)
+    return result;
+
+  if (type != REG_MULTI_SZ)
+    return ERROR_CANTREAD;
+
+  std::vector<wchar_t> buffer(size / sizeof(wchar_t));
+  result = ReadValue(name, &buffer[0], &size, NULL);
+  if (FAILED(result) || size == 0)
+    return result;
+
+  // Parse the double-null-terminated list of strings.
+  // Note: This code is paranoid to not read outside of |buf|, in the case where
+  // it may not be properly terminated.
+  const wchar_t* entry = &buffer[0];
+  const wchar_t* buffer_end = entry + (size / sizeof(wchar_t));
+  while (entry < buffer_end && entry[0] != '\0') {
+    const wchar_t* entry_end = std::find(entry, buffer_end, L'\0');
+    values->push_back(std::wstring(entry, entry_end));
+    entry = entry_end + 1;
+  }
+  return 0;
+}
+
+LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
+  return WriteValue(
+      name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD);
+}
+
+LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) {
+  return WriteValue(name, in_value,
+      static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ);
+}
+
+LONG RegKey::WriteValue(const wchar_t* name,
+                        const void* data,
+                        DWORD dsize,
+                        DWORD dtype) {
+  DCHECK(data || !dsize);
+
+  LONG result = RegSetValueEx(key_, name, 0, dtype,
+      reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
+  return result;
+}
+
+LONG RegKey::StartWatching() {
+  DCHECK(key_);
+  if (!watch_event_)
+    watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  DWORD filter = REG_NOTIFY_CHANGE_NAME |
+                 REG_NOTIFY_CHANGE_ATTRIBUTES |
+                 REG_NOTIFY_CHANGE_LAST_SET |
+                 REG_NOTIFY_CHANGE_SECURITY;
+
+  // Watch the registry key for a change of value.
+  LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE);
+  if (result != ERROR_SUCCESS) {
+    CloseHandle(watch_event_);
+    watch_event_ = 0;
+  }
+
+  return result;
+}
+
+bool RegKey::HasChanged() {
+  if (watch_event_) {
+    if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
+      StartWatching();
+      return true;
+    }
+  }
+  return false;
+}
+
+LONG RegKey::StopWatching() {
+  LONG result = ERROR_INVALID_HANDLE;
+  if (watch_event_) {
+    CloseHandle(watch_event_);
+    watch_event_ = 0;
+    result = ERROR_SUCCESS;
+  }
+  return result;
+}
+
+// RegistryValueIterator ------------------------------------------------------
+
+RegistryValueIterator::RegistryValueIterator(HKEY root_key,
+                                             const wchar_t* folder_key)
+    : name_(MAX_PATH, L'\0'),
+      value_(MAX_PATH, L'\0') {
+  LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
+  if (result != ERROR_SUCCESS) {
+    key_ = NULL;
+  } else {
+    DWORD count = 0;
+    result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
+                               NULL, NULL, NULL, NULL);
+
+    if (result != ERROR_SUCCESS) {
+      ::RegCloseKey(key_);
+      key_ = NULL;
+    } else {
+      index_ = count - 1;
+    }
+  }
+
+  Read();
+}
+
+RegistryValueIterator::~RegistryValueIterator() {
+  if (key_)
+    ::RegCloseKey(key_);
+}
+
+DWORD RegistryValueIterator::ValueCount() const {
+  DWORD count = 0;
+  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
+                                  &count, NULL, NULL, NULL, NULL);
+  if (result != ERROR_SUCCESS)
+    return 0;
+
+  return count;
+}
+
+bool RegistryValueIterator::Valid() const {
+  return key_ != NULL && index_ >= 0;
+}
+
+void RegistryValueIterator::operator++() {
+  --index_;
+  Read();
+}
+
+bool RegistryValueIterator::Read() {
+  if (Valid()) {
+    DWORD capacity = static_cast<DWORD>(name_.capacity());
+    DWORD name_size = capacity;
+    // |value_size_| is in bytes. Reserve the last character for a NUL.
+    value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
+    LONG result = ::RegEnumValue(
+        key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
+        reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
+
+    if (result == ERROR_MORE_DATA) {
+      // Registry key names are limited to 255 characters and fit within
+      // MAX_PATH (which is 260) but registry value names can use up to 16,383
+      // characters and the value itself is not limited
+      // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
+      // ms724872(v=vs.85).aspx).
+      // Resize the buffers and retry if their size caused the failure.
+      DWORD value_size_in_wchars = to_wchar_size(value_size_);
+      if (value_size_in_wchars + 1 > value_.size())
+        value_.resize(value_size_in_wchars + 1, L'\0');
+      value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
+      name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
+      result = ::RegEnumValue(
+          key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
+          reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
+    }
+
+    if (result == ERROR_SUCCESS) {
+      DCHECK_LT(to_wchar_size(value_size_), value_.size());
+      value_[to_wchar_size(value_size_)] = L'\0';
+      return true;
+    }
+  }
+
+  name_[0] = L'\0';
+  value_[0] = L'\0';
+  value_size_ = 0;
+  return false;
+}
+
+// RegistryKeyIterator --------------------------------------------------------
+
+RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
+                                         const wchar_t* folder_key) {
+  LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
+  if (result != ERROR_SUCCESS) {
+    key_ = NULL;
+  } else {
+    DWORD count = 0;
+    LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
+                                    NULL, NULL, NULL, NULL, NULL);
+
+    if (result != ERROR_SUCCESS) {
+      ::RegCloseKey(key_);
+      key_ = NULL;
+    } else {
+      index_ = count - 1;
+    }
+  }
+
+  Read();
+}
+
+RegistryKeyIterator::~RegistryKeyIterator() {
+  if (key_)
+    ::RegCloseKey(key_);
+}
+
+DWORD RegistryKeyIterator::SubkeyCount() const {
+  DWORD count = 0;
+  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
+                                  NULL, NULL, NULL, NULL, NULL);
+  if (result != ERROR_SUCCESS)
+    return 0;
+
+  return count;
+}
+
+bool RegistryKeyIterator::Valid() const {
+  return key_ != NULL && index_ >= 0;
+}
+
+void RegistryKeyIterator::operator++() {
+  --index_;
+  Read();
+}
+
+bool RegistryKeyIterator::Read() {
+  if (Valid()) {
+    DWORD ncount = arraysize(name_);
+    FILETIME written;
+    LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
+                            NULL, &written);
+    if (ERROR_SUCCESS == r)
+      return true;
+  }
+
+  name_[0] = '\0';
+  return false;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/registry.h b/base/win/registry.h
new file mode 100644
index 0000000..7a3d970
--- /dev/null
+++ b/base/win/registry.h
@@ -0,0 +1,212 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_REGISTRY_H_
+#define BASE_WIN_REGISTRY_H_
+
+#include <windows.h>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/stl_util.h"
+
+namespace base {
+namespace win {
+
+// Utility class to read, write and manipulate the Windows Registry.
+// Registry vocabulary primer: a "key" is like a folder, in which there
+// are "values", which are <name, data> pairs, with an associated data type.
+//
+// Note:
+// ReadValue family of functions guarantee that the return arguments
+// are not touched in case of failure.
+class BASE_EXPORT RegKey {
+ public:
+  RegKey();
+  RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+  ~RegKey();
+
+  LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+
+  LONG CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
+                             DWORD* disposition, REGSAM access);
+
+  // Creates a subkey or open it if it already exists.
+  LONG CreateKey(const wchar_t* name, REGSAM access);
+
+  // Opens an existing reg key.
+  LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+
+  // Opens an existing reg key, given the relative key name.
+  LONG OpenKey(const wchar_t* relative_key_name, REGSAM access);
+
+  // Closes this reg key.
+  void Close();
+
+  // Returns false if this key does not have the specified value, of if an error
+  // occurrs while attempting to access it.
+  bool HasValue(const wchar_t* value_name) const;
+
+  // Returns the number of values for this key, of 0 if the number cannot be
+  // determined.
+  DWORD GetValueCount() const;
+
+  // Determine the nth value's name.
+  LONG GetValueNameAt(int index, std::wstring* name) const;
+
+  // True while the key is valid.
+  bool Valid() const { return key_ != NULL; }
+
+  // Kill a key and everything that live below it; please be careful when using
+  // it.
+  LONG DeleteKey(const wchar_t* name);
+
+  // Deletes a single value within the key.
+  LONG DeleteValue(const wchar_t* name);
+
+  // Getters:
+
+  // Returns an int32 value. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadValueDW(const wchar_t* name, DWORD* out_value) const;
+
+  // Returns an int64 value. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadInt64(const wchar_t* name, int64* out_value) const;
+
+  // Returns a string value. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadValue(const wchar_t* name, std::wstring* out_value) const;
+
+  // Reads a REG_MULTI_SZ registry field into a vector of strings. Clears
+  // |values| initially and adds further strings to the list. Returns
+  // ERROR_CANTREAD if type is not REG_MULTI_SZ.
+  LONG ReadValues(const wchar_t* name, std::vector<std::wstring>* values);
+
+  // Returns raw data. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadValue(const wchar_t* name,
+                 void* data,
+                 DWORD* dsize,
+                 DWORD* dtype) const;
+
+  // Setters:
+
+  // Sets an int32 value.
+  LONG WriteValue(const wchar_t* name, DWORD in_value);
+
+  // Sets a string value.
+  LONG WriteValue(const wchar_t* name, const wchar_t* in_value);
+
+  // Sets raw data, including type.
+  LONG WriteValue(const wchar_t* name,
+                  const void* data,
+                  DWORD dsize,
+                  DWORD dtype);
+
+  // Starts watching the key to see if any of its values have changed.
+  // The key must have been opened with the KEY_NOTIFY access privilege.
+  LONG StartWatching();
+
+  // If StartWatching hasn't been called, always returns false.
+  // Otherwise, returns true if anything under the key has changed.
+  // This can't be const because the |watch_event_| may be refreshed.
+  bool HasChanged();
+
+  // Will automatically be called by destructor if not manually called
+  // beforehand.  Returns true if it was watching, false otherwise.
+  LONG StopWatching();
+
+  inline bool IsWatching() const { return watch_event_ != 0; }
+  HANDLE watch_event() const { return watch_event_; }
+  HKEY Handle() const { return key_; }
+
+ private:
+  HKEY key_;  // The registry key being iterated.
+  HANDLE watch_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegKey);
+};
+
+// Iterates the entries found in a particular folder on the registry.
+class BASE_EXPORT RegistryValueIterator {
+ public:
+  RegistryValueIterator(HKEY root_key, const wchar_t* folder_key);
+
+  ~RegistryValueIterator();
+
+  DWORD ValueCount() const;
+
+  // True while the iterator is valid.
+  bool Valid() const;
+
+  // Advances to the next registry entry.
+  void operator++();
+
+  const wchar_t* Name() const { return name_.c_str(); }
+  const wchar_t* Value() const { return vector_as_array(&value_); }
+  // ValueSize() is in bytes.
+  DWORD ValueSize() const { return value_size_; }
+  DWORD Type() const { return type_; }
+
+  int Index() const { return index_; }
+
+ private:
+  // Read in the current values.
+  bool Read();
+
+  // The registry key being iterated.
+  HKEY key_;
+
+  // Current index of the iteration.
+  int index_;
+
+  // Current values.
+  std::wstring name_;
+  std::vector<wchar_t> value_;
+  DWORD value_size_;
+  DWORD type_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegistryValueIterator);
+};
+
+class BASE_EXPORT RegistryKeyIterator {
+ public:
+  RegistryKeyIterator(HKEY root_key, const wchar_t* folder_key);
+
+  ~RegistryKeyIterator();
+
+  DWORD SubkeyCount() const;
+
+  // True while the iterator is valid.
+  bool Valid() const;
+
+  // Advances to the next entry in the folder.
+  void operator++();
+
+  const wchar_t* Name() const { return name_; }
+
+  int Index() const { return index_; }
+
+ private:
+  // Read in the current values.
+  bool Read();
+
+  // The registry key being iterated.
+  HKEY key_;
+
+  // Current index of the iteration.
+  int index_;
+
+  wchar_t name_[MAX_PATH];
+
+  DISALLOW_COPY_AND_ASSIGN(RegistryKeyIterator);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_REGISTRY_H_
diff --git a/base/win/registry_unittest.cc b/base/win/registry_unittest.cc
new file mode 100644
index 0000000..155402a
--- /dev/null
+++ b/base/win/registry_unittest.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/registry.h"
+
+#include <cstring>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/stl_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+const wchar_t kRootKey[] = L"Base_Registry_Unittest";
+
+class RegistryTest : public testing::Test {
+ public:
+  RegistryTest() {}
+
+ protected:
+  virtual void SetUp() OVERRIDE {
+    // Create a temporary key.
+    RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+    key.DeleteKey(kRootKey);
+    ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+    ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+  }
+
+  virtual void TearDown() OVERRIDE {
+    // Clean up the temporary key.
+    RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE);
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RegistryTest);
+};
+
+TEST_F(RegistryTest, ValueTest) {
+  RegKey key;
+
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+
+  {
+    ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ | KEY_SET_VALUE));
+    ASSERT_TRUE(key.Valid());
+
+    const wchar_t kStringValueName[] = L"StringValue";
+    const wchar_t kDWORDValueName[] = L"DWORDValue";
+    const wchar_t kInt64ValueName[] = L"Int64Value";
+    const wchar_t kStringData[] = L"string data";
+    const DWORD kDWORDData = 0xdeadbabe;
+    const int64 kInt64Data = 0xdeadbabedeadbabeLL;
+
+    // Test value creation
+    ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kStringValueName, kStringData));
+    ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kDWORDValueName, kDWORDData));
+    ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kInt64ValueName, &kInt64Data,
+                                            sizeof(kInt64Data), REG_QWORD));
+    EXPECT_EQ(3U, key.GetValueCount());
+    EXPECT_TRUE(key.HasValue(kStringValueName));
+    EXPECT_TRUE(key.HasValue(kDWORDValueName));
+    EXPECT_TRUE(key.HasValue(kInt64ValueName));
+
+    // Test Read
+    std::wstring string_value;
+    DWORD dword_value = 0;
+    int64 int64_value = 0;
+    ASSERT_EQ(ERROR_SUCCESS, key.ReadValue(kStringValueName, &string_value));
+    ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(kDWORDValueName, &dword_value));
+    ASSERT_EQ(ERROR_SUCCESS, key.ReadInt64(kInt64ValueName, &int64_value));
+    EXPECT_STREQ(kStringData, string_value.c_str());
+    EXPECT_EQ(kDWORDData, dword_value);
+    EXPECT_EQ(kInt64Data, int64_value);
+
+    // Make sure out args are not touched if ReadValue fails
+    const wchar_t* kNonExistent = L"NonExistent";
+    ASSERT_NE(ERROR_SUCCESS, key.ReadValue(kNonExistent, &string_value));
+    ASSERT_NE(ERROR_SUCCESS, key.ReadValueDW(kNonExistent, &dword_value));
+    ASSERT_NE(ERROR_SUCCESS, key.ReadInt64(kNonExistent, &int64_value));
+    EXPECT_STREQ(kStringData, string_value.c_str());
+    EXPECT_EQ(kDWORDData, dword_value);
+    EXPECT_EQ(kInt64Data, int64_value);
+
+    // Test delete
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kStringValueName));
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kDWORDValueName));
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kInt64ValueName));
+    EXPECT_EQ(0U, key.GetValueCount());
+    EXPECT_FALSE(key.HasValue(kStringValueName));
+    EXPECT_FALSE(key.HasValue(kDWORDValueName));
+    EXPECT_FALSE(key.HasValue(kInt64ValueName));
+  }
+}
+
+TEST_F(RegistryTest, BigValueIteratorTest) {
+  RegKey key;
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                    KEY_READ | KEY_SET_VALUE));
+  ASSERT_TRUE(key.Valid());
+
+  // Create a test value that is larger than MAX_PATH.
+  std::wstring data(MAX_PATH * 2, L'a');
+
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(data.c_str(), data.c_str()));
+
+  RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str());
+  ASSERT_TRUE(iterator.Valid());
+  EXPECT_STREQ(data.c_str(), iterator.Name());
+  EXPECT_STREQ(data.c_str(), iterator.Value());
+  // ValueSize() is in bytes, including NUL.
+  EXPECT_EQ((MAX_PATH * 2 + 1) * sizeof(wchar_t), iterator.ValueSize());
+  ++iterator;
+  EXPECT_FALSE(iterator.Valid());
+}
+
+TEST_F(RegistryTest, TruncatedCharTest) {
+  RegKey key;
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                    KEY_READ | KEY_SET_VALUE));
+  ASSERT_TRUE(key.Valid());
+
+  const wchar_t kName[] = L"name";
+  // kData size is not a multiple of sizeof(wchar_t).
+  const uint8 kData[] = { 1, 2, 3, 4, 5 };
+  EXPECT_EQ(5, arraysize(kData));
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kName, kData,
+                                          arraysize(kData), REG_BINARY));
+
+  RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str());
+  ASSERT_TRUE(iterator.Valid());
+  EXPECT_STREQ(kName, iterator.Name());
+  // ValueSize() is in bytes.
+  ASSERT_EQ(arraysize(kData), iterator.ValueSize());
+  // Value() is NUL terminated.
+  int end = (iterator.ValueSize() + sizeof(wchar_t) - 1) / sizeof(wchar_t);
+  EXPECT_NE(L'\0', iterator.Value()[end-1]);
+  EXPECT_EQ(L'\0', iterator.Value()[end]);
+  EXPECT_EQ(0, std::memcmp(kData, iterator.Value(), arraysize(kData)));
+  ++iterator;
+  EXPECT_FALSE(iterator.Valid());
+}
+
+}  // namespace
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/resource_util.cc b/base/win/resource_util.cc
new file mode 100644
index 0000000..de9f583
--- /dev/null
+++ b/base/win/resource_util.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/win/resource_util.h"
+
+namespace base {
+namespace win {
+bool GetDataResourceFromModule(HMODULE module, int resource_id,
+                               void** data, size_t* length) {
+  if (!module)
+    return false;
+
+  if (!IS_INTRESOURCE(resource_id)) {
+    NOTREACHED();
+    return false;
+  }
+
+  HRSRC hres_info = FindResource(module, MAKEINTRESOURCE(resource_id),
+                                 L"BINDATA");
+  if (NULL == hres_info)
+    return false;
+
+  DWORD data_size = SizeofResource(module, hres_info);
+  HGLOBAL hres = LoadResource(module, hres_info);
+  if (!hres)
+    return false;
+
+  void* resource = LockResource(hres);
+  if (!resource)
+    return false;
+
+  *data = resource;
+  *length = static_cast<size_t>(data_size);
+  return true;
+}
+}  // namespace win
+}  // namespace base
diff --git a/base/win/resource_util.h b/base/win/resource_util.h
new file mode 100644
index 0000000..9955402
--- /dev/null
+++ b/base/win/resource_util.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains utility functions for accessing resources in external
+// files (DLLs) or embedded in the executable itself.
+
+#ifndef BASE_WIN_RESOURCE_UTIL_H__
+#define BASE_WIN_RESOURCE_UTIL_H__
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Function for getting a data resource (BINDATA) from a dll.  Some
+// resources are optional, especially in unit tests, so this returns false
+// but doesn't raise an error if the resource can't be loaded.
+bool BASE_EXPORT GetDataResourceFromModule(HMODULE module, int resource_id,
+                                           void** data, size_t* length);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_RESOURCE_UTIL_H__
diff --git a/base/win/sampling_profiler.cc b/base/win/sampling_profiler.cc
new file mode 100644
index 0000000..150452c
--- /dev/null
+++ b/base/win/sampling_profiler.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/win/sampling_profiler.h"
+
+#include <winternl.h>  // for NTSTATUS.
+
+#include "base/lazy_instance.h"
+
+// Copied from wdm.h in the WDK as we don't want to take
+// a dependency on the WDK.
+typedef enum _KPROFILE_SOURCE {
+    ProfileTime,
+    ProfileAlignmentFixup,
+    ProfileTotalIssues,
+    ProfilePipelineDry,
+    ProfileLoadInstructions,
+    ProfilePipelineFrozen,
+    ProfileBranchInstructions,
+    ProfileTotalNonissues,
+    ProfileDcacheMisses,
+    ProfileIcacheMisses,
+    ProfileCacheMisses,
+    ProfileBranchMispredictions,
+    ProfileStoreInstructions,
+    ProfileFpInstructions,
+    ProfileIntegerInstructions,
+    Profile2Issue,
+    Profile3Issue,
+    Profile4Issue,
+    ProfileSpecialInstructions,
+    ProfileTotalCycles,
+    ProfileIcacheIssues,
+    ProfileDcacheAccesses,
+    ProfileMemoryBarrierCycles,
+    ProfileLoadLinkedIssues,
+    ProfileMaximum
+} KPROFILE_SOURCE;
+
+
+namespace {
+
+// Signatures for the native functions we need to access the sampling profiler.
+typedef NTSTATUS (NTAPI *ZwSetIntervalProfileFunc)(ULONG, KPROFILE_SOURCE);
+typedef NTSTATUS (NTAPI *ZwQueryIntervalProfileFunc)(KPROFILE_SOURCE, PULONG);
+
+typedef NTSTATUS (NTAPI *ZwCreateProfileFunc)(PHANDLE profile,
+                                              HANDLE process,
+                                              PVOID code_start,
+                                              ULONG code_size,
+                                              ULONG eip_bucket_shift,
+                                              PULONG buckets,
+                                              ULONG buckets_byte_size,
+                                              KPROFILE_SOURCE source,
+                                              DWORD_PTR processor_mask);
+
+typedef NTSTATUS (NTAPI *ZwStartProfileFunc)(HANDLE);
+typedef NTSTATUS (NTAPI *ZwStopProfileFunc)(HANDLE);
+
+// This class is used to lazy-initialize pointers to the native
+// functions we need to access.
+class ProfilerFuncs {
+ public:
+  ProfilerFuncs();
+
+  ZwSetIntervalProfileFunc ZwSetIntervalProfile;
+  ZwQueryIntervalProfileFunc ZwQueryIntervalProfile;
+  ZwCreateProfileFunc ZwCreateProfile;
+  ZwStartProfileFunc ZwStartProfile;
+  ZwStopProfileFunc ZwStopProfile;
+
+  // True iff all of the function pointers above were successfully initialized.
+  bool initialized_;
+};
+
+ProfilerFuncs::ProfilerFuncs()
+    : ZwSetIntervalProfile(NULL),
+      ZwQueryIntervalProfile(NULL),
+      ZwCreateProfile(NULL),
+      ZwStartProfile(NULL),
+      ZwStopProfile(NULL),
+      initialized_(false) {
+  HMODULE ntdll = ::GetModuleHandle(L"ntdll.dll");
+  if (ntdll != NULL) {
+    ZwSetIntervalProfile = reinterpret_cast<ZwSetIntervalProfileFunc>(
+        ::GetProcAddress(ntdll, "ZwSetIntervalProfile"));
+    ZwQueryIntervalProfile = reinterpret_cast<ZwQueryIntervalProfileFunc>(
+        ::GetProcAddress(ntdll, "ZwQueryIntervalProfile"));
+    ZwCreateProfile = reinterpret_cast<ZwCreateProfileFunc>(
+        ::GetProcAddress(ntdll, "ZwCreateProfile"));
+    ZwStartProfile = reinterpret_cast<ZwStartProfileFunc>(
+        ::GetProcAddress(ntdll, "ZwStartProfile"));
+    ZwStopProfile = reinterpret_cast<ZwStopProfileFunc>(
+        ::GetProcAddress(ntdll, "ZwStopProfile"));
+
+    if (ZwSetIntervalProfile &&
+        ZwQueryIntervalProfile &&
+        ZwCreateProfile &&
+        ZwStartProfile &&
+        ZwStopProfile) {
+      initialized_ = true;
+    }
+  }
+}
+
+base::LazyInstance<ProfilerFuncs>::Leaky funcs = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+
+namespace base {
+namespace win {
+
+SamplingProfiler::SamplingProfiler() : is_started_(false) {
+}
+
+SamplingProfiler::~SamplingProfiler() {
+  if (is_started_) {
+    CHECK(Stop()) <<
+        "Unable to stop sampling profiler, this will cause memory corruption.";
+  }
+}
+
+bool SamplingProfiler::Initialize(HANDLE process,
+                                  void* start,
+                                  size_t size,
+                                  size_t log2_bucket_size) {
+  // You only get to initialize each instance once.
+  DCHECK(!profile_handle_.IsValid());
+  DCHECK(!is_started_);
+  DCHECK(start != NULL);
+  DCHECK_NE(0U, size);
+  DCHECK_LE(2, log2_bucket_size);
+  DCHECK_GE(32, log2_bucket_size);
+
+  // Bail if the native functions weren't found.
+  if (!funcs.Get().initialized_)
+    return false;
+
+  size_t bucket_size = 1 << log2_bucket_size;
+  size_t num_buckets = (size + bucket_size - 1) / bucket_size;
+  DCHECK(num_buckets != 0);
+  buckets_.resize(num_buckets);
+
+  // Get our affinity mask for the call below.
+  DWORD_PTR process_affinity = 0;
+  DWORD_PTR system_affinity = 0;
+  if (!::GetProcessAffinityMask(process, &process_affinity, &system_affinity)) {
+    LOG(ERROR) << "Failed to get process affinity mask.";
+    return false;
+  }
+
+  HANDLE profile = NULL;
+  NTSTATUS status =
+      funcs.Get().ZwCreateProfile(&profile,
+                                  process,
+                                  start,
+                                  static_cast<ULONG>(size),
+                                  static_cast<ULONG>(log2_bucket_size),
+                                  &buckets_[0],
+                                  static_cast<ULONG>(
+                                      sizeof(buckets_[0]) * num_buckets),
+                                  ProfileTime,
+                                  process_affinity);
+
+  if (!NT_SUCCESS(status)) {
+    // Might as well deallocate the buckets.
+    buckets_.resize(0);
+    LOG(ERROR) << "Failed to create profile, error 0x" << std::hex << status;
+    return false;
+  }
+
+  DCHECK(profile != NULL);
+  profile_handle_.Set(profile);
+
+  return true;
+}
+
+bool SamplingProfiler::Start() {
+  DCHECK(profile_handle_.IsValid());
+  DCHECK(!is_started_);
+  DCHECK(funcs.Get().initialized_);
+
+  NTSTATUS status = funcs.Get().ZwStartProfile(profile_handle_.Get());
+  if (!NT_SUCCESS(status))
+    return false;
+
+  is_started_ = true;
+
+  return true;
+}
+
+bool SamplingProfiler::Stop() {
+  DCHECK(profile_handle_.IsValid());
+  DCHECK(is_started_);
+  DCHECK(funcs.Get().initialized_);
+
+  NTSTATUS status = funcs.Get().ZwStopProfile(profile_handle_.Get());
+  if (!NT_SUCCESS(status))
+    return false;
+  is_started_ = false;
+
+  return true;
+}
+
+bool SamplingProfiler::SetSamplingInterval(base::TimeDelta sampling_interval) {
+  if (!funcs.Get().initialized_)
+    return false;
+
+  // According to Nebbet, the sampling interval is in units of 100ns.
+  ULONG interval = sampling_interval.InMicroseconds() * 10;
+  NTSTATUS status = funcs.Get().ZwSetIntervalProfile(interval, ProfileTime);
+  if (!NT_SUCCESS(status))
+    return false;
+
+  return true;
+}
+
+bool SamplingProfiler::GetSamplingInterval(base::TimeDelta* sampling_interval) {
+  DCHECK(sampling_interval != NULL);
+
+  if (!funcs.Get().initialized_)
+    return false;
+
+  ULONG interval = 0;
+  NTSTATUS status = funcs.Get().ZwQueryIntervalProfile(ProfileTime, &interval);
+  if (!NT_SUCCESS(status))
+    return false;
+
+  // According to Nebbet, the sampling interval is in units of 100ns.
+  *sampling_interval = base::TimeDelta::FromMicroseconds(interval / 10);
+
+  return true;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/sampling_profiler.h b/base/win/sampling_profiler.h
new file mode 100644
index 0000000..e7e76d8
--- /dev/null
+++ b/base/win/sampling_profiler.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_WIN_SAMPLING_PROFILER_H_
+#define BASE_WIN_SAMPLING_PROFILER_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/time.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+// This class exposes the functionality of Window's built-in sampling profiler.
+// Each profiler instance covers a range of memory, and while the profiler is
+// running, its buckets will count the number of times the instruction counter
+// lands in the associated range of memory on a sample.
+// The sampling interval is settable, but the setting is system-wide.
+class BASE_EXPORT SamplingProfiler {
+ public:
+  // Create an uninitialized sampling profiler.
+  SamplingProfiler();
+  ~SamplingProfiler();
+
+  // Initializes the profiler to cover the memory range |start| through
+  // |start| + |size|, in the process |process_handle| with bucket size
+  // |2^log2_bucket_size|, |log2_bucket_size| must be in the range 2-31,
+  // for bucket sizes of 4 bytes to 2 gigabytes.
+  // The process handle must grant at least PROCESS_QUERY_INFORMATION.
+  // The memory range should be exectuable code, like e.g. the text segment
+  // of an exectuable (whether DLL or EXE).
+  // Returns true on success.
+  bool Initialize(HANDLE process_handle,
+                  void* start,
+                  size_t size,
+                  size_t log2_bucket_size);
+
+  // Start this profiler, which must be initialized and not started.
+  bool Start();
+  // Stop this profiler, which must be started.
+  bool Stop();
+
+  // Get and set the sampling interval.
+  // Note that this is a system-wide setting.
+  static bool SetSamplingInterval(base::TimeDelta sampling_interval);
+  static bool GetSamplingInterval(base::TimeDelta* sampling_interval);
+
+  // Accessors.
+  bool is_started() const { return is_started_; }
+
+  // It is safe to read the counts in the sampling buckets at any time.
+  // Note however that there's no guarantee that you'll read consistent counts
+  // until the profiler has been stopped, as the counts may be updating on other
+  // CPU cores.
+  const std::vector<ULONG>& buckets() const { return buckets_; }
+
+ private:
+  // Handle to the corresponding kernel object.
+  ScopedHandle profile_handle_;
+  // True iff this profiler is started.
+  bool is_started_;
+  std::vector<ULONG> buckets_;
+
+  DISALLOW_COPY_AND_ASSIGN(SamplingProfiler);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SAMPLING_PROFILER_H_
diff --git a/base/win/sampling_profiler_unittest.cc b/base/win/sampling_profiler_unittest.cc
new file mode 100644
index 0000000..d022026
--- /dev/null
+++ b/base/win/sampling_profiler_unittest.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/logging.h"
+#include "base/test/test_timeouts.h"
+#include "base/win/sampling_profiler.h"
+#include "base/win/pe_image.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// The address of our image base.
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+namespace base {
+namespace win {
+
+namespace {
+
+class SamplingProfilerTest : public testing::Test {
+ public:
+  SamplingProfilerTest() : code_start(NULL), code_size(0) {
+  }
+
+  virtual void SetUp() {
+    process.Set(::OpenProcess(PROCESS_QUERY_INFORMATION,
+                              FALSE,
+                              ::GetCurrentProcessId()));
+    ASSERT_TRUE(process.IsValid());
+
+    PEImage image(&__ImageBase);
+
+    // Get the address of the .text section, which is the first section output
+    // by the VS tools.
+    ASSERT_TRUE(image.GetNumSections() > 0);
+    const IMAGE_SECTION_HEADER* text_section = image.GetSectionHeader(0);
+    ASSERT_EQ(0, strncmp(".text",
+                         reinterpret_cast<const char*>(text_section->Name),
+                         arraysize(text_section->Name)));
+    ASSERT_NE(0U, text_section->Characteristics & IMAGE_SCN_MEM_EXECUTE);
+
+    code_start = reinterpret_cast<uint8*>(&__ImageBase) +
+        text_section->VirtualAddress;
+    code_size = text_section->Misc.VirtualSize;
+  }
+
+ protected:
+  ScopedHandle process;
+  void* code_start;
+  size_t code_size;
+};
+
+}  // namespace
+
+TEST_F(SamplingProfilerTest, Initialize) {
+  SamplingProfiler profiler;
+
+  ASSERT_TRUE(profiler.Initialize(process.Get(), code_start, code_size, 8));
+}
+
+TEST_F(SamplingProfilerTest, Sample) {
+  if (base::win::GetVersion() == base::win::VERSION_WIN8) {
+    LOG(INFO) << "Not running test on Windows 8";
+    return;
+  }
+  SamplingProfiler profiler;
+
+  // Initialize with a huge bucket size, aiming for a single bucket.
+  ASSERT_TRUE(
+      profiler.Initialize(process.Get(), code_start, code_size, 31));
+
+  ASSERT_EQ(1, profiler.buckets().size());
+  ASSERT_EQ(0, profiler.buckets()[0]);
+
+  // We use a roomy timeout to make sure this test is not flaky.
+  // On the buildbots, there may not be a whole lot of CPU time
+  // allotted to our process in this wall-clock time duration,
+  // and samples will only accrue while this thread is busy on
+  // a CPU core.
+  base::TimeDelta spin_time = TestTimeouts::action_timeout();
+
+  base::TimeDelta save_sampling_interval;
+  ASSERT_TRUE(SamplingProfiler::GetSamplingInterval(&save_sampling_interval));
+
+  // Sample every 0.5 millisecs.
+  ASSERT_TRUE(SamplingProfiler::SetSamplingInterval(
+      base::TimeDelta::FromMicroseconds(500)));
+
+  ASSERT_TRUE(SamplingProfiler::SetSamplingInterval(
+      base::TimeDelta::FromMicroseconds(500)));
+
+  // Start the profiler.
+  ASSERT_TRUE(profiler.Start());
+
+  // Get a volatile pointer to our bucket to make sure that the compiler
+  // doesn't optimize out the test in the loop that follows.
+  volatile const ULONG* bucket_ptr = &profiler.buckets()[0];
+
+  // Spin for spin_time wall-clock seconds, or until we get some samples.
+  // Note that sleeping isn't going to do us any good, the samples only
+  // accrue while we're executing code.
+  base::Time start = base::Time::Now();
+  base::TimeDelta elapsed;
+  do {
+    elapsed = base::Time::Now() - start;
+  } while((elapsed < spin_time) && *bucket_ptr == 0);
+
+  // Stop the profiler.
+  ASSERT_TRUE(profiler.Stop());
+
+  // Restore the sampling interval we found.
+  ASSERT_TRUE(SamplingProfiler::SetSamplingInterval(save_sampling_interval));
+
+  // Check that we got some samples.
+  ASSERT_NE(0U, profiler.buckets()[0]);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_bstr.cc b/base/win/scoped_bstr.cc
new file mode 100644
index 0000000..63ade0c
--- /dev/null
+++ b/base/win/scoped_bstr.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_bstr.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+ScopedBstr::ScopedBstr(const char16* non_bstr)
+    : bstr_(SysAllocString(non_bstr)) {
+}
+
+ScopedBstr::~ScopedBstr() {
+  COMPILE_ASSERT(sizeof(ScopedBstr) == sizeof(BSTR), ScopedBstrSize);
+  SysFreeString(bstr_);
+}
+
+void ScopedBstr::Reset(BSTR bstr) {
+  if (bstr != bstr_) {
+    // if |bstr_| is NULL, SysFreeString does nothing.
+    SysFreeString(bstr_);
+    bstr_ = bstr;
+  }
+}
+
+BSTR ScopedBstr::Release() {
+  BSTR bstr = bstr_;
+  bstr_ = NULL;
+  return bstr;
+}
+
+void ScopedBstr::Swap(ScopedBstr& bstr2) {
+  BSTR tmp = bstr_;
+  bstr_ = bstr2.bstr_;
+  bstr2.bstr_ = tmp;
+}
+
+BSTR* ScopedBstr::Receive() {
+  DCHECK(!bstr_) << "BSTR leak.";
+  return &bstr_;
+}
+
+BSTR ScopedBstr::Allocate(const char16* str) {
+  Reset(SysAllocString(str));
+  return bstr_;
+}
+
+BSTR ScopedBstr::AllocateBytes(size_t bytes) {
+  Reset(SysAllocStringByteLen(NULL, static_cast<UINT>(bytes)));
+  return bstr_;
+}
+
+void ScopedBstr::SetByteLen(size_t bytes) {
+  DCHECK(bstr_ != NULL) << "attempting to modify a NULL bstr";
+  uint32* data = reinterpret_cast<uint32*>(bstr_);
+  data[-1] = static_cast<uint32>(bytes);
+}
+
+size_t ScopedBstr::Length() const {
+  return SysStringLen(bstr_);
+}
+
+size_t ScopedBstr::ByteLength() const {
+  return SysStringByteLen(bstr_);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_bstr.h b/base/win/scoped_bstr.h
new file mode 100644
index 0000000..ed46d63
--- /dev/null
+++ b/base/win/scoped_bstr.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_BSTR_H_
+#define BASE_WIN_SCOPED_BSTR_H_
+
+#include <windows.h>
+#include <oleauto.h>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/string16.h"
+
+namespace base {
+namespace win {
+
+// Manages a BSTR string pointer.
+// The class interface is based on scoped_ptr.
+class BASE_EXPORT ScopedBstr {
+ public:
+  ScopedBstr() : bstr_(NULL) {
+  }
+
+  // Constructor to create a new BSTR.
+  //
+  // NOTE: Do not pass a BSTR to this constructor expecting ownership to
+  // be transferred - even though it compiles! ;-)
+  explicit ScopedBstr(const char16* non_bstr);
+  ~ScopedBstr();
+
+  // Give ScopedBstr ownership over an already allocated BSTR or NULL.
+  // If you need to allocate a new BSTR instance, use |allocate| instead.
+  void Reset(BSTR bstr = NULL);
+
+  // Releases ownership of the BSTR to the caller.
+  BSTR Release();
+
+  // Creates a new BSTR from a 16-bit C-style string.
+  //
+  // If you already have a BSTR and want to transfer ownership to the
+  // ScopedBstr instance, call |reset| instead.
+  //
+  // Returns a pointer to the new BSTR, or NULL if allocation failed.
+  BSTR Allocate(const char16* str);
+
+  // Allocates a new BSTR with the specified number of bytes.
+  // Returns a pointer to the new BSTR, or NULL if allocation failed.
+  BSTR AllocateBytes(size_t bytes);
+
+  // Sets the allocated length field of the already-allocated BSTR to be
+  // |bytes|.  This is useful when the BSTR was preallocated with e.g.
+  // SysAllocStringLen or SysAllocStringByteLen (call |AllocateBytes|) and then
+  // not all the bytes are being used.
+  //
+  // Note that if you want to set the length to a specific number of
+  // characters, you need to multiply by sizeof(wchar_t).  Oddly, there's no
+  // public API to set the length, so we do this ourselves by hand.
+  //
+  // NOTE: The actual allocated size of the BSTR MUST be >= bytes.  That
+  // responsibility is with the caller.
+  void SetByteLen(size_t bytes);
+
+  // Swap values of two ScopedBstr's.
+  void Swap(ScopedBstr& bstr2);
+
+  // Retrieves the pointer address.
+  // Used to receive BSTRs as out arguments (and take ownership).
+  // The function DCHECKs on the current value being NULL.
+  // Usage: GetBstr(bstr.Receive());
+  BSTR* Receive();
+
+  // Returns number of chars in the BSTR.
+  size_t Length() const;
+
+  // Returns the number of bytes allocated for the BSTR.
+  size_t ByteLength() const;
+
+  operator BSTR() const {
+    return bstr_;
+  }
+
+ protected:
+  BSTR bstr_;
+
+ private:
+  // Forbid comparison of ScopedBstr types.  You should never have the same
+  // BSTR owned by two different scoped_ptrs.
+  bool operator==(const ScopedBstr& bstr2) const;
+  bool operator!=(const ScopedBstr& bstr2) const;
+  DISALLOW_COPY_AND_ASSIGN(ScopedBstr);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_SCOPED_BSTR_H_
diff --git a/base/win/scoped_bstr_unittest.cc b/base/win/scoped_bstr_unittest.cc
new file mode 100644
index 0000000..5f6f7df
--- /dev/null
+++ b/base/win/scoped_bstr_unittest.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_bstr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const wchar_t kTestString1[] = L"123";
+static const wchar_t kTestString2[] = L"456789";
+size_t test1_len = arraysize(kTestString1) - 1;
+size_t test2_len = arraysize(kTestString2) - 1;
+
+void DumbBstrTests() {
+  ScopedBstr b;
+  EXPECT_TRUE(b == NULL);
+  EXPECT_EQ(0, b.Length());
+  EXPECT_EQ(0, b.ByteLength());
+  b.Reset(NULL);
+  EXPECT_TRUE(b == NULL);
+  EXPECT_TRUE(b.Release() == NULL);
+  ScopedBstr b2;
+  b.Swap(b2);
+  EXPECT_TRUE(b2 == NULL);
+}
+
+void GiveMeABstr(BSTR* ret) {
+  *ret = SysAllocString(kTestString1);
+}
+
+void BasicBstrTests() {
+  ScopedBstr b1(kTestString1);
+  EXPECT_EQ(test1_len, b1.Length());
+  EXPECT_EQ(test1_len * sizeof(kTestString1[0]), b1.ByteLength());
+
+  ScopedBstr b2;
+  b1.Swap(b2);
+  EXPECT_EQ(test1_len, b2.Length());
+  EXPECT_EQ(0, b1.Length());
+  EXPECT_EQ(0, lstrcmp(b2, kTestString1));
+  BSTR tmp = b2.Release();
+  EXPECT_TRUE(tmp != NULL);
+  EXPECT_EQ(0, lstrcmp(tmp, kTestString1));
+  EXPECT_TRUE(b2 == NULL);
+  SysFreeString(tmp);
+
+  GiveMeABstr(b2.Receive());
+  EXPECT_TRUE(b2 != NULL);
+  b2.Reset();
+  EXPECT_TRUE(b2.AllocateBytes(100) != NULL);
+  EXPECT_EQ(100, b2.ByteLength());
+  EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
+  lstrcpy(static_cast<BSTR>(b2), kTestString1);
+  EXPECT_EQ(test1_len, lstrlen(b2));
+  EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
+  b2.SetByteLen(lstrlen(b2) * sizeof(kTestString2[0]));
+  EXPECT_EQ(b2.Length(), lstrlen(b2));
+
+  EXPECT_TRUE(b1.Allocate(kTestString2) != NULL);
+  EXPECT_EQ(test2_len, b1.Length());
+  b1.SetByteLen((test2_len - 1) * sizeof(kTestString2[0]));
+  EXPECT_EQ(test2_len - 1, b1.Length());
+}
+
+}  // namespace
+
+TEST(ScopedBstrTest, ScopedBstr) {
+  DumbBstrTests();
+  BasicBstrTests();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_co_mem.h b/base/win/scoped_co_mem.h
new file mode 100644
index 0000000..572999a
--- /dev/null
+++ b/base/win/scoped_co_mem.h
@@ -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.
+
+#ifndef BASE_WIN_SCOPED_CO_MEM_H_
+#define BASE_WIN_SCOPED_CO_MEM_H_
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Simple scoped memory releaser class for COM allocated memory.
+// Example:
+//   base::win::ScopedCoMem<ITEMIDLIST> file_item;
+//   SHGetSomeInfo(&file_item, ...);
+//   ...
+//   return;  <-- memory released
+template<typename T>
+class ScopedCoMem {
+ public:
+  ScopedCoMem() : mem_ptr_(NULL) {}
+  ~ScopedCoMem() {
+    Reset(NULL);
+  }
+
+  T** operator&() {  // NOLINT
+    DCHECK(mem_ptr_ == NULL);  // To catch memory leaks.
+    return &mem_ptr_;
+  }
+
+  operator T*() {
+    return mem_ptr_;
+  }
+
+  T* operator->() {
+    DCHECK(mem_ptr_ != NULL);
+    return mem_ptr_;
+  }
+
+  const T* operator->() const {
+    DCHECK(mem_ptr_ != NULL);
+    return mem_ptr_;
+  }
+
+  void Reset(T* ptr) {
+    if (mem_ptr_)
+      CoTaskMemFree(mem_ptr_);
+    mem_ptr_ = ptr;
+  }
+
+ private:
+  T* mem_ptr_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCoMem);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_CO_MEM_H_
diff --git a/base/win/scoped_com_initializer.h b/base/win/scoped_com_initializer.h
new file mode 100644
index 0000000..392c351
--- /dev/null
+++ b/base/win/scoped_com_initializer.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_COM_INITIALIZER_H_
+#define BASE_WIN_SCOPED_COM_INITIALIZER_H_
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace win {
+
+// Initializes COM in the constructor (STA or MTA), and uninitializes COM in the
+// destructor.
+class ScopedCOMInitializer {
+ public:
+  // Enum value provided to initialize the thread as an MTA instead of STA.
+  enum SelectMTA { kMTA };
+
+  // Constructor for STA initialization.
+  ScopedCOMInitializer() {
+    Initialize(COINIT_APARTMENTTHREADED);
+  }
+
+  // Constructor for MTA initialization.
+  explicit ScopedCOMInitializer(SelectMTA mta) {
+    Initialize(COINIT_MULTITHREADED);
+  }
+
+  ~ScopedCOMInitializer() {
+#ifndef NDEBUG
+    // Using the windows API directly to avoid dependency on platform_thread.
+    DCHECK_EQ(GetCurrentThreadId(), thread_id_);
+#endif
+    if (succeeded())
+      CoUninitialize();
+  }
+
+  bool succeeded() const { return SUCCEEDED(hr_); }
+
+ private:
+  void Initialize(COINIT init) {
+#ifndef NDEBUG
+    thread_id_ = GetCurrentThreadId();
+#endif
+    hr_ = CoInitializeEx(NULL, init);
+#ifndef NDEBUG
+    if (hr_ == S_FALSE)
+      LOG(ERROR) << "Multiple CoInitialize() calls for thread " << thread_id_;
+    else
+      DCHECK_NE(RPC_E_CHANGED_MODE, hr_) << "Invalid COM thread model change";
+#endif
+  }
+
+  HRESULT hr_;
+#ifndef NDEBUG
+  // In debug builds we use this variable to catch a potential bug where a
+  // ScopedCOMInitializer instance is deleted on a different thread than it
+  // was initially created on.  If that ever happens it can have bad
+  // consequences and the cause can be tricky to track down.
+  DWORD thread_id_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_COM_INITIALIZER_H_
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h
new file mode 100644
index 0000000..9d5301f
--- /dev/null
+++ b/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.
+    COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) ==
+                   sizeof(Interface*), ScopedComPtrSize);
+  }
+
+  // Explicit Release() of the held object.  Useful for reuse of the
+  // ScopedComPtr instance.
+  // Note that this function equates to IUnknown::Release and should not
+  // be confused with e.g. scoped_ptr::release().
+  void Release() {
+    if (ptr_ != NULL) {
+      ptr_->Release();
+      ptr_ = NULL;
+    }
+  }
+
+  // Sets the internal pointer to NULL and returns the held object without
+  // releasing the reference.
+  Interface* Detach() {
+    Interface* p = ptr_;
+    ptr_ = NULL;
+    return p;
+  }
+
+  // Accepts an interface pointer that has already been addref-ed.
+  void Attach(Interface* p) {
+    DCHECK(!ptr_);
+    ptr_ = p;
+  }
+
+  // Retrieves the pointer address.
+  // Used to receive object pointers as out arguments (and take ownership).
+  // The function DCHECKs on the current value being NULL.
+  // Usage: Foo(p.Receive());
+  Interface** Receive() {
+    DCHECK(!ptr_) << "Object leak. Pointer must be NULL";
+    return &ptr_;
+  }
+
+  // A convenience for whenever a void pointer is needed as an out argument.
+  void** ReceiveVoid() {
+    return reinterpret_cast<void**>(Receive());
+  }
+
+  template <class Query>
+  HRESULT QueryInterface(Query** p) {
+    DCHECK(p != NULL);
+    DCHECK(ptr_ != NULL);
+    // IUnknown already has a template version of QueryInterface
+    // so the iid parameter is implicit here. The only thing this
+    // function adds are the DCHECKs.
+    return ptr_->QueryInterface(p);
+  }
+
+  // QI for times when the IID is not associated with the type.
+  HRESULT QueryInterface(const IID& iid, void** obj) {
+    DCHECK(obj != NULL);
+    DCHECK(ptr_ != NULL);
+    return ptr_->QueryInterface(iid, obj);
+  }
+
+  // Queries |other| for the interface this object wraps and returns the
+  // error code from the other->QueryInterface operation.
+  HRESULT QueryFrom(IUnknown* object) {
+    DCHECK(object != NULL);
+    return object->QueryInterface(Receive());
+  }
+
+  // Convenience wrapper around CoCreateInstance
+  HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
+                         DWORD context = CLSCTX_ALL) {
+    DCHECK(!ptr_);
+    HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
+                                    reinterpret_cast<void**>(&ptr_));
+    return hr;
+  }
+
+  // Checks if the identity of |other| and this object is the same.
+  bool IsSameObject(IUnknown* other) {
+    if (!other && !ptr_)
+      return true;
+
+    if (!other || !ptr_)
+      return false;
+
+    ScopedComPtr<IUnknown> my_identity;
+    QueryInterface(my_identity.Receive());
+
+    ScopedComPtr<IUnknown> other_identity;
+    other->QueryInterface(other_identity.Receive());
+
+    return static_cast<IUnknown*>(my_identity) ==
+           static_cast<IUnknown*>(other_identity);
+  }
+
+  // Provides direct access to the interface.
+  // Here we use a well known trick to make sure we block access to
+  // IUknown methods so that something bad like this doesn't happen:
+  //    ScopedComPtr<IUnknown> p(Foo());
+  //    p->Release();
+  //    ... later the destructor runs, which will Release() again.
+  // and to get the benefit of the DCHECKs we add to QueryInterface.
+  // There's still a way to call these methods if you absolutely must
+  // by statically casting the ScopedComPtr instance to the wrapped interface
+  // and then making the call... but generally that shouldn't be necessary.
+  BlockIUnknownMethods* operator->() const {
+    DCHECK(ptr_ != NULL);
+    return reinterpret_cast<BlockIUnknownMethods*>(ptr_);
+  }
+
+  // Pull in operator=() from the parent class.
+  using scoped_refptr<Interface>::operator=;
+
+  // static methods
+
+  static const IID& iid() {
+    return *interface_id;
+  }
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_COMPTR_H_
diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc
new file mode 100644
index 0000000..d8d12be
--- /dev/null
+++ b/base/win/scoped_comptr_unittest.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_comptr.h"
+
+#include <shlobj.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_com_initializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct Dummy {
+  Dummy() : adds(0), releases(0) { }
+  void AddRef() { ++adds; }
+  void Release() { ++releases; }
+
+  int adds;
+  int releases;
+};
+
+extern const IID dummy_iid;
+const IID dummy_iid = { 0x12345678u, 0x1234u, 0x5678u, 01, 23, 45, 67, 89,
+                        01, 23, 45 };
+
+}  // namespace
+
+TEST(ScopedComPtrTest, ScopedComPtr) {
+  EXPECT_TRUE(memcmp(&ScopedComPtr<IUnknown>::iid(), &IID_IUnknown,
+                     sizeof(IID)) == 0);
+
+  base::win::ScopedCOMInitializer com_initializer;
+  EXPECT_TRUE(com_initializer.succeeded());
+
+  ScopedComPtr<IUnknown> unk;
+  EXPECT_TRUE(SUCCEEDED(unk.CreateInstance(CLSID_ShellLink)));
+  ScopedComPtr<IUnknown> unk2;
+  unk2.Attach(unk.Detach());
+  EXPECT_TRUE(unk == NULL);
+  EXPECT_TRUE(unk2 != NULL);
+
+  ScopedComPtr<IMalloc> mem_alloc;
+  EXPECT_TRUE(SUCCEEDED(CoGetMalloc(1, mem_alloc.Receive())));
+
+  ScopedComPtr<IUnknown> qi_test;
+  EXPECT_HRESULT_SUCCEEDED(mem_alloc.QueryInterface(IID_IUnknown,
+      reinterpret_cast<void**>(qi_test.Receive())));
+  EXPECT_TRUE(qi_test.get() != NULL);
+  qi_test.Release();
+
+  // test ScopedComPtr& constructor
+  ScopedComPtr<IMalloc> copy1(mem_alloc);
+  EXPECT_TRUE(copy1.IsSameObject(mem_alloc));
+  EXPECT_FALSE(copy1.IsSameObject(unk2));  // unk2 is valid but different
+  EXPECT_FALSE(copy1.IsSameObject(unk));  // unk is NULL
+
+  IMalloc* naked_copy = copy1.Detach();
+  copy1 = naked_copy;  // Test the =(T*) operator.
+  naked_copy->Release();
+
+  copy1.Release();
+  EXPECT_FALSE(copy1.IsSameObject(unk2));  // unk2 is valid, copy1 is not
+
+  // test Interface* constructor
+  ScopedComPtr<IMalloc> copy2(static_cast<IMalloc*>(mem_alloc));
+  EXPECT_TRUE(copy2.IsSameObject(mem_alloc));
+
+  EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc)));
+  EXPECT_TRUE(unk != NULL);
+  unk.Release();
+  EXPECT_TRUE(unk == NULL);
+  EXPECT_TRUE(unk.IsSameObject(copy1));  // both are NULL
+}
+
+TEST(ScopedComPtrTest, ScopedComPtrVector) {
+  // Verify we don't get error C2558.
+  typedef ScopedComPtr<Dummy, &dummy_iid> Ptr;
+  std::vector<Ptr> bleh;
+
+  scoped_ptr<Dummy> p(new Dummy);
+  {
+    Ptr p2(p.get());
+    EXPECT_EQ(p->adds, 1);
+    EXPECT_EQ(p->releases, 0);
+    Ptr p3 = p2;
+    EXPECT_EQ(p->adds, 2);
+    EXPECT_EQ(p->releases, 0);
+    p3 = p2;
+    EXPECT_EQ(p->adds, 3);
+    EXPECT_EQ(p->releases, 1);
+    // To avoid hitting a reallocation.
+    bleh.reserve(1);
+    bleh.push_back(p2);
+    EXPECT_EQ(p->adds, 4);
+    EXPECT_EQ(p->releases, 1);
+    EXPECT_EQ(bleh[0], p.get());
+    bleh.pop_back();
+    EXPECT_EQ(p->adds, 4);
+    EXPECT_EQ(p->releases, 2);
+  }
+  EXPECT_EQ(p->adds, 4);
+  EXPECT_EQ(p->releases, 4);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_gdi_object.h b/base/win/scoped_gdi_object.h
new file mode 100644
index 0000000..d44310a
--- /dev/null
+++ b/base/win/scoped_gdi_object.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_GDI_OBJECT_H_
+#define BASE_WIN_SCOPED_GDI_OBJECT_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle but for GDI objects.
+template<class T>
+class ScopedGDIObject {
+ public:
+  ScopedGDIObject() : object_(NULL) {}
+  explicit ScopedGDIObject(T object) : object_(object) {}
+
+  ~ScopedGDIObject() {
+    Close();
+  }
+
+  T Get() {
+    return object_;
+  }
+
+  void Set(T object) {
+    if (object_ && object != object_)
+      Close();
+    object_ = object;
+  }
+
+  ScopedGDIObject& operator=(T object) {
+    Set(object);
+    return *this;
+  }
+
+  T release() {
+    T object = object_;
+    object_ = NULL;
+    return object;
+  }
+
+  operator T() { return object_; }
+
+ private:
+  void Close() {
+    if (object_)
+      DeleteObject(object_);
+  }
+
+  T object_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedGDIObject);
+};
+
+// An explicit specialization for HICON because we have to call DestroyIcon()
+// instead of DeleteObject() for HICON.
+template<>
+void ScopedGDIObject<HICON>::Close() {
+  if (object_)
+    DestroyIcon(object_);
+}
+
+// Typedefs for some common use cases.
+typedef ScopedGDIObject<HBITMAP> ScopedBitmap;
+typedef ScopedGDIObject<HRGN> ScopedRegion;
+typedef ScopedGDIObject<HFONT> ScopedHFONT;
+typedef ScopedGDIObject<HICON> ScopedHICON;
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_GDI_OBJECT_H_
diff --git a/base/win/scoped_handle.cc b/base/win/scoped_handle.cc
new file mode 100644
index 0000000..03d026a
--- /dev/null
+++ b/base/win/scoped_handle.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/win/scoped_handle.h"
+
+#include <map>
+#include <set>
+
+#include "base/debug/alias.h"
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+struct Info {
+  const void* owner;
+  const void* pc1;
+  const void* pc2;
+  DWORD thread_id;
+};
+typedef std::map<HANDLE, Info> HandleMap;
+
+base::LazyInstance<HandleMap>::Leaky g_handle_map = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<std::set<const void*> >::Leaky g_owner_set =
+    LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::Lock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+namespace win {
+
+// Static.
+void VerifierTraits::StartTracking(HANDLE handle, const void* owner,
+                                   const void* pc1, const void* pc2) {
+  // Grab the thread id before the lock.
+  DWORD thread_id = GetCurrentThreadId();
+
+  AutoLock lock(g_lock.Get());
+
+  if (handle == INVALID_HANDLE_VALUE) {
+    // Cannot track this handle.
+    g_owner_set.Get().insert(owner);
+    return;
+  }
+
+  Info handle_info = { owner, pc1, pc2, thread_id };
+  std::pair<HANDLE, Info> item(handle, handle_info);
+  std::pair<HandleMap::iterator, bool> result = g_handle_map.Get().insert(item);
+  if (!result.second) {
+    Info other = result.first->second;
+    debug::Alias(&other);
+    CHECK(false);
+  }
+}
+
+// Static.
+void VerifierTraits::StopTracking(HANDLE handle, const void* owner,
+                                  const void* pc1, const void* pc2) {
+  AutoLock lock(g_lock.Get());
+  HandleMap::iterator i = g_handle_map.Get().find(handle);
+  if (i == g_handle_map.Get().end()) {
+    std::set<const void*>::iterator j = g_owner_set.Get().find(owner);
+    if (j != g_owner_set.Get().end()) {
+      g_owner_set.Get().erase(j);
+      return;
+    }
+    CHECK(false);
+  }
+
+  Info other = i->second;
+  if (other.owner != owner) {
+    debug::Alias(&other);
+    CHECK(false);
+  }
+
+  g_handle_map.Get().erase(i);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_handle.h b/base/win/scoped_handle.h
new file mode 100644
index 0000000..b5d9b5c
--- /dev/null
+++ b/base/win/scoped_handle.h
@@ -0,0 +1,188 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_HANDLE_H_
+#define BASE_WIN_SCOPED_HANDLE_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/move.h"
+
+namespace base {
+namespace win {
+
+// TODO(rvargas): remove this with the rest of the verifier.
+#if defined(COMPILER_MSVC)
+// MSDN says to #include <intrin.h>, but that breaks the VS2005 build.
+extern "C" {
+  void* _ReturnAddress();
+}
+#define BASE_WIN_GET_CALLER _ReturnAddress()
+#elif defined(COMPILER_GCC)
+#define BASE_WIN_GET_CALLER __builtin_extract_return_addr(\\
+    __builtin_return_address(0))
+#endif
+
+// Generic wrapper for raw handles that takes care of closing handles
+// automatically. The class interface follows the style of
+// the ScopedStdioHandle class with a few additions:
+//   - IsValid() method can tolerate multiple invalid handle values such as NULL
+//     and INVALID_HANDLE_VALUE (-1) for Win32 handles.
+//   - Receive() method allows to receive a handle value from a function that
+//     takes a raw handle pointer only.
+template <class Traits, class Verifier>
+class GenericScopedHandle {
+  MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue)
+
+ public:
+  typedef typename Traits::Handle Handle;
+
+  GenericScopedHandle() : handle_(Traits::NullHandle()) {}
+
+  explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
+    Set(handle);
+  }
+
+  // Move constructor for C++03 move emulation of this type.
+  GenericScopedHandle(RValue other) : handle_(Traits::NullHandle()) {
+    Set(other.object->Take());
+  }
+
+  ~GenericScopedHandle() {
+    Close();
+  }
+
+  bool IsValid() const {
+    return Traits::IsHandleValid(handle_);
+  }
+
+  // Move operator= for C++03 move emulation of this type.
+  GenericScopedHandle& operator=(RValue other) {
+    if (this != other.object) {
+      Set(other.object->Take());
+    }
+    return *this;
+  }
+
+  void Set(Handle handle) {
+    if (handle_ != handle) {
+      Close();
+
+      if (Traits::IsHandleValid(handle)) {
+        handle_ = handle;
+        Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
+                                tracked_objects::GetProgramCounter());
+      }
+    }
+  }
+
+  Handle Get() const {
+    return handle_;
+  }
+
+  operator Handle() const {
+    return handle_;
+  }
+
+  Handle* Receive() {
+    DCHECK(!Traits::IsHandleValid(handle_)) << "Handle must be NULL";
+
+    // We cannot track this case :(. Just tell the verifier about it.
+    Verifier::StartTracking(INVALID_HANDLE_VALUE, this, BASE_WIN_GET_CALLER,
+                            tracked_objects::GetProgramCounter());
+    return &handle_;
+  }
+
+  // Transfers ownership away from this object.
+  Handle Take() {
+    Handle temp = handle_;
+    handle_ = Traits::NullHandle();
+    if (Traits::IsHandleValid(temp)) {
+      Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER,
+                             tracked_objects::GetProgramCounter());
+    }
+    return temp;
+  }
+
+  // Explicitly closes the owned handle.
+  void Close() {
+    if (Traits::IsHandleValid(handle_)) {
+      Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER,
+                             tracked_objects::GetProgramCounter());
+
+      if (!Traits::CloseHandle(handle_))
+        CHECK(false);
+
+      handle_ = Traits::NullHandle();
+    }
+  }
+
+ private:
+  Handle handle_;
+};
+
+#undef BASE_WIN_GET_CALLER
+
+// The traits class for Win32 handles that can be closed via CloseHandle() API.
+class HandleTraits {
+ public:
+  typedef HANDLE Handle;
+
+  // Closes the handle.
+  static bool CloseHandle(HANDLE handle) {
+    return ::CloseHandle(handle) != FALSE;
+  }
+
+  // Returns true if the handle value is valid.
+  static bool IsHandleValid(HANDLE handle) {
+    return handle != NULL && handle != INVALID_HANDLE_VALUE;
+  }
+
+  // Returns NULL handle value.
+  static HANDLE NullHandle() {
+    return NULL;
+  }
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits);
+};
+
+// Do-nothing verifier.
+class DummyVerifierTraits {
+ public:
+  typedef HANDLE Handle;
+
+  static void StartTracking(HANDLE handle, const void* owner,
+                            const void* pc1, const void* pc2) {}
+  static void StopTracking(HANDLE handle, const void* owner,
+                           const void* pc1, const void* pc2) {}
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DummyVerifierTraits);
+};
+
+// Performs actual run-time tracking.
+class BASE_EXPORT VerifierTraits {
+ public:
+  typedef HANDLE Handle;
+
+  static void StartTracking(HANDLE handle, const void* owner,
+                            const void* pc1, const void* pc2);
+  static void StopTracking(HANDLE handle, const void* owner,
+                           const void* pc1, const void* pc2);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(VerifierTraits);
+};
+
+typedef GenericScopedHandle<HandleTraits, VerifierTraits> ScopedHandle;
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_SCOPED_HANDLE_WIN_H_
diff --git a/base/win/scoped_hdc.h b/base/win/scoped_hdc.h
new file mode 100644
index 0000000..9aead96
--- /dev/null
+++ b/base/win/scoped_hdc.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_HDC_H_
+#define BASE_WIN_SCOPED_HDC_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle but for HDC.  Only use this on HDCs returned from
+// GetDC.
+class ScopedGetDC {
+ public:
+  explicit ScopedGetDC(HWND hwnd)
+      : hwnd_(hwnd),
+        hdc_(GetDC(hwnd)) {
+    if (hwnd_) {
+      DCHECK(IsWindow(hwnd_));
+      DCHECK(hdc_);
+    } else {
+      // If GetDC(NULL) returns NULL, something really bad has happened, like
+      // GDI handle exhaustion.  In this case Chrome is going to behave badly no
+      // matter what, so we may as well just force a crash now.
+      CHECK(hdc_);
+    }
+  }
+
+  ~ScopedGetDC() {
+    if (hdc_)
+      ReleaseDC(hwnd_, hdc_);
+  }
+
+  operator HDC() { return hdc_; }
+
+ private:
+  HWND hwnd_;
+  HDC hdc_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedGetDC);
+};
+
+// Like ScopedHandle but for HDC.  Only use this on HDCs returned from
+// CreateCompatibleDC, CreateDC and CreateIC.
+class CreateDCTraits {
+ public:
+  typedef HDC Handle;
+
+  static bool CloseHandle(HDC handle) {
+    return ::DeleteDC(handle) != FALSE;
+  }
+
+  static bool IsHandleValid(HDC handle) {
+    return handle != NULL;
+  }
+
+  static HDC NullHandle() {
+    return NULL;
+  }
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CreateDCTraits);
+};
+
+typedef GenericScopedHandle<CreateDCTraits, VerifierTraits> ScopedCreateDC;
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_HDC_H_
diff --git a/base/win/scoped_hglobal.h b/base/win/scoped_hglobal.h
new file mode 100644
index 0000000..891e6cd
--- /dev/null
+++ b/base/win/scoped_hglobal.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_HGLOBAL_H_
+#define BASE_WIN_SCOPED_HGLOBAL_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle except for HGLOBAL.
+template<class T>
+class ScopedHGlobal {
+ public:
+  explicit ScopedHGlobal(HGLOBAL glob) : glob_(glob) {
+    data_ = static_cast<T*>(GlobalLock(glob_));
+  }
+  ~ScopedHGlobal() {
+    GlobalUnlock(glob_);
+  }
+
+  T* get() { return data_; }
+
+  size_t Size() const { return GlobalSize(glob_); }
+
+  T* operator->() const  {
+    assert(data_ != 0);
+    return data_;
+  }
+
+  T* release() {
+    T* data = data_;
+    data_ = NULL;
+    return data;
+  }
+
+ private:
+  HGLOBAL glob_;
+
+  T* data_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedHGlobal);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_HGLOBAL_H_
diff --git a/base/win/scoped_process_information.cc b/base/win/scoped_process_information.cc
new file mode 100644
index 0000000..4adb8d4
--- /dev/null
+++ b/base/win/scoped_process_information.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 "base/win/scoped_process_information.h"
+
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Closes the provided handle if it is not NULL.
+void CheckAndCloseHandle(HANDLE handle) {
+  if (!handle)
+    return;
+  if (::CloseHandle(handle))
+    return;
+  CHECK(false);
+}
+
+// Duplicates source into target, returning true upon success. |target| is
+// guaranteed to be untouched in case of failure. Succeeds with no side-effects
+// if source is NULL.
+bool CheckAndDuplicateHandle(HANDLE source, HANDLE* target) {
+  if (!source)
+    return true;
+
+  HANDLE temp = NULL;
+  if (!::DuplicateHandle(::GetCurrentProcess(), source,
+                         ::GetCurrentProcess(), &temp, 0, FALSE,
+                         DUPLICATE_SAME_ACCESS)) {
+    DPLOG(ERROR) << "Failed to duplicate a handle.";
+    return false;
+  }
+  *target = temp;
+  return true;
+}
+
+}  // namespace
+
+ScopedProcessInformation::ScopedProcessInformation()
+    : process_information_() {
+}
+
+ScopedProcessInformation::~ScopedProcessInformation() {
+  Close();
+}
+
+PROCESS_INFORMATION* ScopedProcessInformation::Receive() {
+  DCHECK(!IsValid()) << "process_information_ must be NULL";
+  return &process_information_;
+}
+
+bool ScopedProcessInformation::IsValid() const {
+  return process_information_.hThread || process_information_.hProcess ||
+    process_information_.dwProcessId || process_information_.dwThreadId;
+}
+
+
+void ScopedProcessInformation::Close() {
+  CheckAndCloseHandle(process_information_.hThread);
+  CheckAndCloseHandle(process_information_.hProcess);
+  Reset();
+}
+
+void ScopedProcessInformation::Swap(ScopedProcessInformation* other) {
+  DCHECK(other);
+  PROCESS_INFORMATION temp = other->process_information_;
+  other->process_information_ = process_information_;
+  process_information_ = temp;
+}
+
+bool ScopedProcessInformation::DuplicateFrom(
+    const ScopedProcessInformation& other) {
+  DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL";
+  DCHECK(other.IsValid()) << "source ScopedProcessInformation must be valid";
+
+  ScopedHandle duplicate_process;
+  ScopedHandle duplicate_thread;
+
+  if (CheckAndDuplicateHandle(other.process_handle(),
+                              duplicate_process.Receive()) &&
+      CheckAndDuplicateHandle(other.thread_handle(),
+                              duplicate_thread.Receive())) {
+    process_information_.dwProcessId = other.process_id();
+    process_information_.dwThreadId = other.thread_id();
+    process_information_.hProcess = duplicate_process.Take();
+    process_information_.hThread = duplicate_thread.Take();
+    return true;
+  }
+
+  return false;
+}
+
+PROCESS_INFORMATION ScopedProcessInformation::Take() {
+  PROCESS_INFORMATION process_information = process_information_;
+  Reset();
+  return process_information;
+}
+
+HANDLE ScopedProcessInformation::TakeProcessHandle() {
+  HANDLE process = process_information_.hProcess;
+  process_information_.hProcess = NULL;
+  process_information_.dwProcessId = 0;
+  return process;
+}
+
+HANDLE ScopedProcessInformation::TakeThreadHandle() {
+  HANDLE thread = process_information_.hThread;
+  process_information_.hThread = NULL;
+  process_information_.dwThreadId = 0;
+  return thread;
+}
+
+void ScopedProcessInformation::Reset() {
+  process_information_.hThread = NULL;
+  process_information_.hProcess = NULL;
+  process_information_.dwProcessId = 0;
+  process_information_.dwThreadId = 0;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_process_information.h b/base/win/scoped_process_information.h
new file mode 100644
index 0000000..cfa7dc9
--- /dev/null
+++ b/base/win/scoped_process_information.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
+#define BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/base_export.h"
+
+namespace base {
+namespace win {
+
+// Manages the closing of process and thread handles from PROCESS_INFORMATION
+// structures. Allows clients to take ownership of either handle independently.
+class BASE_EXPORT ScopedProcessInformation {
+ public:
+  // Creates an instance holding a null PROCESS_INFORMATION.
+  ScopedProcessInformation();
+
+  // Closes the held thread and process handles, if any.
+  ~ScopedProcessInformation();
+
+  // Returns a pointer that may be passed to API calls such as CreateProcess.
+  // DCHECKs that the object is not currently holding any handles.
+  // HANDLEs stored in the returned PROCESS_INFORMATION will be owned by this
+  // instance.
+  PROCESS_INFORMATION* Receive();
+
+  // Returns true iff this instance is holding a thread and/or process handle.
+  bool IsValid() const;
+
+  // Closes the held thread and process handles, if any, and resets the held
+  // PROCESS_INFORMATION to null.
+  void Close();
+
+  // Swaps contents with the other ScopedProcessInformation.
+  void Swap(ScopedProcessInformation* other);
+
+  // Populates this instance with duplicate handles and the thread/process IDs
+  // from |other|. Returns false in case of failure, in which case this instance
+  // will be completely unpopulated.
+  bool DuplicateFrom(const ScopedProcessInformation& other);
+
+  // Transfers ownership of the held PROCESS_INFORMATION, if any, away from this
+  // instance. Resets the held PROCESS_INFORMATION to null.
+  PROCESS_INFORMATION Take();
+
+  // Transfers ownership of the held process handle, if any, away from this
+  // instance. The hProcess and dwProcessId members of the held
+  // PROCESS_INFORMATION will be reset.
+  HANDLE TakeProcessHandle();
+
+  // Transfers ownership of the held thread handle, if any, away from this
+  // instance. The hThread and dwThreadId members of the held
+  // PROCESS_INFORMATION will be reset.
+  HANDLE TakeThreadHandle();
+
+  // Returns the held process handle, if any, while retaining ownership.
+  HANDLE process_handle() const {
+    return process_information_.hProcess;
+  }
+
+  // Returns the held thread handle, if any, while retaining ownership.
+  HANDLE thread_handle() const {
+    return process_information_.hThread;
+  }
+
+  // Returns the held process id, if any.
+  DWORD process_id() const {
+    return process_information_.dwProcessId;
+  }
+
+  // Returns the held thread id, if any.
+  DWORD thread_id() const {
+    return process_information_.dwThreadId;
+  }
+
+ private:
+  // Resets the held PROCESS_INFORMATION to null.
+  void Reset();
+
+  PROCESS_INFORMATION process_information_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedProcessInformation);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
diff --git a/base/win/scoped_process_information_unittest.cc b/base/win/scoped_process_information_unittest.cc
new file mode 100644
index 0000000..906c156
--- /dev/null
+++ b/base/win/scoped_process_information_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 <windows.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/process_util.h"
+#include "base/test/multiprocess_test.h"
+#include "base/win/scoped_process_information.h"
+#include "testing/multiprocess_func_list.h"
+
+class ScopedProcessInformationTest : public base::MultiProcessTest {
+ protected:
+  void DoCreateProcess(const std::string& main_id,
+                       PROCESS_INFORMATION* process_handle);
+};
+
+MULTIPROCESS_TEST_MAIN(ReturnSeven) {
+  return 7;
+}
+
+MULTIPROCESS_TEST_MAIN(ReturnNine) {
+  return 9;
+}
+
+void ScopedProcessInformationTest::DoCreateProcess(
+    const std::string& main_id, PROCESS_INFORMATION* process_handle) {
+  std::wstring cmd_line =
+      this->MakeCmdLine(main_id, false).GetCommandLineString();
+  STARTUPINFO startup_info = {};
+  startup_info.cb = sizeof(startup_info);
+
+  EXPECT_TRUE(::CreateProcess(NULL,
+                              const_cast<wchar_t*>(cmd_line.c_str()),
+                              NULL, NULL, false, 0, NULL, NULL,
+                              &startup_info, process_handle));
+}
+
+TEST_F(ScopedProcessInformationTest, TakeProcess) {
+  base::win::ScopedProcessInformation process_info;
+  DoCreateProcess("ReturnSeven", process_info.Receive());
+  int exit_code = 0;
+  ASSERT_TRUE(base::WaitForExitCode(process_info.TakeProcessHandle(),
+                                    &exit_code));
+  ASSERT_EQ(7, exit_code);
+  ASSERT_TRUE(process_info.IsValid());
+  ASSERT_EQ(0u, process_info.process_id());
+  ASSERT_TRUE(process_info.process_handle() == NULL);
+  ASSERT_NE(0u, process_info.thread_id());
+  ASSERT_FALSE(process_info.thread_handle() == NULL);
+}
+
+TEST_F(ScopedProcessInformationTest, TakeThread) {
+  base::win::ScopedProcessInformation process_info;
+  DoCreateProcess("ReturnSeven", process_info.Receive());
+  ASSERT_TRUE(::CloseHandle(process_info.TakeThreadHandle()));
+  ASSERT_TRUE(process_info.IsValid());
+  ASSERT_NE(0u, process_info.process_id());
+  ASSERT_FALSE(process_info.process_handle() == NULL);
+  ASSERT_EQ(0u, process_info.thread_id());
+  ASSERT_TRUE(process_info.thread_handle() == NULL);
+}
+
+TEST_F(ScopedProcessInformationTest, TakeBoth) {
+  base::win::ScopedProcessInformation process_info;
+  DoCreateProcess("ReturnSeven", process_info.Receive());
+  int exit_code = 0;
+  ASSERT_TRUE(base::WaitForExitCode(process_info.TakeProcessHandle(),
+                                    &exit_code));
+  ASSERT_EQ(7, exit_code);
+  ASSERT_TRUE(::CloseHandle(process_info.TakeThreadHandle()));
+  ASSERT_FALSE(process_info.IsValid());
+  ASSERT_EQ(0u, process_info.process_id());
+  ASSERT_TRUE(process_info.process_handle() == NULL);
+  ASSERT_EQ(0u, process_info.thread_id());
+  ASSERT_TRUE(process_info.thread_handle() == NULL);
+}
+
+TEST_F(ScopedProcessInformationTest, TakeNothing) {
+  base::win::ScopedProcessInformation process_info;
+  DoCreateProcess("ReturnSeven", process_info.Receive());
+  ASSERT_TRUE(process_info.IsValid());
+  ASSERT_NE(0u, process_info.thread_id());
+  ASSERT_FALSE(process_info.thread_handle() == NULL);
+  ASSERT_NE(0u, process_info.process_id());
+  ASSERT_FALSE(process_info.process_handle() == NULL);
+}
+
+TEST_F(ScopedProcessInformationTest, TakeWholeStruct) {
+  base::win::ScopedProcessInformation process_info;
+  DoCreateProcess("ReturnSeven", process_info.Receive());
+  base::win::ScopedProcessInformation other;
+  *other.Receive() = process_info.Take();
+
+  ASSERT_FALSE(process_info.IsValid());
+  ASSERT_EQ(0u, process_info.process_id());
+  ASSERT_TRUE(process_info.process_handle() == NULL);
+  ASSERT_EQ(0u, process_info.thread_id());
+  ASSERT_TRUE(process_info.thread_handle() == NULL);
+
+  // Validate that what was taken is good.
+  ASSERT_NE(0u, other.thread_id());
+  ASSERT_NE(0u, other.process_id());
+  int exit_code = 0;
+  ASSERT_TRUE(base::WaitForExitCode(other.TakeProcessHandle(),
+                                    &exit_code));
+  ASSERT_EQ(7, exit_code);
+  ASSERT_TRUE(::CloseHandle(other.TakeThreadHandle()));
+}
+
+TEST_F(ScopedProcessInformationTest, Duplicate) {
+  base::win::ScopedProcessInformation process_info;
+  DoCreateProcess("ReturnSeven", process_info.Receive());
+  base::win::ScopedProcessInformation duplicate;
+  duplicate.DuplicateFrom(process_info);
+
+  ASSERT_TRUE(process_info.IsValid());
+  ASSERT_NE(0u, process_info.process_id());
+  ASSERT_EQ(duplicate.process_id(), process_info.process_id());
+  ASSERT_NE(0u, process_info.thread_id());
+  ASSERT_EQ(duplicate.thread_id(), process_info.thread_id());
+
+  // Validate that we have separate handles that are good.
+  int exit_code = 0;
+  ASSERT_TRUE(base::WaitForExitCode(process_info.TakeProcessHandle(),
+                                    &exit_code));
+  ASSERT_EQ(7, exit_code);
+
+  exit_code = 0;
+  ASSERT_TRUE(base::WaitForExitCode(duplicate.TakeProcessHandle(),
+                                    &exit_code));
+  ASSERT_EQ(7, exit_code);
+
+  ASSERT_TRUE(::CloseHandle(process_info.TakeThreadHandle()));
+  ASSERT_TRUE(::CloseHandle(duplicate.TakeThreadHandle()));
+}
+
+TEST_F(ScopedProcessInformationTest, Swap) {
+  base::win::ScopedProcessInformation seven_to_nine_info;
+  DoCreateProcess("ReturnSeven", seven_to_nine_info.Receive());
+  base::win::ScopedProcessInformation nine_to_seven_info;
+  DoCreateProcess("ReturnNine", nine_to_seven_info.Receive());
+
+  HANDLE seven_process = seven_to_nine_info.process_handle();
+  DWORD seven_process_id = seven_to_nine_info.process_id();
+  HANDLE seven_thread = seven_to_nine_info.thread_handle();
+  DWORD seven_thread_id = seven_to_nine_info.thread_id();
+  HANDLE nine_process = nine_to_seven_info.process_handle();
+  DWORD nine_process_id = nine_to_seven_info.process_id();
+  HANDLE nine_thread = nine_to_seven_info.thread_handle();
+  DWORD nine_thread_id = nine_to_seven_info.thread_id();
+
+  seven_to_nine_info.Swap(&nine_to_seven_info);
+
+  ASSERT_EQ(seven_process, nine_to_seven_info.process_handle());
+  ASSERT_EQ(seven_process_id, nine_to_seven_info.process_id());
+  ASSERT_EQ(seven_thread, nine_to_seven_info.thread_handle());
+  ASSERT_EQ(seven_thread_id, nine_to_seven_info.thread_id());
+  ASSERT_EQ(nine_process, seven_to_nine_info.process_handle());
+  ASSERT_EQ(nine_process_id, seven_to_nine_info.process_id());
+  ASSERT_EQ(nine_thread, seven_to_nine_info.thread_handle());
+  ASSERT_EQ(nine_thread_id, seven_to_nine_info.thread_id());
+
+  int exit_code = 0;
+  ASSERT_TRUE(base::WaitForExitCode(seven_to_nine_info.TakeProcessHandle(),
+                                    &exit_code));
+  ASSERT_EQ(9, exit_code);
+
+  ASSERT_TRUE(base::WaitForExitCode(nine_to_seven_info.TakeProcessHandle(),
+                                    &exit_code));
+  ASSERT_EQ(7, exit_code);
+
+}
+
+TEST_F(ScopedProcessInformationTest, InitiallyInvalid) {
+  base::win::ScopedProcessInformation process_info;
+  ASSERT_FALSE(process_info.IsValid());
+}
diff --git a/base/win/scoped_select_object.h b/base/win/scoped_select_object.h
new file mode 100644
index 0000000..347de79
--- /dev/null
+++ b/base/win/scoped_select_object.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_SELECT_OBJECT_H_
+#define BASE_WIN_SCOPED_SELECT_OBJECT_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Helper class for deselecting object from DC.
+class ScopedSelectObject {
+ public:
+  ScopedSelectObject(HDC hdc, HGDIOBJ object)
+      : hdc_(hdc),
+        oldobj_(SelectObject(hdc, object)) {
+    DCHECK(hdc_);
+    DCHECK(object);
+    DCHECK(oldobj_ != NULL && oldobj_ != HGDI_ERROR);
+  }
+
+  ~ScopedSelectObject() {
+    HGDIOBJ object = SelectObject(hdc_, oldobj_);
+    DCHECK((GetObjectType(oldobj_) != OBJ_REGION && object != NULL) ||
+           (GetObjectType(oldobj_) == OBJ_REGION && object != HGDI_ERROR));
+  }
+
+ private:
+  HDC hdc_;
+  HGDIOBJ oldobj_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSelectObject);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_SELECT_OBJECT_H_
diff --git a/base/win/scoped_variant.cc b/base/win/scoped_variant.cc
new file mode 100644
index 0000000..f57ab93
--- /dev/null
+++ b/base/win/scoped_variant.cc
@@ -0,0 +1,276 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_variant.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Global, const instance of an empty variant.
+const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY };
+
+ScopedVariant::~ScopedVariant() {
+  COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize);
+  ::VariantClear(&var_);
+}
+
+ScopedVariant::ScopedVariant(const wchar_t* str) {
+  var_.vt = VT_EMPTY;
+  Set(str);
+}
+
+ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) {
+  var_.vt = VT_BSTR;
+  var_.bstrVal = ::SysAllocStringLen(str, length);
+}
+
+ScopedVariant::ScopedVariant(int value, VARTYPE vt) {
+  var_.vt = vt;
+  var_.lVal = value;
+}
+
+ScopedVariant::ScopedVariant(double value, VARTYPE vt) {
+  DCHECK(vt == VT_R8 || vt == VT_DATE);
+  var_.vt = vt;
+  var_.dblVal = value;
+}
+
+ScopedVariant::ScopedVariant(IDispatch* dispatch) {
+  var_.vt = VT_EMPTY;
+  Set(dispatch);
+}
+
+ScopedVariant::ScopedVariant(IUnknown* unknown) {
+  var_.vt = VT_EMPTY;
+  Set(unknown);
+}
+
+ScopedVariant::ScopedVariant(SAFEARRAY* safearray) {
+  var_.vt = VT_EMPTY;
+  Set(safearray);
+}
+
+ScopedVariant::ScopedVariant(const VARIANT& var) {
+  var_.vt = VT_EMPTY;
+  Set(var);
+}
+
+void ScopedVariant::Reset(const VARIANT& var) {
+  if (&var != &var_) {
+    ::VariantClear(&var_);
+    var_ = var;
+  }
+}
+
+VARIANT ScopedVariant::Release() {
+  VARIANT var = var_;
+  var_.vt = VT_EMPTY;
+  return var;
+}
+
+void ScopedVariant::Swap(ScopedVariant& var) {
+  VARIANT tmp = var_;
+  var_ = var.var_;
+  var.var_ = tmp;
+}
+
+VARIANT* ScopedVariant::Receive() {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt;
+  return &var_;
+}
+
+VARIANT ScopedVariant::Copy() const {
+  VARIANT ret = { VT_EMPTY };
+  ::VariantCopy(&ret, &var_);
+  return ret;
+}
+
+int ScopedVariant::Compare(const VARIANT& var, bool ignore_case) const {
+  ULONG flags = ignore_case ? NORM_IGNORECASE : 0;
+  HRESULT hr = ::VarCmp(const_cast<VARIANT*>(&var_), const_cast<VARIANT*>(&var),
+                        LOCALE_USER_DEFAULT, flags);
+  int ret = 0;
+
+  switch (hr) {
+    case VARCMP_LT:
+      ret = -1;
+      break;
+
+    case VARCMP_GT:
+    case VARCMP_NULL:
+      ret = 1;
+      break;
+
+    default:
+      // Equal.
+      break;
+  }
+
+  return ret;
+}
+
+void ScopedVariant::Set(const wchar_t* str) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_BSTR;
+  var_.bstrVal = ::SysAllocString(str);
+}
+
+void ScopedVariant::Set(int8 i8) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I1;
+  var_.cVal = i8;
+}
+
+void ScopedVariant::Set(uint8 ui8) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI1;
+  var_.bVal = ui8;
+}
+
+void ScopedVariant::Set(int16 i16) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I2;
+  var_.iVal = i16;
+}
+
+void ScopedVariant::Set(uint16 ui16) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI2;
+  var_.uiVal = ui16;
+}
+
+void ScopedVariant::Set(int32 i32) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I4;
+  var_.lVal = i32;
+}
+
+void ScopedVariant::Set(uint32 ui32) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI4;
+  var_.ulVal = ui32;
+}
+
+void ScopedVariant::Set(int64 i64) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I8;
+  var_.llVal = i64;
+}
+
+void ScopedVariant::Set(uint64 ui64) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI8;
+  var_.ullVal = ui64;
+}
+
+void ScopedVariant::Set(float r32) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_R4;
+  var_.fltVal = r32;
+}
+
+void ScopedVariant::Set(double r64) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_R8;
+  var_.dblVal = r64;
+}
+
+void ScopedVariant::SetDate(DATE date) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_DATE;
+  var_.date = date;
+}
+
+void ScopedVariant::Set(IDispatch* disp) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_DISPATCH;
+  var_.pdispVal = disp;
+  if (disp)
+    disp->AddRef();
+}
+
+void ScopedVariant::Set(bool b) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_BOOL;
+  var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE;
+}
+
+void ScopedVariant::Set(IUnknown* unk) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UNKNOWN;
+  var_.punkVal = unk;
+  if (unk)
+    unk->AddRef();
+}
+
+void ScopedVariant::Set(SAFEARRAY* array) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) {
+    var_.vt |= VT_ARRAY;
+    var_.parray = array;
+  } else {
+    DCHECK(!array) << "Unable to determine safearray vartype";
+    var_.vt = VT_EMPTY;
+  }
+}
+
+void ScopedVariant::Set(const VARIANT& var) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  if (FAILED(::VariantCopy(&var_, &var))) {
+    DLOG(ERROR) << "VariantCopy failed";
+    var_.vt = VT_EMPTY;
+  }
+}
+
+ScopedVariant& ScopedVariant::operator=(const VARIANT& var) {
+  if (&var != &var_) {
+    VariantClear(&var_);
+    Set(var);
+  }
+  return *this;
+}
+
+bool ScopedVariant::IsLeakableVarType(VARTYPE vt) {
+  bool leakable = false;
+  switch (vt & VT_TYPEMASK) {
+    case VT_BSTR:
+    case VT_DISPATCH:
+    // we treat VT_VARIANT as leakable to err on the safe side.
+    case VT_VARIANT:
+    case VT_UNKNOWN:
+    case VT_SAFEARRAY:
+
+    // very rarely used stuff (if ever):
+    case VT_VOID:
+    case VT_PTR:
+    case VT_CARRAY:
+    case VT_USERDEFINED:
+    case VT_LPSTR:
+    case VT_LPWSTR:
+    case VT_RECORD:
+    case VT_INT_PTR:
+    case VT_UINT_PTR:
+    case VT_FILETIME:
+    case VT_BLOB:
+    case VT_STREAM:
+    case VT_STORAGE:
+    case VT_STREAMED_OBJECT:
+    case VT_STORED_OBJECT:
+    case VT_BLOB_OBJECT:
+    case VT_VERSIONED_STREAM:
+    case VT_BSTR_BLOB:
+      leakable = true;
+      break;
+  }
+
+  if (!leakable && (vt & VT_ARRAY) != 0) {
+    leakable = true;
+  }
+
+  return leakable;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_variant.h b/base/win/scoped_variant.h
new file mode 100644
index 0000000..b6e6579
--- /dev/null
+++ b/base/win/scoped_variant.h
@@ -0,0 +1,166 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_VARIANT_H_
+#define BASE_WIN_SCOPED_VARIANT_H_
+
+#include <windows.h>
+#include <oleauto.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Scoped VARIANT class for automatically freeing a COM VARIANT at the
+// end of a scope.  Additionally provides a few functions to make the
+// encapsulated VARIANT easier to use.
+// Instead of inheriting from VARIANT, we take the containment approach
+// in order to have more control over the usage of the variant and guard
+// against memory leaks.
+class BASE_EXPORT ScopedVariant {
+ public:
+  // Declaration of a global variant variable that's always VT_EMPTY
+  static const VARIANT kEmptyVariant;
+
+  // Default constructor.
+  ScopedVariant() {
+    // This is equivalent to what VariantInit does, but less code.
+    var_.vt = VT_EMPTY;
+  }
+
+  // Constructor to create a new VT_BSTR VARIANT.
+  // NOTE: Do not pass a BSTR to this constructor expecting ownership to
+  // be transferred
+  explicit ScopedVariant(const wchar_t* str);
+
+  // Creates a new VT_BSTR variant of a specified length.
+  ScopedVariant(const wchar_t* str, UINT length);
+
+  // Creates a new integral type variant and assigns the value to
+  // VARIANT.lVal (32 bit sized field).
+  explicit ScopedVariant(int value, VARTYPE vt = VT_I4);
+
+  // Creates a new double-precision type variant.  |vt| must be either VT_R8
+  // or VT_DATE.
+  explicit ScopedVariant(double value, VARTYPE vt = VT_R8);
+
+  // VT_DISPATCH
+  explicit ScopedVariant(IDispatch* dispatch);
+
+  // VT_UNKNOWN
+  explicit ScopedVariant(IUnknown* unknown);
+
+  // SAFEARRAY
+  explicit ScopedVariant(SAFEARRAY* safearray);
+
+  // Copies the variant.
+  explicit ScopedVariant(const VARIANT& var);
+
+  ~ScopedVariant();
+
+  inline VARTYPE type() const {
+    return var_.vt;
+  }
+
+  // Give ScopedVariant ownership over an already allocated VARIANT.
+  void Reset(const VARIANT& var = kEmptyVariant);
+
+  // Releases ownership of the VARIANT to the caller.
+  VARIANT Release();
+
+  // Swap two ScopedVariant's.
+  void Swap(ScopedVariant& var);
+
+  // Returns a copy of the variant.
+  VARIANT Copy() const;
+
+  // The return value is 0 if the variants are equal, 1 if this object is
+  // greater than |var|, -1 if it is smaller.
+  int Compare(const VARIANT& var, bool ignore_case = false) const;
+
+  // Retrieves the pointer address.
+  // Used to receive a VARIANT as an out argument (and take ownership).
+  // The function DCHECKs on the current value being empty/null.
+  // Usage: GetVariant(var.receive());
+  VARIANT* Receive();
+
+  void Set(const wchar_t* str);
+
+  // Setters for simple types.
+  void Set(int8 i8);
+  void Set(uint8 ui8);
+  void Set(int16 i16);
+  void Set(uint16 ui16);
+  void Set(int32 i32);
+  void Set(uint32 ui32);
+  void Set(int64 i64);
+  void Set(uint64 ui64);
+  void Set(float r32);
+  void Set(double r64);
+  void Set(bool b);
+
+  // Creates a copy of |var| and assigns as this instance's value.
+  // Note that this is different from the Reset() method that's used to
+  // free the current value and assume ownership.
+  void Set(const VARIANT& var);
+
+  // COM object setters
+  void Set(IDispatch* disp);
+  void Set(IUnknown* unk);
+
+  // SAFEARRAY support
+  void Set(SAFEARRAY* array);
+
+  // Special setter for DATE since DATE is a double and we already have
+  // a setter for double.
+  void SetDate(DATE date);
+
+  // Allows const access to the contained variant without DCHECKs etc.
+  // This support is necessary for the V_XYZ (e.g. V_BSTR) set of macros to
+  // work properly but still doesn't allow modifications since we want control
+  // over that.
+  const VARIANT* operator&() const {
+    return &var_;
+  }
+
+  // Like other scoped classes (e.g scoped_refptr, ScopedComPtr, ScopedBstr)
+  // we support the assignment operator for the type we wrap.
+  ScopedVariant& operator=(const VARIANT& var);
+
+  // A hack to pass a pointer to the variant where the accepting
+  // function treats the variant as an input-only, read-only value
+  // but the function prototype requires a non const variant pointer.
+  // There's no DCHECK or anything here.  Callers must know what they're doing.
+  VARIANT* AsInput() const {
+    // The nature of this function is const, so we declare
+    // it as such and cast away the constness here.
+    return const_cast<VARIANT*>(&var_);
+  }
+
+  // Allows the ScopedVariant instance to be passed to functions either by value
+  // or by const reference.
+  operator const VARIANT&() const {
+    return var_;
+  }
+
+  // Used as a debug check to see if we're leaking anything.
+  static bool IsLeakableVarType(VARTYPE vt);
+
+ protected:
+  VARIANT var_;
+
+ private:
+  // Comparison operators for ScopedVariant are not supported at this point.
+  // Use the Compare method instead.
+  bool operator==(const ScopedVariant& var) const;
+  bool operator!=(const ScopedVariant& var) const;
+  DISALLOW_COPY_AND_ASSIGN(ScopedVariant);
+};
+
+}  // namespace win
+}  // namesoace base
+
+#endif  // BASE_WIN_SCOPED_VARIANT_H_
diff --git a/base/win/scoped_variant_unittest.cc b/base/win/scoped_variant_unittest.cc
new file mode 100644
index 0000000..1f017cf
--- /dev/null
+++ b/base/win/scoped_variant_unittest.cc
@@ -0,0 +1,261 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_variant.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const wchar_t kTestString1[] = L"Used to create BSTRs";
+static const wchar_t kTestString2[] = L"Also used to create BSTRs";
+
+void GiveMeAVariant(VARIANT* ret) {
+  EXPECT_TRUE(ret != NULL);
+  ret->vt = VT_BSTR;
+  V_BSTR(ret) = ::SysAllocString(kTestString1);
+}
+
+// A dummy IDispatch implementation (if you can call it that).
+// The class does nothing intelligent really.  Only increments a counter
+// when AddRef is called and decrements it when Release is called.
+class FakeComObject : public IDispatch {
+ public:
+  FakeComObject() : ref_(0) {
+  }
+
+  STDMETHOD_(DWORD, AddRef)() {
+    ref_++;
+    return ref_;
+  }
+
+  STDMETHOD_(DWORD, Release)() {
+    ref_--;
+    return ref_;
+  }
+
+  STDMETHOD(QueryInterface)(REFIID, void**) {
+    return E_NOTIMPL;
+  }
+
+  STDMETHOD(GetTypeInfoCount)(UINT*) {
+    return E_NOTIMPL;
+  }
+
+  STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) {
+    return E_NOTIMPL;
+  }
+
+  STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) {
+    return E_NOTIMPL;
+  }
+
+  STDMETHOD(Invoke)(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*,
+                    EXCEPINFO*, UINT*) {
+    return E_NOTIMPL;
+  }
+
+  // A way to check the internal reference count of the class.
+  int ref_count() const {
+    return ref_;
+  }
+
+ protected:
+  int ref_;
+};
+
+}  // namespace
+
+TEST(ScopedVariantTest, ScopedVariant) {
+  ScopedVariant var;
+  EXPECT_TRUE(var.type() == VT_EMPTY);
+  // V_BSTR(&var) = NULL;  <- NOTE: Assignment like that is not supported
+
+  ScopedVariant var_bstr(L"VT_BSTR");
+  EXPECT_EQ(VT_BSTR, V_VT(&var_bstr));
+  EXPECT_TRUE(V_BSTR(&var_bstr) != NULL);  // can't use EXPECT_NE for BSTR
+  var_bstr.Reset();
+  EXPECT_NE(VT_BSTR, V_VT(&var_bstr));
+  var_bstr.Set(kTestString2);
+  EXPECT_EQ(VT_BSTR, V_VT(&var_bstr));
+
+  VARIANT tmp = var_bstr.Release();
+  EXPECT_EQ(VT_EMPTY, V_VT(&var_bstr));
+  EXPECT_EQ(VT_BSTR, V_VT(&tmp));
+  EXPECT_EQ(0, lstrcmp(V_BSTR(&tmp), kTestString2));
+
+  var.Reset(tmp);
+  EXPECT_EQ(VT_BSTR, V_VT(&var));
+  EXPECT_EQ(0, lstrcmpW(V_BSTR(&var), kTestString2));
+
+  var_bstr.Swap(var);
+  EXPECT_EQ(VT_EMPTY, V_VT(&var));
+  EXPECT_EQ(VT_BSTR, V_VT(&var_bstr));
+  EXPECT_EQ(0, lstrcmpW(V_BSTR(&var_bstr), kTestString2));
+  var_bstr.Reset();
+
+  // Test the Compare and Copy routines.
+  GiveMeAVariant(var_bstr.Receive());
+  ScopedVariant var_bstr2(V_BSTR(&var_bstr));
+  EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset();
+  EXPECT_NE(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset(var_bstr.Copy());
+  EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset();
+  var_bstr2.Set(V_BSTR(&var_bstr));
+  EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset();
+  var_bstr.Reset();
+
+  // Test for the SetDate setter.
+  SYSTEMTIME sys_time;
+  ::GetSystemTime(&sys_time);
+  DATE date;
+  ::SystemTimeToVariantTime(&sys_time, &date);
+  var.Reset();
+  var.SetDate(date);
+  EXPECT_EQ(VT_DATE, var.type());
+  EXPECT_EQ(date, V_DATE(&var));
+
+  // Simple setter tests.  These do not require resetting the variant
+  // after each test since the variant type is not "leakable" (i.e. doesn't
+  // need to be freed explicitly).
+
+  // We need static cast here since char defaults to int (!?).
+  var.Set(static_cast<int8>('v'));
+  EXPECT_EQ(VT_I1, var.type());
+  EXPECT_EQ('v', V_I1(&var));
+
+  var.Set(static_cast<short>(123));
+  EXPECT_EQ(VT_I2, var.type());
+  EXPECT_EQ(123, V_I2(&var));
+
+  var.Set(static_cast<int32>(123));
+  EXPECT_EQ(VT_I4, var.type());
+  EXPECT_EQ(123, V_I4(&var));
+
+  var.Set(static_cast<int64>(123));
+  EXPECT_EQ(VT_I8, var.type());
+  EXPECT_EQ(123, V_I8(&var));
+
+  var.Set(static_cast<uint8>(123));
+  EXPECT_EQ(VT_UI1, var.type());
+  EXPECT_EQ(123, V_UI1(&var));
+
+  var.Set(static_cast<unsigned short>(123));
+  EXPECT_EQ(VT_UI2, var.type());
+  EXPECT_EQ(123, V_UI2(&var));
+
+  var.Set(static_cast<uint32>(123));
+  EXPECT_EQ(VT_UI4, var.type());
+  EXPECT_EQ(123, V_UI4(&var));
+
+  var.Set(static_cast<uint64>(123));
+  EXPECT_EQ(VT_UI8, var.type());
+  EXPECT_EQ(123, V_UI8(&var));
+
+  var.Set(123.123f);
+  EXPECT_EQ(VT_R4, var.type());
+  EXPECT_EQ(123.123f, V_R4(&var));
+
+  var.Set(static_cast<double>(123.123));
+  EXPECT_EQ(VT_R8, var.type());
+  EXPECT_EQ(123.123, V_R8(&var));
+
+  var.Set(true);
+  EXPECT_EQ(VT_BOOL, var.type());
+  EXPECT_EQ(VARIANT_TRUE, V_BOOL(&var));
+  var.Set(false);
+  EXPECT_EQ(VT_BOOL, var.type());
+  EXPECT_EQ(VARIANT_FALSE, V_BOOL(&var));
+
+  // Com interface tests
+
+  var.Set(static_cast<IDispatch*>(NULL));
+  EXPECT_EQ(VT_DISPATCH, var.type());
+  EXPECT_EQ(NULL, V_DISPATCH(&var));
+  var.Reset();
+
+  var.Set(static_cast<IUnknown*>(NULL));
+  EXPECT_EQ(VT_UNKNOWN, var.type());
+  EXPECT_EQ(NULL, V_UNKNOWN(&var));
+  var.Reset();
+
+  FakeComObject faker;
+  EXPECT_EQ(0, faker.ref_count());
+  var.Set(static_cast<IDispatch*>(&faker));
+  EXPECT_EQ(VT_DISPATCH, var.type());
+  EXPECT_EQ(&faker, V_DISPATCH(&var));
+  EXPECT_EQ(1, faker.ref_count());
+  var.Reset();
+  EXPECT_EQ(0, faker.ref_count());
+
+  var.Set(static_cast<IUnknown*>(&faker));
+  EXPECT_EQ(VT_UNKNOWN, var.type());
+  EXPECT_EQ(&faker, V_UNKNOWN(&var));
+  EXPECT_EQ(1, faker.ref_count());
+  var.Reset();
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant disp_var(&faker);
+    EXPECT_EQ(VT_DISPATCH, disp_var.type());
+    EXPECT_EQ(&faker, V_DISPATCH(&disp_var));
+    EXPECT_EQ(1, faker.ref_count());
+  }
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant ref1(&faker);
+    EXPECT_EQ(1, faker.ref_count());
+    ScopedVariant ref2(static_cast<const VARIANT&>(ref1));
+    EXPECT_EQ(2, faker.ref_count());
+    ScopedVariant ref3;
+    ref3 = static_cast<const VARIANT&>(ref2);
+    EXPECT_EQ(3, faker.ref_count());
+  }
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant unk_var(static_cast<IUnknown*>(&faker));
+    EXPECT_EQ(VT_UNKNOWN, unk_var.type());
+    EXPECT_EQ(&faker, V_UNKNOWN(&unk_var));
+    EXPECT_EQ(1, faker.ref_count());
+  }
+  EXPECT_EQ(0, faker.ref_count());
+
+  VARIANT raw;
+  raw.vt = VT_UNKNOWN;
+  raw.punkVal = &faker;
+  EXPECT_EQ(0, faker.ref_count());
+  var.Set(raw);
+  EXPECT_EQ(1, faker.ref_count());
+  var.Reset();
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant number(123);
+    EXPECT_EQ(VT_I4, number.type());
+    EXPECT_EQ(123, V_I4(&number));
+  }
+
+  // SAFEARRAY tests
+  var.Set(static_cast<SAFEARRAY*>(NULL));
+  EXPECT_EQ(VT_EMPTY, var.type());
+
+  SAFEARRAY* sa = ::SafeArrayCreateVector(VT_UI1, 0, 100);
+  ASSERT_TRUE(sa != NULL);
+
+  var.Set(sa);
+  EXPECT_TRUE(ScopedVariant::IsLeakableVarType(var.type()));
+  EXPECT_EQ(VT_ARRAY | VT_UI1, var.type());
+  EXPECT_EQ(sa, V_ARRAY(&var));
+  // The array is destroyed in the destructor of var.
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
new file mode 100644
index 0000000..8afd55d
--- /dev/null
+++ b/base/win/shortcut.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/shortcut.h"
+
+#include <shellapi.h>
+#include <shlobj.h>
+#include <propkey.h>
+
+#include "base/file_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Initializes |i_shell_link| and |i_persist_file| (releasing them first if they
+// are already initialized).
+// If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|.
+// If any of the above steps fail, both |i_shell_link| and |i_persist_file| will
+// be released.
+void InitializeShortcutInterfaces(
+    const wchar_t* shortcut,
+    ScopedComPtr<IShellLink>* i_shell_link,
+    ScopedComPtr<IPersistFile>* i_persist_file) {
+  i_shell_link->Release();
+  i_persist_file->Release();
+  if (FAILED(i_shell_link->CreateInstance(CLSID_ShellLink, NULL,
+                                          CLSCTX_INPROC_SERVER)) ||
+      FAILED(i_persist_file->QueryFrom(*i_shell_link)) ||
+      (shortcut && FAILED((*i_persist_file)->Load(shortcut, STGM_READWRITE)))) {
+    i_shell_link->Release();
+    i_persist_file->Release();
+  }
+}
+
+}  // namespace
+
+bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path,
+                                const ShortcutProperties& properties,
+                                ShortcutOperation operation) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // A target is required unless |operation| is SHORTCUT_UPDATE_EXISTING.
+  if (operation != SHORTCUT_UPDATE_EXISTING &&
+      !(properties.options & ShortcutProperties::PROPERTIES_TARGET)) {
+    NOTREACHED();
+    return false;
+  }
+
+  bool shortcut_existed = file_util::PathExists(shortcut_path);
+
+  ScopedComPtr<IShellLink> i_shell_link;
+  ScopedComPtr<IPersistFile> i_persist_file;
+  switch (operation) {
+    case SHORTCUT_CREATE_ALWAYS:
+      InitializeShortcutInterfaces(NULL, &i_shell_link, &i_persist_file);
+      break;
+    case SHORTCUT_UPDATE_EXISTING:
+      InitializeShortcutInterfaces(shortcut_path.value().c_str(), &i_shell_link,
+                                   &i_persist_file);
+      break;
+    case SHORTCUT_REPLACE_EXISTING:
+      InitializeShortcutInterfaces(shortcut_path.value().c_str(), &i_shell_link,
+                                   &i_persist_file);
+      // Confirm |shortcut_path| exists and is a shortcut by verifying
+      // |i_persist_file| was successfully initialized in the call above. If so,
+      // re-initialize the interfaces to begin writing a new shortcut (to
+      // overwrite the current one if successful).
+      if (i_persist_file.get())
+        InitializeShortcutInterfaces(NULL, &i_shell_link, &i_persist_file);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  // Return false immediately upon failure to initialize shortcut interfaces.
+  if (!i_persist_file.get())
+    return false;
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_TARGET) &&
+      FAILED(i_shell_link->SetPath(properties.target.value().c_str()))) {
+    return false;
+  }
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) &&
+      FAILED(i_shell_link->SetWorkingDirectory(
+          properties.working_dir.value().c_str()))) {
+    return false;
+  }
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) &&
+      FAILED(i_shell_link->SetArguments(properties.arguments.c_str()))) {
+    return false;
+  }
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) &&
+      FAILED(i_shell_link->SetDescription(properties.description.c_str()))) {
+    return false;
+  }
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_ICON) &&
+      FAILED(i_shell_link->SetIconLocation(properties.icon.value().c_str(),
+                                           properties.icon_index))) {
+    return false;
+  }
+
+  bool has_app_id =
+      (properties.options & ShortcutProperties::PROPERTIES_APP_ID) != 0;
+  bool has_dual_mode =
+      (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) != 0;
+  if ((has_app_id || has_dual_mode) &&
+      GetVersion() >= VERSION_WIN7) {
+    ScopedComPtr<IPropertyStore> property_store;
+    if (FAILED(property_store.QueryFrom(i_shell_link)) || !property_store.get())
+      return false;
+
+    if (has_app_id &&
+        !SetAppIdForPropertyStore(property_store, properties.app_id.c_str())) {
+      return false;
+    }
+    if (has_dual_mode &&
+        !SetBooleanValueForPropertyStore(property_store,
+                                         PKEY_AppUserModel_IsDualMode,
+                                         properties.dual_mode)) {
+      return false;
+    }
+  }
+
+  HRESULT result = i_persist_file->Save(shortcut_path.value().c_str(), TRUE);
+
+  // Release the interfaces in case the SHChangeNotify call below depends on
+  // the operations above being fully completed.
+  i_persist_file.Release();
+  i_shell_link.Release();
+
+  // If we successfully created/updated the icon, notify the shell that we have
+  // done so.
+  const bool succeeded = SUCCEEDED(result);
+  if (succeeded) {
+    if (shortcut_existed) {
+      // TODO(gab): SHCNE_UPDATEITEM might be sufficient here; further testing
+      // required.
+      SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+    } else {
+      SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, shortcut_path.value().c_str(),
+                     NULL);
+    }
+  }
+
+  return succeeded;
+}
+
+bool ResolveShortcut(const FilePath& shortcut_path,
+                     FilePath* target_path,
+                     string16* args) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  HRESULT result;
+  ScopedComPtr<IShellLink> i_shell_link;
+
+  // Get pointer to the IShellLink interface.
+  result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
+                                       CLSCTX_INPROC_SERVER);
+  if (FAILED(result))
+    return false;
+
+  ScopedComPtr<IPersistFile> persist;
+  // Query IShellLink for the IPersistFile interface.
+  result = persist.QueryFrom(i_shell_link);
+  if (FAILED(result))
+    return false;
+
+  // Load the shell link.
+  result = persist->Load(shortcut_path.value().c_str(), STGM_READ);
+  if (FAILED(result))
+    return false;
+
+  WCHAR temp[MAX_PATH];
+  if (target_path) {
+    // Try to find the target of a shortcut.
+    result = i_shell_link->Resolve(0, SLR_NO_UI);
+    if (FAILED(result))
+      return false;
+
+    result = i_shell_link->GetPath(temp, MAX_PATH, NULL, SLGP_UNCPRIORITY);
+    if (FAILED(result))
+      return false;
+
+    *target_path = FilePath(temp);
+  }
+
+  if (args) {
+    result = i_shell_link->GetArguments(temp, MAX_PATH);
+    if (FAILED(result))
+      return false;
+
+    *args = string16(temp);
+  }
+  return true;
+}
+
+bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // "Pin to taskbar" is only supported after Win7.
+  if (GetVersion() < VERSION_WIN7)
+    return false;
+
+  int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarpin", shortcut,
+      NULL, NULL, 0));
+  return result > 32;
+}
+
+bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // "Unpin from taskbar" is only supported after Win7.
+  if (base::win::GetVersion() < base::win::VERSION_WIN7)
+    return false;
+
+  int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarunpin",
+      shortcut, NULL, NULL, 0));
+  return result > 32;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/shortcut.h b/base/win/shortcut.h
new file mode 100644
index 0000000..c1e7d5c
--- /dev/null
+++ b/base/win/shortcut.h
@@ -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.
+
+#ifndef BASE_WIN_SHORTCUT_H_
+#define BASE_WIN_SHORTCUT_H_
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/file_path.h"
+#include "base/string16.h"
+
+namespace base {
+namespace win {
+
+enum ShortcutOperation {
+  // Create a new shortcut (overwriting if necessary).
+  SHORTCUT_CREATE_ALWAYS = 0,
+  // Overwrite an existing shortcut (fails if the shortcut doesn't exist).
+  SHORTCUT_REPLACE_EXISTING,
+  // Update specified properties only on an existing shortcut.
+  SHORTCUT_UPDATE_EXISTING,
+};
+
+// Properties for shortcuts. Properties set will be applied to the shortcut on
+// creation/update, others will be ignored.
+// Callers are encouraged to use the setters provided which take care of
+// setting |options| as desired.
+struct ShortcutProperties {
+  enum IndividualProperties {
+    PROPERTIES_TARGET = 1 << 0,
+    PROPERTIES_WORKING_DIR = 1 << 1,
+    PROPERTIES_ARGUMENTS = 1 << 2,
+    PROPERTIES_DESCRIPTION = 1 << 3,
+    PROPERTIES_ICON = 1 << 4,
+    PROPERTIES_APP_ID = 1 << 5,
+    PROPERTIES_DUAL_MODE = 1 << 6,
+  };
+
+  ShortcutProperties() : icon_index(-1), dual_mode(false), options(0U) {}
+
+  void set_target(const FilePath& target_in) {
+    target = target_in;
+    options |= PROPERTIES_TARGET;
+  }
+
+  void set_working_dir(const FilePath& working_dir_in) {
+    working_dir = working_dir_in;
+    options |= PROPERTIES_WORKING_DIR;
+  }
+
+  void set_arguments(const string16& arguments_in) {
+    // Size restriction as per MSDN at http://goo.gl/TJ7q5.
+    DCHECK(arguments_in.size() < MAX_PATH);
+    arguments = arguments_in;
+    options |= PROPERTIES_ARGUMENTS;
+  }
+
+  void set_description(const string16& description_in) {
+    // Size restriction as per MSDN at http://goo.gl/OdNQq.
+    DCHECK(description_in.size() < MAX_PATH);
+    description = description_in;
+    options |= PROPERTIES_DESCRIPTION;
+  }
+
+  void set_icon(const FilePath& icon_in, int icon_index_in) {
+    icon = icon_in;
+    icon_index = icon_index_in;
+    options |= PROPERTIES_ICON;
+  }
+
+  void set_app_id(const string16& app_id_in) {
+    app_id = app_id_in;
+    options |= PROPERTIES_APP_ID;
+  }
+
+  void set_dual_mode(bool dual_mode_in) {
+    dual_mode = dual_mode_in;
+    options |= PROPERTIES_DUAL_MODE;
+  }
+
+  // The target to launch from this shortcut. This is mandatory when creating
+  // a shortcut.
+  FilePath target;
+  // The name of the working directory when launching the shortcut.
+  FilePath working_dir;
+  // The arguments to be applied to |target| when launching from this shortcut.
+  // The length of this string must be less than MAX_PATH.
+  string16 arguments;
+  // The localized description of the shortcut.
+  // The length of this string must be less than MAX_PATH.
+  string16 description;
+  // The path to the icon (can be a dll or exe, in which case |icon_index| is
+  // the resource id).
+  FilePath icon;
+  int icon_index;
+  // The app model id for the shortcut (Win7+).
+  string16 app_id;
+  // Whether this is a dual mode shortcut (Win8+).
+  bool dual_mode;
+  // Bitfield made of IndividualProperties. Properties set in |options| will be
+  // set on the shortcut, others will be ignored.
+  uint32 options;
+};
+
+// This method creates (or updates) a shortcut link at |shortcut_path| using the
+// information given through |properties|.
+// Ensure you have initialized COM before calling into this function.
+// |operation|: a choice from the ShortcutOperation enum.
+// If |operation| is SHORTCUT_REPLACE_EXISTING or SHORTCUT_UPDATE_EXISTING and
+// |shortcut_path| does not exist, this method is a no-op and returns false.
+BASE_EXPORT bool CreateOrUpdateShortcutLink(
+    const FilePath& shortcut_path,
+    const ShortcutProperties& properties,
+    ShortcutOperation operation);
+
+// Resolve Windows shortcut (.LNK file)
+// This methods tries to resolve a shortcut .LNK file. The path of the shortcut
+// to resolve is in |shortcut_path|. If |target_path| is not NULL, the target
+// will be resolved and placed in |target_path|. If |args| is not NULL, the
+// arguments will be retrieved and placed in |args|. The function returns true
+// if all requested fields are found successfully.
+// Callers can safely use the same variable for both |shortcut_path| and
+// |target_path|.
+BASE_EXPORT bool ResolveShortcut(const FilePath& shortcut_path,
+                                 FilePath* target_path,
+                                 string16* args);
+
+// Pins a shortcut to the Windows 7 taskbar. The shortcut file must already
+// exist and be a shortcut that points to an executable.
+BASE_EXPORT bool TaskbarPinShortcutLink(const wchar_t* shortcut);
+
+// Unpins a shortcut from the Windows 7 taskbar. The shortcut must exist and
+// already be pinned to the taskbar.
+BASE_EXPORT bool TaskbarUnpinShortcutLink(const wchar_t* shortcut);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SHORTCUT_H_
diff --git a/base/win/shortcut_unittest.cc b/base/win/shortcut_unittest.cc
new file mode 100644
index 0000000..e13bc28
--- /dev/null
+++ b/base/win/shortcut_unittest.cc
@@ -0,0 +1,250 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/shortcut.h"
+
+#include <string>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/scoped_temp_dir.h"
+#include "base/test/test_file_util.h"
+#include "base/test/test_shortcut_win.h"
+#include "base/win/scoped_com_initializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+static const char kFileContents[] = "This is a target.";
+static const char kFileContents2[] = "This is another target.";
+
+class ShortcutTest : public testing::Test {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(temp_dir_2_.CreateUniqueTempDir());
+
+    link_file_ = temp_dir_.path().Append(L"My Link.lnk");
+
+    // Shortcut 1's properties
+    {
+      const FilePath target_file(temp_dir_.path().Append(L"Target 1.txt"));
+      file_util::WriteFile(target_file, kFileContents,
+                           arraysize(kFileContents));
+
+      link_properties_.set_target(target_file);
+      link_properties_.set_working_dir(temp_dir_.path());
+      link_properties_.set_arguments(L"--magic --awesome");
+      link_properties_.set_description(L"Chrome is awesome.");
+      link_properties_.set_icon(link_properties_.target, 4);
+      link_properties_.set_app_id(L"Chrome");
+      link_properties_.set_dual_mode(false);
+    }
+
+    // Shortcut 2's properties (all different from properties of shortcut 1).
+    {
+      const FilePath target_file_2(temp_dir_.path().Append(L"Target 2.txt"));
+      file_util::WriteFile(target_file_2, kFileContents2,
+                           arraysize(kFileContents2));
+
+      FilePath icon_path_2;
+      file_util::CreateTemporaryFileInDir(temp_dir_.path(), &icon_path_2);
+
+      link_properties_2_.set_target(target_file_2);
+      link_properties_2_.set_working_dir(temp_dir_2_.path());
+      link_properties_2_.set_arguments(L"--super --crazy");
+      link_properties_2_.set_description(L"The best in the west.");
+      link_properties_2_.set_icon(icon_path_2, 0);
+      link_properties_2_.set_app_id(L"Chrome.UserLevelCrazySuffix");
+      link_properties_2_.set_dual_mode(true);
+    }
+  }
+
+  base::win::ScopedCOMInitializer com_initializer_;
+  ScopedTempDir temp_dir_;
+  ScopedTempDir temp_dir_2_;
+
+  // The link file to be created/updated in the shortcut tests below.
+  FilePath link_file_;
+
+  // Properties for the created shortcut.
+  base::win::ShortcutProperties link_properties_;
+
+  // Properties for the updated shortcut.
+  base::win::ShortcutProperties link_properties_2_;
+};
+
+}  // namespace
+
+TEST_F(ShortcutTest, CreateAndResolveShortcut) {
+  base::win::ShortcutProperties only_target_properties;
+  only_target_properties.set_target(link_properties_.target);
+
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, only_target_properties, base::win::SHORTCUT_CREATE_ALWAYS));
+
+  FilePath resolved_name;
+  EXPECT_TRUE(base::win::ResolveShortcut(link_file_, &resolved_name, NULL));
+
+  char read_contents[arraysize(kFileContents)];
+  file_util::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+  EXPECT_STREQ(kFileContents, read_contents);
+}
+
+TEST_F(ShortcutTest, ResolveShortcutWithArgs) {
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+  FilePath resolved_name;
+  string16 args;
+  EXPECT_TRUE(base::win::ResolveShortcut(link_file_, &resolved_name, &args));
+
+  char read_contents[arraysize(kFileContents)];
+  file_util::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+  EXPECT_STREQ(kFileContents, read_contents);
+  EXPECT_EQ(link_properties_.arguments, args);
+}
+
+TEST_F(ShortcutTest, CreateShortcutWithOnlySomeProperties) {
+  base::win::ShortcutProperties target_and_args_properties;
+  target_and_args_properties.set_target(link_properties_.target);
+  target_and_args_properties.set_arguments(link_properties_.arguments);
+
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, target_and_args_properties,
+      base::win::SHORTCUT_CREATE_ALWAYS));
+
+  base::win::ValidateShortcut(link_file_, target_and_args_properties);
+}
+
+TEST_F(ShortcutTest, CreateShortcutVerifyProperties) {
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+  base::win::ValidateShortcut(link_file_, link_properties_);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutVerifyProperties) {
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, base::win::SHORTCUT_UPDATE_EXISTING));
+
+  base::win::ValidateShortcut(link_file_, link_properties_2_);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutUpdateOnlyTargetAndResolve) {
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+  base::win::ShortcutProperties update_only_target_properties;
+  update_only_target_properties.set_target(link_properties_2_.target);
+
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, update_only_target_properties,
+      base::win::SHORTCUT_UPDATE_EXISTING));
+
+  base::win::ShortcutProperties expected_properties = link_properties_;
+  expected_properties.set_target(link_properties_2_.target);
+  base::win::ValidateShortcut(link_file_, expected_properties);
+
+  FilePath resolved_name;
+  EXPECT_TRUE(base::win::ResolveShortcut(link_file_, &resolved_name, NULL));
+
+  char read_contents[arraysize(kFileContents2)];
+  file_util::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+  EXPECT_STREQ(kFileContents2, read_contents);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutMakeDualMode) {
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+  base::win::ShortcutProperties make_dual_mode_properties;
+  make_dual_mode_properties.set_dual_mode(true);
+
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, make_dual_mode_properties,
+      base::win::SHORTCUT_UPDATE_EXISTING));
+
+  base::win::ShortcutProperties expected_properties = link_properties_;
+  expected_properties.set_dual_mode(true);
+  base::win::ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutRemoveDualMode) {
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+  base::win::ShortcutProperties remove_dual_mode_properties;
+  remove_dual_mode_properties.set_dual_mode(false);
+
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, remove_dual_mode_properties,
+      base::win::SHORTCUT_UPDATE_EXISTING));
+
+  base::win::ShortcutProperties expected_properties = link_properties_2_;
+  expected_properties.set_dual_mode(false);
+  base::win::ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutClearArguments) {
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+  base::win::ShortcutProperties clear_arguments_properties;
+  clear_arguments_properties.set_arguments(string16());
+
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, clear_arguments_properties,
+      base::win::SHORTCUT_UPDATE_EXISTING));
+
+  base::win::ShortcutProperties expected_properties = link_properties_;
+  expected_properties.set_arguments(string16());
+  base::win::ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, FailUpdateShortcutThatDoesNotExist) {
+  ASSERT_FALSE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, base::win::SHORTCUT_UPDATE_EXISTING));
+  ASSERT_FALSE(file_util::PathExists(link_file_));
+}
+
+TEST_F(ShortcutTest, TruncateShortcutAllProperties) {
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, base::win::SHORTCUT_REPLACE_EXISTING));
+
+  base::win::ValidateShortcut(link_file_, link_properties_2_);
+}
+
+TEST_F(ShortcutTest, TruncateShortcutSomeProperties) {
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+  base::win::ShortcutProperties new_properties;
+  new_properties.set_target(link_properties_2_.target);
+  new_properties.set_description(link_properties_2_.description);
+  ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, new_properties, base::win::SHORTCUT_REPLACE_EXISTING));
+
+  // Expect only properties in |new_properties| to be set, all other properties
+  // should have been overwritten.
+  base::win::ShortcutProperties expected_properties = new_properties;
+  expected_properties.set_working_dir(FilePath());
+  expected_properties.set_arguments(string16());
+  expected_properties.set_icon(FilePath(), 0);
+  expected_properties.set_app_id(string16());
+  expected_properties.set_dual_mode(false);
+  base::win::ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, FailTruncateShortcutThatDoesNotExist) {
+  ASSERT_FALSE(base::win::CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, base::win::SHORTCUT_REPLACE_EXISTING));
+  ASSERT_FALSE(file_util::PathExists(link_file_));
+}
diff --git a/base/win/startup_information.cc b/base/win/startup_information.cc
new file mode 100644
index 0000000..aff52eb
--- /dev/null
+++ b/base/win/startup_information.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/startup_information.h"
+
+#include "base/logging.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+typedef BOOL (WINAPI *InitializeProcThreadAttributeListFunction)(
+    LPPROC_THREAD_ATTRIBUTE_LIST attribute_list,
+    DWORD attribute_count,
+    DWORD flags,
+    PSIZE_T size);
+static InitializeProcThreadAttributeListFunction
+    initialize_proc_thread_attribute_list;
+
+typedef BOOL (WINAPI *UpdateProcThreadAttributeFunction)(
+    LPPROC_THREAD_ATTRIBUTE_LIST attribute_list,
+    DWORD flags,
+    DWORD_PTR attribute,
+    PVOID value,
+    SIZE_T size,
+    PVOID previous_value,
+    PSIZE_T return_size);
+static UpdateProcThreadAttributeFunction update_proc_thread_attribute_list;
+
+typedef VOID (WINAPI *DeleteProcThreadAttributeListFunction)(
+    LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList);
+static DeleteProcThreadAttributeListFunction delete_proc_thread_attribute_list;
+
+}  // namespace
+
+namespace base {
+namespace win {
+
+StartupInformation::StartupInformation() {
+  memset(&startup_info_, 0, sizeof(startup_info_));
+
+  // Pre Windows Vista doesn't support STARTUPINFOEX.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+    startup_info_.StartupInfo.cb = sizeof(STARTUPINFO);
+    return;
+  }
+
+  startup_info_.StartupInfo.cb = sizeof(startup_info_);
+
+  // Load the attribute API functions.
+  if (!initialize_proc_thread_attribute_list ||
+      !update_proc_thread_attribute_list ||
+      !delete_proc_thread_attribute_list) {
+    HMODULE module = ::GetModuleHandleW(L"kernel32.dll");
+    initialize_proc_thread_attribute_list =
+        reinterpret_cast<InitializeProcThreadAttributeListFunction>(
+            ::GetProcAddress(module, "InitializeProcThreadAttributeList"));
+    update_proc_thread_attribute_list =
+        reinterpret_cast<UpdateProcThreadAttributeFunction>(
+            ::GetProcAddress(module, "UpdateProcThreadAttribute"));
+    delete_proc_thread_attribute_list =
+        reinterpret_cast<DeleteProcThreadAttributeListFunction>(
+            ::GetProcAddress(module, "DeleteProcThreadAttributeList"));
+  }
+}
+
+StartupInformation::~StartupInformation() {
+  if (startup_info_.lpAttributeList) {
+    delete_proc_thread_attribute_list(startup_info_.lpAttributeList);
+    delete [] reinterpret_cast<BYTE*>(startup_info_.lpAttributeList);
+  }
+}
+
+bool StartupInformation::InitializeProcThreadAttributeList(
+    DWORD attribute_count) {
+  if (startup_info_.StartupInfo.cb != sizeof(startup_info_) ||
+      startup_info_.lpAttributeList)
+    return false;
+
+  SIZE_T size = 0;
+  initialize_proc_thread_attribute_list(NULL, attribute_count, 0, &size);
+  if (size == 0)
+    return false;
+
+  startup_info_.lpAttributeList =
+      reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(new BYTE[size]);
+  if (!initialize_proc_thread_attribute_list(startup_info_.lpAttributeList,
+                                           attribute_count, 0, &size)) {
+    delete [] reinterpret_cast<BYTE*>(startup_info_.lpAttributeList);
+    startup_info_.lpAttributeList = NULL;
+    return false;
+  }
+
+  return true;
+}
+
+bool StartupInformation::UpdateProcThreadAttribute(
+    DWORD_PTR attribute,
+    void* value,
+    size_t size) {
+  if (!startup_info_.lpAttributeList)
+    return false;
+  return !!update_proc_thread_attribute_list(startup_info_.lpAttributeList, 0,
+                                       attribute, value, size, NULL, NULL);
+}
+
+}  // namespace win
+}  // namespace base
+
diff --git a/base/win/startup_information.h b/base/win/startup_information.h
new file mode 100644
index 0000000..7cef81f
--- /dev/null
+++ b/base/win/startup_information.h
@@ -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.
+
+#ifndef BASE_WIN_STARTUP_INFORMATION_H_
+#define BASE_WIN_STARTUP_INFORMATION_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Manages the lifetime of additional attributes in STARTUPINFOEX.
+class BASE_EXPORT StartupInformation {
+ public:
+  StartupInformation();
+
+  ~StartupInformation();
+
+  // Initialize the attribute list for the specified number of entries.
+  bool InitializeProcThreadAttributeList(DWORD attribute_count);
+
+  // Sets one entry in the initialized attribute list.
+  bool UpdateProcThreadAttribute(DWORD_PTR attribute,
+                                 void* value,
+                                 size_t size);
+
+  LPSTARTUPINFOW startup_info() { return &startup_info_.StartupInfo; }
+  const LPSTARTUPINFOW startup_info() const {
+    return const_cast<const LPSTARTUPINFOW>(&startup_info_.StartupInfo);
+  }
+
+  bool has_extended_startup_info() const {
+    return !!startup_info_.lpAttributeList;
+  }
+
+ private:
+  STARTUPINFOEXW startup_info_;
+  DISALLOW_COPY_AND_ASSIGN(StartupInformation);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_STARTUP_INFO_EX_H_
+
diff --git a/base/win/startup_information_unittest.cc b/base/win/startup_information_unittest.cc
new file mode 100644
index 0000000..1903564
--- /dev/null
+++ b/base/win/startup_information_unittest.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/test/multiprocess_test.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/startup_information.h"
+#include "base/win/windows_version.h"
+#include "testing/multiprocess_func_list.h"
+
+const wchar_t kSectionName[] = L"EventTestSection";
+const size_t kSectionSize = 4096;
+
+MULTIPROCESS_TEST_MAIN(FireInheritedEvents) {
+  HANDLE section = ::OpenFileMappingW(PAGE_READWRITE, false, kSectionName);
+  HANDLE* events = reinterpret_cast<HANDLE*>(::MapViewOfFile(section,
+      PAGE_READWRITE, 0, 0, kSectionSize));
+  // This event should not be valid because it wasn't explicitly inherited.
+  if (::SetEvent(events[1]))
+    return -1;
+  // This event should be valid because it was explicitly inherited.
+  if (!::SetEvent(events[0]))
+    return -1;
+
+  return 0;
+}
+
+class StartupInformationTest : public base::MultiProcessTest {};
+
+// Verify that only the explicitly specified event is inherited.
+TEST_F(StartupInformationTest, InheritStdOut) {
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return;
+
+  base::win::ScopedProcessInformation process_info;
+  base::win::StartupInformation startup_info;
+
+  HANDLE section = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
+                                        PAGE_READWRITE, 0, kSectionSize,
+                                        kSectionName);
+  ASSERT_TRUE(section);
+
+  HANDLE* events = reinterpret_cast<HANDLE*>(::MapViewOfFile(section,
+      FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kSectionSize));
+
+  // Make two inheritable events.
+  SECURITY_ATTRIBUTES security_attributes = { sizeof(security_attributes),
+                                              NULL, true };
+  events[0] = ::CreateEvent(&security_attributes, false, false, NULL);
+  ASSERT_TRUE(events[0]);
+  events[1] = ::CreateEvent(&security_attributes, false, false, NULL);
+  ASSERT_TRUE(events[1]);
+
+  ASSERT_TRUE(startup_info.InitializeProcThreadAttributeList(1));
+  ASSERT_TRUE(startup_info.UpdateProcThreadAttribute(
+      PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &events[0],
+      sizeof(events[0])));
+
+  std::wstring cmd_line =
+      this->MakeCmdLine("FireInheritedEvents", false).GetCommandLineString();
+
+  ASSERT_TRUE(::CreateProcess(NULL, const_cast<wchar_t*>(cmd_line.c_str()),
+                              NULL, NULL, true, EXTENDED_STARTUPINFO_PRESENT,
+                              NULL, NULL, startup_info.startup_info(),
+                              process_info.Receive())) << ::GetLastError();
+  // Only the first event should be signalled
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(2, events, false,
+                                                    4000));
+}
+
diff --git a/base/win/text_services_message_filter.cc b/base/win/text_services_message_filter.cc
new file mode 100644
index 0000000..7ce233d
--- /dev/null
+++ b/base/win/text_services_message_filter.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/win/text_services_message_filter.h"
+
+namespace base {
+namespace win {
+
+TextServicesMessageFilter::TextServicesMessageFilter()
+    : client_id_(TF_CLIENTID_NULL),
+      is_initialized_(false) {
+}
+
+TextServicesMessageFilter::~TextServicesMessageFilter() {
+  if (is_initialized_)
+    thread_mgr_->Deactivate();
+}
+
+bool TextServicesMessageFilter::Init() {
+  if (FAILED(thread_mgr_.CreateInstance(CLSID_TF_ThreadMgr)))
+    return false;
+
+  if (FAILED(message_pump_.QueryFrom(thread_mgr_)))
+    return false;
+
+  if (FAILED(keystroke_mgr_.QueryFrom(thread_mgr_)))
+    return false;
+
+  if (FAILED(thread_mgr_->Activate(&client_id_)))
+    return false;
+
+  is_initialized_ = true;
+  return is_initialized_;
+}
+
+// Wraps for ITfMessagePump::PeekMessage with win32 PeekMessage signature.
+// Obtains messages from application message queue.
+BOOL TextServicesMessageFilter::DoPeekMessage(MSG* msg,
+                                              HWND window_handle,
+                                              UINT msg_filter_min,
+                                              UINT msg_filter_max,
+                                              UINT remove_msg) {
+  BOOL result = FALSE;
+  if (FAILED(message_pump_->PeekMessage(msg, window_handle,
+                                        msg_filter_min, msg_filter_max,
+                                        remove_msg, &result))) {
+    result = FALSE;
+  }
+
+  return result;
+}
+
+// Sends message to Text Service Manager.
+// The message will be used to input composition text.
+// Returns true if |message| was consumed by text service manager.
+bool TextServicesMessageFilter::ProcessMessage(const MSG& msg) {
+  if (msg.message == WM_KEYDOWN) {
+    BOOL eaten = FALSE;
+    HRESULT hr = keystroke_mgr_->TestKeyDown(msg.wParam, msg.lParam, &eaten);
+    if (FAILED(hr) && !eaten)
+      return false;
+    eaten = FALSE;
+    hr = keystroke_mgr_->KeyDown(msg.wParam, msg.lParam, &eaten);
+    return (SUCCEEDED(hr) && !!eaten);
+  }
+
+  if (msg.message == WM_KEYUP) {
+    BOOL eaten = FALSE;
+    HRESULT hr = keystroke_mgr_->TestKeyUp(msg.wParam, msg.lParam, &eaten);
+    if (FAILED(hr) && !eaten)
+      return false;
+    eaten = FALSE;
+    hr = keystroke_mgr_->KeyUp(msg.wParam, msg.lParam, &eaten);
+    return (SUCCEEDED(hr) && !!eaten);
+  }
+
+  return false;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/text_services_message_filter.h b/base/win/text_services_message_filter.h
new file mode 100644
index 0000000..facd613
--- /dev/null
+++ b/base/win/text_services_message_filter.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_TEXT_SERVICES_MESSAGE_FILTER_H_
+#define BASE_WIN_TEXT_SERVICES_MESSAGE_FILTER_H_
+
+#include <msctf.h>
+#include <Windows.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_pump_win.h"
+#include "base/win/metro.h"
+#include "base/win/scoped_comptr.h"
+
+namespace base {
+namespace win {
+
+// TextServicesMessageFilter extends MessageFilter with methods that are using
+// Text Services Framework COM component.
+class BASE_EXPORT TextServicesMessageFilter
+    : public base::MessagePumpForUI::MessageFilter {
+ public:
+  TextServicesMessageFilter();
+  virtual ~TextServicesMessageFilter();
+  virtual BOOL DoPeekMessage(MSG* msg,
+                             HWND window_handle,
+                             UINT msg_filter_min,
+                             UINT msg_filter_max,
+                             UINT remove_msg) OVERRIDE;
+  virtual bool ProcessMessage(const MSG& msg) OVERRIDE;
+
+  bool Init();
+
+ private:
+  TfClientId client_id_;
+  bool is_initialized_;
+  base::win::ScopedComPtr<ITfThreadMgr> thread_mgr_;
+  base::win::ScopedComPtr<ITfMessagePump> message_pump_;
+  base::win::ScopedComPtr<ITfKeystrokeMgr> keystroke_mgr_;
+
+  DISALLOW_COPY_AND_ASSIGN(TextServicesMessageFilter);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_TEXT_SERVICES_MESSAGE_FILTER_H_
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
new file mode 100644
index 0000000..7c106a2
--- /dev/null
+++ b/base/win/win_util.cc
@@ -0,0 +1,227 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/win_util.h"
+
+#include <aclapi.h>
+#include <shobjidl.h>  // Must be before propkey.
+#include <initguid.h>
+#include <propkey.h>
+#include <propvarutil.h>
+#include <sddl.h>
+#include <shlobj.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/registry.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+// Sets the value of |property_key| to |property_value| in |property_store|.
+// Clears the PropVariant contained in |property_value|.
+bool SetPropVariantValueForPropertyStore(
+    IPropertyStore* property_store,
+    const PROPERTYKEY& property_key,
+    PROPVARIANT* property_value) {
+  DCHECK(property_store);
+
+  HRESULT result = property_store->SetValue(property_key, *property_value);
+  if (result == S_OK)
+    result = property_store->Commit();
+
+  PropVariantClear(property_value);
+  return SUCCEEDED(result);
+}
+
+}  // namespace
+
+namespace base {
+namespace win {
+
+static bool g_crash_on_process_detach = false;
+
+#define NONCLIENTMETRICS_SIZE_PRE_VISTA \
+    SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont)
+
+void GetNonClientMetrics(NONCLIENTMETRICS* metrics) {
+  DCHECK(metrics);
+
+  static const UINT SIZEOF_NONCLIENTMETRICS =
+      (base::win::GetVersion() >= base::win::VERSION_VISTA) ?
+      sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
+  metrics->cbSize = SIZEOF_NONCLIENTMETRICS;
+  const bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
+                                              SIZEOF_NONCLIENTMETRICS, metrics,
+                                              0);
+  DCHECK(success);
+}
+
+bool GetUserSidString(std::wstring* user_sid) {
+  // Get the current token.
+  HANDLE token = NULL;
+  if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
+    return false;
+  base::win::ScopedHandle token_scoped(token);
+
+  DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+  scoped_array<BYTE> user_bytes(new BYTE[size]);
+  TOKEN_USER* user = reinterpret_cast<TOKEN_USER*>(user_bytes.get());
+
+  if (!::GetTokenInformation(token, TokenUser, user, size, &size))
+    return false;
+
+  if (!user->User.Sid)
+    return false;
+
+  // Convert the data to a string.
+  wchar_t* sid_string;
+  if (!::ConvertSidToStringSid(user->User.Sid, &sid_string))
+    return false;
+
+  *user_sid = sid_string;
+
+  ::LocalFree(sid_string);
+
+  return true;
+}
+
+bool IsShiftPressed() {
+  return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000;
+}
+
+bool IsCtrlPressed() {
+  return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
+}
+
+bool IsAltPressed() {
+  return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000;
+}
+
+bool UserAccountControlIsEnabled() {
+  // This can be slow if Windows ends up going to disk.  Should watch this key
+  // for changes and only read it once, preferably on the file thread.
+  //   http://code.google.com/p/chromium/issues/detail?id=61644
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  base::win::RegKey key(HKEY_LOCAL_MACHINE,
+      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
+      KEY_READ);
+  DWORD uac_enabled;
+  if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS)
+    return true;
+  // Users can set the EnableLUA value to something arbitrary, like 2, which
+  // Vista will treat as UAC enabled, so we make sure it is not set to 0.
+  return (uac_enabled != 0);
+}
+
+bool SetBooleanValueForPropertyStore(IPropertyStore* property_store,
+                                     const PROPERTYKEY& property_key,
+                                     bool property_bool_value) {
+  PROPVARIANT property_value;
+  if (FAILED(InitPropVariantFromBoolean(property_bool_value, &property_value)))
+    return false;
+
+  return SetPropVariantValueForPropertyStore(property_store,
+                                             property_key,
+                                             &property_value);
+}
+
+bool SetStringValueForPropertyStore(IPropertyStore* property_store,
+                                    const PROPERTYKEY& property_key,
+                                    const wchar_t* property_string_value) {
+  PROPVARIANT property_value;
+  if (FAILED(InitPropVariantFromString(property_string_value, &property_value)))
+    return false;
+
+  return SetPropVariantValueForPropertyStore(property_store,
+                                             property_key,
+                                             &property_value);
+}
+
+bool SetAppIdForPropertyStore(IPropertyStore* property_store,
+                              const wchar_t* app_id) {
+  // App id should be less than 64 chars and contain no space. And recommended
+  // format is CompanyName.ProductName[.SubProduct.ProductNumber].
+  // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx
+  DCHECK(lstrlen(app_id) < 64 && wcschr(app_id, L' ') == NULL);
+
+  return SetStringValueForPropertyStore(property_store,
+                                        PKEY_AppUserModel_ID,
+                                        app_id);
+}
+
+static const char16 kAutoRunKeyPath[] =
+    L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
+
+bool AddCommandToAutoRun(HKEY root_key, const string16& name,
+                         const string16& command) {
+  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  return (autorun_key.WriteValue(name.c_str(), command.c_str()) ==
+      ERROR_SUCCESS);
+}
+
+bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) {
+  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS);
+}
+
+bool ReadCommandFromAutoRun(HKEY root_key,
+                            const string16& name,
+                            string16* command) {
+  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
+  return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS);
+}
+
+void SetShouldCrashOnProcessDetach(bool crash) {
+  g_crash_on_process_detach = crash;
+}
+
+bool ShouldCrashOnProcessDetach() {
+  return g_crash_on_process_detach;
+}
+
+bool IsMachineATablet() {
+  if (base::win::GetVersion() < base::win::VERSION_WIN7)
+    return false;
+  const int kMultiTouch = NID_INTEGRATED_TOUCH | NID_MULTI_INPUT | NID_READY;
+  const int kMaxTabletScreenWidth = 1366;
+  const int kMaxTabletScreenHeight = 768;
+  int sm = GetSystemMetrics(SM_DIGITIZER);
+  if ((sm & kMultiTouch) == kMultiTouch) {
+    int cx = GetSystemMetrics(SM_CXSCREEN);
+    int cy = GetSystemMetrics(SM_CYSCREEN);
+    return cx <= kMaxTabletScreenWidth && cy <= kMaxTabletScreenHeight;
+  }
+  return false;
+}
+
+}  // namespace win
+}  // namespace base
+
+#ifdef _MSC_VER
+//
+// If the ASSERT below fails, please install Visual Studio 2005 Service Pack 1.
+//
+extern char VisualStudio2005ServicePack1Detection[10];
+COMPILE_ASSERT(sizeof(&VisualStudio2005ServicePack1Detection) == sizeof(void*),
+               VS2005SP1Detect);
+//
+// Chrome requires at least Service Pack 1 for Visual Studio 2005.
+//
+#endif  // _MSC_VER
+
+#ifndef COPY_FILE_COPY_SYMLINK
+#error You must install the Windows 2008 or Vista Software Development Kit and \
+set it as your default include path to build this library. You can grab it by \
+searching for "download windows sdk 2008" in your favorite web search engine.  \
+Also make sure you register the SDK with Visual Studio, by selecting \
+"Integrate Windows SDK with Visual Studio 2005" from the Windows SDK \
+menu (see Start - All Programs - Microsoft Windows SDK - \
+Visual Studio Registration).
+#endif
diff --git a/base/win/win_util.h b/base/win/win_util.h
new file mode 100644
index 0000000..7db98e9
--- /dev/null
+++ b/base/win/win_util.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.
+
+// =============================================================================
+// PLEASE READ
+//
+// In general, you should not be adding stuff to this file.
+//
+// - If your thing is only used in one place, just put it in a reasonable
+//   location in or near that one place. It's nice you want people to be able
+//   to re-use your function, but realistically, if it hasn't been necessary
+//   before after so many years of development, it's probably not going to be
+//   used in other places in the future unless you know of them now.
+//
+// - If your thing is used by multiple callers and is UI-related, it should
+//   probably be in app/win/ instead. Try to put it in the most specific file
+//   possible (avoiding the *_util files when practical).
+//
+// =============================================================================
+
+#ifndef BASE_WIN_WIN_UTIL_H_
+#define BASE_WIN_WIN_UTIL_H_
+
+#include <windows.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/string16.h"
+
+struct IPropertyStore;
+struct _tagpropertykey;
+typedef _tagpropertykey PROPERTYKEY;
+
+namespace base {
+namespace win {
+
+// A Windows message reflected from other windows. This message is sent
+// with the following arguments:
+// hWnd - Target window
+// uMsg - kReflectedMessage
+// wParam - Should be 0
+// lParam - Pointer to MSG struct containing the original message.
+const int kReflectedMessage = WM_APP + 3;
+
+BASE_EXPORT void GetNonClientMetrics(NONCLIENTMETRICS* metrics);
+
+// Returns the string representing the current user sid.
+BASE_EXPORT bool GetUserSidString(std::wstring* user_sid);
+
+// Returns true if the shift key is currently pressed.
+BASE_EXPORT bool IsShiftPressed();
+
+// Returns true if the ctrl key is currently pressed.
+BASE_EXPORT bool IsCtrlPressed();
+
+// Returns true if the alt key is currently pressed.
+BASE_EXPORT bool IsAltPressed();
+
+// Returns false if user account control (UAC) has been disabled with the
+// EnableLUA registry flag. Returns true if user account control is enabled.
+// NOTE: The EnableLUA registry flag, which is ignored on Windows XP
+// machines, might still exist and be set to 0 (UAC disabled), in which case
+// this function will return false. You should therefore check this flag only
+// if the OS is Vista or later.
+BASE_EXPORT bool UserAccountControlIsEnabled();
+
+// Sets the boolean value for a given key in given IPropertyStore.
+BASE_EXPORT bool SetBooleanValueForPropertyStore(
+    IPropertyStore* property_store,
+    const PROPERTYKEY& property_key,
+    bool property_bool_value);
+
+// Sets the string value for a given key in given IPropertyStore.
+BASE_EXPORT bool SetStringValueForPropertyStore(
+    IPropertyStore* property_store,
+    const PROPERTYKEY& property_key,
+    const wchar_t* property_string_value);
+
+// Sets the application id in given IPropertyStore. The function is intended
+// for tagging application/chromium shortcut, browser window and jump list for
+// Win7.
+BASE_EXPORT bool SetAppIdForPropertyStore(IPropertyStore* property_store,
+                                          const wchar_t* app_id);
+
+// Adds the specified |command| using the specified |name| to the AutoRun key.
+// |root_key| could be HKCU or HKLM or the root of any user hive.
+BASE_EXPORT bool AddCommandToAutoRun(HKEY root_key, const string16& name,
+                                     const string16& command);
+// Removes the command specified by |name| from the AutoRun key. |root_key|
+// could be HKCU or HKLM or the root of any user hive.
+BASE_EXPORT bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name);
+
+// Reads the command specified by |name| from the AutoRun key. |root_key|
+// could be HKCU or HKLM or the root of any user hive. Used for unit-tests.
+BASE_EXPORT bool ReadCommandFromAutoRun(HKEY root_key,
+                                        const string16& name,
+                                        string16* command);
+
+// Sets whether to crash the process during exit. This is inspected by DLLMain
+// and used to intercept unexpected terminations of the process (via calls to
+// exit(), abort(), _exit(), ExitProcess()) and convert them into crashes.
+// Note that not all mechanisms for terminating the process are covered by
+// this. In particular, TerminateProcess() is not caught.
+BASE_EXPORT void SetShouldCrashOnProcessDetach(bool crash);
+BASE_EXPORT bool ShouldCrashOnProcessDetach();
+
+// A tablet by this definition is something that has integrated multi-touch
+// ready to use and also has screen resolution not greater than 1366x768.
+BASE_EXPORT bool IsMachineATablet();
+
+// Get the size of a struct up to and including the specified member.
+// This is necessary to set compatible struct sizes for different versions
+// of certain Windows APIs (e.g. SystemParametersInfo).
+#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(struct_name, member) \
+    offsetof(struct_name, member) + \
+    (sizeof static_cast<struct_name*>(NULL)->member)
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_WIN_UTIL_H_
diff --git a/base/win/win_util_unittest.cc b/base/win/win_util_unittest.cc
new file mode 100644
index 0000000..b79ed56
--- /dev/null
+++ b/base/win/win_util_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/string_util.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Saves the current thread's locale ID when initialized, and restores it when
+// the instance is going out of scope.
+class ThreadLocaleSaver {
+ public:
+  ThreadLocaleSaver() : original_locale_id_(GetThreadLocale()) {}
+  ~ThreadLocaleSaver() { SetThreadLocale(original_locale_id_); }
+
+ private:
+  LCID original_locale_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocaleSaver);
+};
+
+}  // namespace
+
+// The test is somewhat silly, because the Vista bots some have UAC enabled
+// and some have it disabled. At least we check that it does not crash.
+TEST(BaseWinUtilTest, TestIsUACEnabled) {
+  if (GetVersion() >= base::win::VERSION_VISTA) {
+    UserAccountControlIsEnabled();
+  } else {
+    EXPECT_TRUE(UserAccountControlIsEnabled());
+  }
+}
+
+TEST(BaseWinUtilTest, TestGetUserSidString) {
+  std::wstring user_sid;
+  EXPECT_TRUE(GetUserSidString(&user_sid));
+  EXPECT_TRUE(!user_sid.empty());
+}
+
+TEST(BaseWinUtilTest, TestGetNonClientMetrics) {
+  NONCLIENTMETRICS metrics = {0};
+  GetNonClientMetrics(&metrics);
+  EXPECT_TRUE(metrics.cbSize > 0);
+  EXPECT_TRUE(metrics.iScrollWidth > 0);
+  EXPECT_TRUE(metrics.iScrollHeight > 0);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc
new file mode 100644
index 0000000..c130e0e
--- /dev/null
+++ b/base/win/windows_version.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/windows_version.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/registry.h"
+
+namespace base {
+namespace win {
+
+// static
+OSInfo* OSInfo::GetInstance() {
+  // Note: we don't use the Singleton class because it depends on AtExitManager,
+  // and it's convenient for other modules to use this classs without it. This
+  // pattern is copied from gurl.cc.
+  static OSInfo* info;
+  if (!info) {
+    OSInfo* new_info = new OSInfo();
+    if (InterlockedCompareExchangePointer(
+        reinterpret_cast<PVOID*>(&info), new_info, NULL)) {
+      delete new_info;
+    }
+  }
+  return info;
+}
+
+OSInfo::OSInfo()
+    : version_(VERSION_PRE_XP),
+      architecture_(OTHER_ARCHITECTURE),
+      wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) {
+  OSVERSIONINFOEX version_info = { sizeof version_info };
+  GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
+  version_number_.major = version_info.dwMajorVersion;
+  version_number_.minor = version_info.dwMinorVersion;
+  version_number_.build = version_info.dwBuildNumber;
+  if ((version_number_.major == 5) && (version_number_.minor > 0)) {
+    // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
+    version_ = (version_number_.minor == 1) ? VERSION_XP : VERSION_SERVER_2003;
+  } else if (version_number_.major == 6) {
+    switch (version_number_.minor) {
+      case 0:
+        // Treat Windows Server 2008 the same as Windows Vista.
+        version_ = VERSION_VISTA;
+        break;
+      case 1:
+        // Treat Windows Server 2008 R2 the same as Windows 7.
+        version_ = VERSION_WIN7;
+        break;
+      default:
+        DCHECK_EQ(version_number_.minor, 2);
+        // Treat Windows Server 2012 the same as Windows 8.
+        version_ = VERSION_WIN8;
+        break;
+    }
+  } else if (version_number_.major > 6) {
+    NOTREACHED();
+    version_ = VERSION_WIN_LAST;
+  }
+  service_pack_.major = version_info.wServicePackMajor;
+  service_pack_.minor = version_info.wServicePackMinor;
+
+  SYSTEM_INFO system_info = { 0 };
+  GetNativeSystemInfo(&system_info);
+  switch (system_info.wProcessorArchitecture) {
+    case PROCESSOR_ARCHITECTURE_INTEL: architecture_ = X86_ARCHITECTURE; break;
+    case PROCESSOR_ARCHITECTURE_AMD64: architecture_ = X64_ARCHITECTURE; break;
+    case PROCESSOR_ARCHITECTURE_IA64:  architecture_ = IA64_ARCHITECTURE; break;
+  }
+  processors_ = system_info.dwNumberOfProcessors;
+  allocation_granularity_ = system_info.dwAllocationGranularity;
+}
+
+OSInfo::~OSInfo() {
+}
+
+std::string OSInfo::processor_model_name() {
+  if (processor_model_name_.empty()) {
+    const wchar_t kProcessorNameString[] =
+        L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
+    base::win::RegKey key(HKEY_LOCAL_MACHINE, kProcessorNameString, KEY_READ);
+    string16 value;
+    key.ReadValue(L"ProcessorNameString", &value);
+    processor_model_name_ = UTF16ToUTF8(value);
+  }
+  return processor_model_name_;
+}
+
+// static
+OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) {
+  typedef BOOL (WINAPI* IsWow64ProcessFunc)(HANDLE, PBOOL);
+  IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
+      GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
+  if (!is_wow64_process)
+    return WOW64_DISABLED;
+  BOOL is_wow64 = FALSE;
+  if (!(*is_wow64_process)(process_handle, &is_wow64))
+    return WOW64_UNKNOWN;
+  return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
+}
+
+Version GetVersion() {
+  return OSInfo::GetInstance()->version();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/windows_version.h b/base/win/windows_version.h
new file mode 100644
index 0000000..d466dad
--- /dev/null
+++ b/base/win/windows_version.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_WIN_WINDOWS_VERSION_H_
+#define BASE_WIN_WINDOWS_VERSION_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+typedef void* HANDLE;
+
+namespace base {
+namespace win {
+
+// The running version of Windows.  This is declared outside OSInfo for
+// syntactic sugar reasons; see the declaration of GetVersion() below.
+// NOTE: Keep these in order so callers can do things like
+// "if (base::win::GetVersion() >= base::win::VERSION_VISTA) ...".
+enum Version {
+  VERSION_PRE_XP = 0,  // Not supported.
+  VERSION_XP,
+  VERSION_SERVER_2003, // Also includes XP Pro x64 and Server 2003 R2.
+  VERSION_VISTA,       // Also includes Windows Server 2008.
+  VERSION_WIN7,        // Also includes Windows Server 2008 R2.
+  VERSION_WIN8,        // Also includes Windows Server 2012.
+  VERSION_WIN_LAST,    // Indicates error condition.
+};
+
+// A singleton that can be used to query various pieces of information about the
+// OS and process state. Note that this doesn't use the base Singleton class, so
+// it can be used without an AtExitManager.
+class BASE_EXPORT OSInfo {
+ public:
+  struct VersionNumber {
+    int major;
+    int minor;
+    int build;
+  };
+
+  struct ServicePack {
+    int major;
+    int minor;
+  };
+
+  // The processor architecture this copy of Windows natively uses.  For
+  // example, given an x64-capable processor, we have three possibilities:
+  //   32-bit Chrome running on 32-bit Windows:           X86_ARCHITECTURE
+  //   32-bit Chrome running on 64-bit Windows via WOW64: X64_ARCHITECTURE
+  //   64-bit Chrome running on 64-bit Windows:           X64_ARCHITECTURE
+  enum WindowsArchitecture {
+    X86_ARCHITECTURE,
+    X64_ARCHITECTURE,
+    IA64_ARCHITECTURE,
+    OTHER_ARCHITECTURE,
+  };
+
+  // Whether a process is running under WOW64 (the wrapper that allows 32-bit
+  // processes to run on 64-bit versions of Windows).  This will return
+  // WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit
+  // Chrome on 64-bit Windows".  WOW64_UNKNOWN means "an error occurred", e.g.
+  // the process does not have sufficient access rights to determine this.
+  enum WOW64Status {
+    WOW64_DISABLED,
+    WOW64_ENABLED,
+    WOW64_UNKNOWN,
+  };
+
+  static OSInfo* GetInstance();
+
+  Version version() const { return version_; }
+  // The next two functions return arrays of values, [major, minor(, build)].
+  VersionNumber version_number() const { return version_number_; }
+  ServicePack service_pack() const { return service_pack_; }
+  WindowsArchitecture architecture() const { return architecture_; }
+  int processors() const { return processors_; }
+  size_t allocation_granularity() const { return allocation_granularity_; }
+  WOW64Status wow64_status() const { return wow64_status_; }
+  std::string processor_model_name();
+
+  // Like wow64_status(), but for the supplied handle instead of the current
+  // process.  This doesn't touch member state, so you can bypass the singleton.
+  static WOW64Status GetWOW64StatusForProcess(HANDLE process_handle);
+
+ private:
+  OSInfo();
+  ~OSInfo();
+
+  Version version_;
+  VersionNumber version_number_;
+  ServicePack service_pack_;
+  WindowsArchitecture architecture_;
+  int processors_;
+  size_t allocation_granularity_;
+  WOW64Status wow64_status_;
+  std::string processor_model_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(OSInfo);
+};
+
+// Because this is by far the most commonly-requested value from the above
+// singleton, we add a global-scope accessor here as syntactic sugar.
+BASE_EXPORT Version GetVersion();
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_WINDOWS_VERSION_H_
diff --git a/base/win/wrapped_window_proc.cc b/base/win/wrapped_window_proc.cc
new file mode 100644
index 0000000..04e59c5
--- /dev/null
+++ b/base/win/wrapped_window_proc.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/wrapped_window_proc.h"
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+#include "base/process_util.h"
+
+namespace {
+
+base::win::WinProcExceptionFilter s_exception_filter = NULL;
+
+}  // namespace.
+
+namespace base {
+namespace win {
+
+WinProcExceptionFilter SetWinProcExceptionFilter(
+    WinProcExceptionFilter filter) {
+  subtle::AtomicWord rv = subtle::NoBarrier_AtomicExchange(
+      reinterpret_cast<subtle::AtomicWord*>(&s_exception_filter),
+      reinterpret_cast<subtle::AtomicWord>(filter));
+  return reinterpret_cast<WinProcExceptionFilter>(rv);
+}
+
+int CallExceptionFilter(EXCEPTION_POINTERS* info) {
+  return s_exception_filter ? s_exception_filter(info) :
+                              EXCEPTION_CONTINUE_SEARCH;
+}
+
+BASE_EXPORT void InitializeWindowClass(
+    const char16* class_name,
+    WNDPROC window_proc,
+    UINT style,
+    int class_extra,
+    int window_extra,
+    HCURSOR cursor,
+    HBRUSH background,
+    const char16* menu_name,
+    HICON large_icon,
+    HICON small_icon,
+    WNDCLASSEX* class_out) {
+  class_out->cbSize = sizeof(WNDCLASSEX);
+  class_out->style = style;
+  class_out->lpfnWndProc = window_proc;
+  class_out->cbClsExtra = class_extra;
+  class_out->cbWndExtra = window_extra;
+  class_out->hInstance = base::GetModuleFromAddress(window_proc);
+  class_out->hIcon = large_icon;
+  class_out->hCursor = cursor;
+  class_out->hbrBackground = background;
+  class_out->lpszMenuName = menu_name;
+  class_out->lpszClassName = class_name;
+  class_out->hIconSm = small_icon;
+
+  // Check if |window_proc| is valid.
+  DCHECK(class_out->hInstance != NULL);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/wrapped_window_proc.h b/base/win/wrapped_window_proc.h
new file mode 100644
index 0000000..b5793f2
--- /dev/null
+++ b/base/win/wrapped_window_proc.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Provides a way to handle exceptions that happen while a WindowProc is
+// running. The behavior of exceptions generated inside a WindowProc is OS
+// dependent, but it is possible that the OS just ignores the exception and
+// continues execution, which leads to unpredictable behavior for Chrome.
+
+#ifndef BASE_WIN_WRAPPED_WINDOW_PROC_H_
+#define BASE_WIN_WRAPPED_WINDOW_PROC_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/string16.h"
+
+namespace base {
+namespace win {
+
+// An exception filter for a WindowProc. The return value determines how the
+// exception should be handled, following standard SEH rules. However, the
+// expected behavior for this function is to not return, instead of returning
+// EXCEPTION_EXECUTE_HANDLER or similar, given that in general we are not
+// prepared to handle exceptions.
+typedef int (__cdecl *WinProcExceptionFilter)(EXCEPTION_POINTERS* info);
+
+// Sets the filter to deal with exceptions inside a WindowProc. Returns the old
+// exception filter, if any.
+// This function should be called before any window is created.
+BASE_EXPORT WinProcExceptionFilter SetWinProcExceptionFilter(
+    WinProcExceptionFilter filter);
+
+// Calls the registered exception filter.
+BASE_EXPORT int CallExceptionFilter(EXCEPTION_POINTERS* info);
+
+// Initializes the WNDCLASSEX structure |*class_out| to be passed to
+// RegisterClassEx() making sure that it is associated with the module
+// containing the window procedure.
+BASE_EXPORT void InitializeWindowClass(
+    const char16* class_name,
+    WNDPROC window_proc,
+    UINT style,
+    int class_extra,
+    int window_extra,
+    HCURSOR cursor,
+    HBRUSH background,
+    const char16* menu_name,
+    HICON large_icon,
+    HICON small_icon,
+    WNDCLASSEX* class_out);
+
+// Wrapper that supplies a standard exception frame for the provided WindowProc.
+// The normal usage is something like this:
+//
+// LRESULT CALLBACK MyWinProc(HWND hwnd, UINT message,
+//                            WPARAM wparam, LPARAM lparam) {
+//   // Do Something.
+// }
+//
+// ...
+//
+//   WNDCLASSEX wc = {0};
+//   wc.lpfnWndProc = WrappedWindowProc<MyWinProc>;
+//   wc.lpszClassName = class_name;
+//   ...
+//   RegisterClassEx(&wc);
+//
+//   CreateWindowW(class_name, window_name, ...
+//
+template <WNDPROC proc>
+LRESULT CALLBACK WrappedWindowProc(HWND hwnd, UINT message,
+                                   WPARAM wparam, LPARAM lparam) {
+  LRESULT rv = 0;
+  __try {
+    rv = proc(hwnd, message, wparam, lparam);
+  } __except(CallExceptionFilter(GetExceptionInformation())) {
+  }
+  return rv;
+}
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_WRAPPED_WINDOW_PROC_H_
diff --git a/base/win/wrapped_window_proc_unittest.cc b/base/win/wrapped_window_proc_unittest.cc
new file mode 100644
index 0000000..ccf3c85
--- /dev/null
+++ b/base/win/wrapped_window_proc_unittest.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/wrapped_window_proc.h"
+#include "base/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+DWORD kExceptionCode = 12345;
+WPARAM kCrashMsg = 98765;
+
+// A trivial WindowProc that generates an exception.
+LRESULT CALLBACK TestWindowProc(HWND hwnd, UINT message,
+                                WPARAM wparam, LPARAM lparam) {
+  if (message == kCrashMsg)
+    RaiseException(kExceptionCode, 0, 0, NULL);
+  return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+// This class implements an exception filter that can be queried about a past
+// exception.
+class TestWrappedExceptionFiter {
+ public:
+  TestWrappedExceptionFiter() : called_(false) {
+    EXPECT_FALSE(s_filter_);
+    s_filter_ = this;
+  }
+
+  ~TestWrappedExceptionFiter() {
+    EXPECT_EQ(s_filter_, this);
+    s_filter_ = NULL;
+  }
+
+  bool called() {
+    return called_;
+  }
+
+  // The actual exception filter just records the exception.
+  static int Filter(EXCEPTION_POINTERS* info) {
+    EXPECT_FALSE(s_filter_->called_);
+    if (info->ExceptionRecord->ExceptionCode == kExceptionCode)
+      s_filter_->called_ = true;
+    return EXCEPTION_EXECUTE_HANDLER;
+  }
+
+ private:
+  bool called_;
+  static TestWrappedExceptionFiter* s_filter_;
+};
+TestWrappedExceptionFiter* TestWrappedExceptionFiter::s_filter_ = NULL;
+
+}  // namespace.
+
+TEST(WrappedWindowProc, CatchesExceptions) {
+  HINSTANCE hinst = GetModuleHandle(NULL);
+  std::wstring class_name(L"TestClass");
+
+  WNDCLASS wc = {0};
+  wc.lpfnWndProc = base::win::WrappedWindowProc<TestWindowProc>;
+  wc.hInstance = hinst;
+  wc.lpszClassName = class_name.c_str();
+  RegisterClass(&wc);
+
+  HWND window = CreateWindow(class_name.c_str(), 0, 0, 0, 0, 0, 0, HWND_MESSAGE,
+                             0, hinst, 0);
+  ASSERT_TRUE(window);
+
+  // Before generating the exception we make sure that the filter will see it.
+  TestWrappedExceptionFiter wrapper;
+  base::win::WinProcExceptionFilter old_filter =
+      base::win::SetWinProcExceptionFilter(TestWrappedExceptionFiter::Filter);
+
+  SendMessage(window, kCrashMsg, 0, 0);
+  EXPECT_TRUE(wrapper.called());
+
+  base::win::SetWinProcExceptionFilter(old_filter);
+}