Initial import of Cobalt 2.8885 2016-07-27
diff --git a/src/.clang-format b/src/.clang-format
new file mode 100644
index 0000000..d5c7b08
--- /dev/null
+++ b/src/.clang-format
@@ -0,0 +1,3 @@
+# Defines the Chromium style for automatic reformatting.

+# http://clang.llvm.org/docs/ClangFormatStyleOptions.html

+BasedOnStyle: Chromium

diff --git a/src/AUTHORS b/src/AUTHORS
new file mode 100644
index 0000000..5a7ed82
--- /dev/null
+++ b/src/AUTHORS
@@ -0,0 +1,12 @@
+# Names should be added to this file with this pattern:
+#
+# For individuals:
+#   Name <email address>
+#
+# For organizations:
+#   Organization <fnmatch pattern>
+#
+# See python fnmatch module documentation for more information.
+
+The Chromium Authors <*@chromium.org>
+Google Inc. <*@google.com>
diff --git a/src/LICENSE b/src/LICENSE
new file mode 100644
index 0000000..3d0f7d3
--- /dev/null
+++ b/src/LICENSE
@@ -0,0 +1,27 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/README.cobalt.txt b/src/README.cobalt.txt
new file mode 100644
index 0000000..bc2d9c7
--- /dev/null
+++ b/src/README.cobalt.txt
@@ -0,0 +1,2 @@
+This is a fork of the chromium repository at http://git.chromium.org/git/chromium.git
+
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..2d2efba
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,247 @@
+# Cobalt
+
+## Overview
+
+Cobalt is a lightweight application container (i.e. an application runtime, like
+a JVM or the Flash Player) that is compatible with a subset of the W3C HTML5
+specifications. If you author a single-page web application (SPA) that complies
+with the Cobalt Subset of W3C standards, it will run as well as possible on all
+the devices that Cobalt supports.
+
+
+## Motivation
+
+The Cobalt Authors originally maintained a port of Chromium called H5VCC, the
+HTML5 Video Container for Consoles, ported to each of the major game consoles,
+designed to run our HTML5-based video browse and play application. This took a
+long time to port to each platform, consisted of 9 million lines of C++ code
+(before we touched it), was dangerous to modify without unintended consequences,
+and was thoroughly designed for a resource-rich, multi-process environment
+(e.g. a desktop, laptop, or modern smartphone).
+
+After wrestling with this for several years, we imagined an environment that was
+not designed for traditional scrolling web content, but was intended to be a
+runtime environment for rich client applications built with the same
+technologies -- HTML, CSS, JavaScript -- and designed from the ground-up to run
+on constrained, embedded, Living Room Consumer Electronics (CE) devices, such as
+Game Consoles, Set-Top Boxes (e.g. Cable, Satellite), OTT devices (e.g. Roku,
+Apple TV, Chromecast, Fire TV), Blu-ray Disc Players, and Smart TVs.
+
+These constraints (not intended to be a canonical list) make this device
+spectrum vastly different from the desktop computer environment targeted by
+Chromium, FireFox, and IE:
+
+  * **Limited Memory.** All except the very latest, expensive CE devices have a
+    very small amount of memory available for applications. This usually is
+    somewhere in the ballpark of 200MB-500MB, including graphics and media
+    memory, as opposed to multiple gigabytes of CPU memory (and more gigabytes
+    of GPU memory) in modern desktop and laptop computers, and mobile devices.
+  * **Slow CPUs.** Most CE devices have much slower CPUs than what is available
+    on even a budget desktop computer. Minor performance concerns can be greatly
+    exaggerated, which seriously affects priorities.
+  * **Fewer cores.** CE System-on-a-Chip (SoC) processors often do not have as
+    many processor cores as we are used to in modern computers. Many deployed
+    devices still only have a single core.
+  * **Sometimes No GPU.** Not all CE devices have a monster GPU to throw shaders
+    at to offload CPU work. A different strategy is required to maximize
+    leverage of an accelerated blitter, which is all some older devices
+    have. Some newer CE devices have a GPU, but it's not nearly as powerful as
+    what one would even see on a laptop.
+  * **Sometimes No JIT.** Many CE devices are dealing with "High-Value Content,"
+    and, as such, are very sensitive to security concerns. Ensuring that
+    writable pages are not executable is a strong security protocol that can
+    prevent a wide spectrum of attacks. But, as a side effect, this also means
+    no ability to JIT.
+  * **Heterogenous Development Environments.** This is slowly evening out, but
+    all CE devices run on custom hardware, often with proprietary methods of
+    building, packaging, deploying, and running programs. Almost all CE devices
+    have ARM or MIPS processors instead of the more familiar x86. Sometimes the
+    toolchain doesn't support contemporary C++11 features. Sometimes the OS
+    isn't POSIX, or it tries to be, but it is only partially implemented.
+    Sometimes the program entry point is in another language or architecture
+    that requires a "trampoline" over to native binary code.
+  * **No navigation.** The point of a Single-Page Application is that you don't
+    go through the HTTP page dance every time you switch screens. It's slow, and
+    provides poor user feedback, not to mention a jarring transition. Instead,
+    one loads data from an XMLHttpRequest (XHR), and then updates one's DOM to
+    reflect the new data. AJAX! Web 2.0!!
+  * **No scrolling.** Well, full-screen, 10-foot UI SPA apps might scroll, but
+    not like traditional web pages, with scroll bars and a mouse
+    wheel. Scrolling is generally built into the app very carefully, with
+    support for a Directional Pad and a focus cursor.
+
+
+## Architecture
+
+The Cobalt Authors forked H5VCC, removed most of the Chromium code -- in
+particular WebCore and the Chrome Renderer and Compositor -- and built up from
+scratch an implementation of a simplified subset of HTML, the CSS Box Model for
+layout, and the Web APIs that were really needed to build a full-screen SPA
+browse and play application.
+
+The Cobalt technology stack has these major components, roughly in a high-level
+application to a low-level platform order:
+
+  * **Web Implementation** - This is where the W3C standards are implemented,
+    ultimately producing an annotated DOM tree that can be passed into the
+    Layout Engine to produce a Render Tree.
+  * **JavaScript Engine** - We have, perhaps surprisingly, *not* written our own
+    JavaScript Engine from scratch. Because of the JITing constraint, we have to
+    be flexible with which engine(s) we work with. We have a bindings layer that
+    interfaces with the JS Engine so that application script can interface with
+    natively-backed objects (like DOM elements).
+  * **Layout Engine** - The Layout Engine takes an annotated DOM Document
+    produced by the Web Implementation and JavaScript Engine working together,
+    and calculates a tree of rendering commands to send to the renderer (i.e. a
+    Render Tree). It caches intermediate layout artifacts so that subsequent
+    incremental layouts can be sped up.
+  * **Renderer/Skia** - The Renderer walks a Render Tree produced by the Layout
+    Engine, rasterizes it using the third-party graphics library Skia, and swaps
+    it to the front buffer. There are two major paths here, one using Hardware
+    Skia on OpenGL ES 2.0, and one using Software Skia combined with the
+    hardware-accelerated Starboard Blitter. Note that the renderer runs in a
+    different thread from the Layout Engine, and can interpolate animations that
+    do not require re-layout. This decouples rendering from Layout and
+    JavaScript, allowing for smooth, consistent animations on platforms with a
+    variety of capabilities.
+  * **Net / Media** - These are Chromium's Network and Media engines. We are
+    using them directly, as they don't cause any particular problems with the
+    extra constraints listed above.
+  * **Base** - This is Chromium's "Base" library, which contains a wide variety
+    of useful things used throughout Cobalt, Net, and Media. Cobalt uses a
+    combination of standard C++ containers (e.g. vector, string) and Base as the
+    foundation library for all of its code.
+  * **Other Third-party Libraries** - Most of these are venerable, straight-C,
+    open-source libraries that are commonly included in other open-source
+    software. Mostly format decoders and parsers (e.g. libpng, libxml2,
+    zlib). We fork these from Chromium, as we want them to be the most
+    battle-tested versions of these libraries.
+  * **Starboard/Glimp/ANGLE** - **Starboard** is the Cobalt porting
+    interface. One major difference between Cobalt and Chromium is that we have
+    created a hard straight-C porting layer, and ported ALL of the compiled
+    code, including Base and all third-party libraries, to use it instead of
+    directly using POSIX standard libraries, which are not consistent, even on
+    modern systems (see Android, Windows, MacOS X, and iOS). Additionally,
+    Starboard includes APIs that haven't been effectively standardized across
+    platforms, such as display Window creation, Input events, and Media
+    playback. **Glimp** is an OpenGL ES 2.0 implementation framework, built by
+    the Cobalt team directly on Starboard, designed to adapt proprietary 3D APIs
+    to GLES2. **ANGLE** Is a third-party library that adapts DirectX to GLES2,
+    similar to Glimp, but only for DirectX.
+
+Cobalt is like a flaky layered pastry - perhaps Baklava. It shouldn't be too
+difficult to rip the Web Implementation and Layout off the top, and just use the
+Renderer, or even to just use Base + Starboard + GLES2 as the basis of a new
+project.
+
+
+## The Cobalt Subset
+
+> Oh, we got both kinds of HTML tags,\
+> we got `<span>` and `<div>`!
+
+See the [Cobalt Subset specification](TODO) for more details on which tags,
+properties, and Web APIs are supported in Cobalt.
+
+*More to come.*
+
+
+## Interesting Source Locations
+
+All source locations are specified relative to `src/` (this directory).
+
+  * `base/` - Chromium's Base library. Contains common utilities, and a light
+    platform abstraction, which has been superceded in Cobalt by Starboard.
+  * `net/` - Chromium's Network library. Contains enough infrastructure to
+    support the network needs of an HTTP User-Agent (like Chromium or Cobalt),
+    an HTTP server, a DIAL server, and several abstractions for networking
+    primitives. Also contains SPDY and QUIC implementations.
+  * `media/` - Chromium's Media library. Contains all the code that parses,
+    processes, and manages buffers of video and audio data. Media decoding is
+    passed off to decoding hardware, wherever possible.
+  * `cobalt/` - The home of all Cobalt application code. This includes the Web
+    Implementation, Layout Engine, Renderer, and some other Cobalt-specific
+    features.
+      * `cobalt/build/` - The core build generation system, `gyp_cobalt`, and
+        configurations for supported platforms. (NOTE: This should eventually be
+        mostly moved into `starboard/`.)
+  * `starboard/` - Cobalt's porting layer. Please see Starboard's
+    [`README.md`](starboard/README.md) for more detailed information about
+    porting Starboard (and Cobalt) to a new platform.
+  * `third_party/` - Where all of Cobalt's third-party dependencies live. We
+    don't mean to be perjorative, we love our third-party libraries! This
+    location is dictated by Google OSS release management rules...
+      * `third_party/starboard/` - The location for third-party ports. This
+        directory will be scanned automatically by gyp_cobalt for available
+        Starboard ports.
+
+
+## Building and Running the Code
+
+Here's a quick and dirty guide to get to build the code on Linux.
+
+  1. Install the provided `depot_tools` archive into your favorite directory. It
+     has been slightly modified from Chromium's `depot_tools`.
+  2. Add that directory to the end of your `$PATH`.
+  3. Ensure you have these packages installed: `sudo apt-get install
+     libgles2-mesa-dev libpulse-dev libavformat-dev libavresample-dev
+     libasound2-dev libxrender-dev libxcomposite-dev`
+  4. Ensure you have the standard C++ header files installed
+     (e.g. `libstdc++-4.8-dev`).
+  5. Remove bison-3 and install bison-2.7, or just make sure that bison-2.7 is
+     before bison-3 on your `$PATH`. (NOTE: We plan on moving to bison-3 in the
+     future.)
+
+         $ sudo apt-get remove bison
+         $ sudo apt-get install m4
+         $ wget http://ftp.gnu.org/gnu/bison/bison-2.7.1.tar.gz
+         $ tar zxf bison-2.7.1.tar.gz
+         $ cd bison-2.7.1
+         $ sh configure && make && sudo make install
+         $ which bison
+         /usr/local/bin/bison
+         $ bison --version
+         bison (GNU Bison) 2.7.12-4996
+
+  6. (From this directory) run GYP:
+
+         cobalt/build/gyp_cobalt -C debug linux-x64x11
+
+  7. If you get a "clang not found" error, add the path to Cobalt's clang to
+     your `$PATH` and rerun `gyp_cobalt` as above. For example:
+     `/path/to/cobalt/src/third_party/llvm-build/Release+Asserts/bin`
+  8. Run Ninja:
+
+         ninja -C out/linux-x64x11_debug cobalt
+
+  9. Run Cobalt:
+
+         out/linux-x64x11_debug/cobalt [--url=<url>]
+
+      * If you want to use `http` instead of `https`, you must pass the
+        `--allow_http` flag to the Cobalt command-line.
+      * If you want to connect to an `https` host that doesn't have a
+        globally-validatable certificate, you must pass the
+        `--ignore_certificate_errors` flag to the Cobalt command-line.
+      * See `cobalt/browser/switches.cc` for more command-line options.
+
+
+## Build Types
+
+Cobalt has four build optimization levels, going from the slowest, least
+optimized, with the most debug information at the top (debug) to the fastest,
+most optimized, and with the least debug information at the bottom (gold):
+
+ | Type  | Optimizations | Logging | Asserts | Debug Info | Console  |
+ | :---- | :------------ | :------ | :------ | :--------- | :------- |
+ | debug | None          | Full    | Full    | Full       | Enabled  |
+ | devel | Full          | Full    | Full    | Full       | Enabled  |
+ | qa    | Full          | Limited | None    | None       | Enabled  |
+ | gold  | Full          | None    | None    | None       | Disabled |
+
+When building for release, you should always use a gold build for the final
+product.
+
+    $ cobalt/build/gyp_cobalt -C gold linux-x64x11
+    $ ninja -C out/linux-x64x11_gold cobalt
+    $ out/linux-x64x11_gold/cobalt
diff --git a/src/base/allocator/README b/src/base/allocator/README
new file mode 100644
index 0000000..ec8a707
--- /dev/null
+++ b/src/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/src/base/allocator/allocator.gyp b/src/base/allocator/allocator.gyp
new file mode 100644
index 0000000..f5bda73
--- /dev/null
+++ b/src/base/allocator/allocator.gyp
@@ -0,0 +1,671 @@
+# Copyright (c) 2012 The Chromium 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': [
+    # Only executables and not libraries should depend on the
+    # allocator target; only the application (the final executable)
+    # knows what allocator makes sense.
+    {
+      'target_name': 'allocator',
+      'type': 'static_library',
+      # 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',
+        'debugallocation_shim.cc',
+        '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',
+
+        # Included by debugallocation_shim.cc.
+        '<(tcmalloc_dir)/src/debugallocation.cc',
+        '<(tcmalloc_dir)/src/tcmalloc.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',
+            },
+          },
+          'variables': {
+            # Provide a way to force disable debugallocation in Debug builds,
+            # e.g. for profiling (it's more rare to profile Debug builds,
+            # but people sometimes need to do that).
+            'disable_debugallocation%': 1,
+          },
+          'conditions': [
+            ['disable_debugallocation==0', {
+              'defines': [
+                # Use debugallocation for Debug builds to catch problems early
+                # and cleanly, http://crbug.com/30715 .
+                'TCMALLOC_FOR_DEBUGALLOCATION',
+              ],
+            }],
+          ],
+        },
+      },
+      '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
+            'debugallocation_shim.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',
+          ],
+        }],
+        ['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_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/src/base/allocator/allocator_extension.cc b/src/base/allocator/allocator_extension.cc
new file mode 100644
index 0000000..83e460a
--- /dev/null
+++ b/src/base/allocator/allocator_extension.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/allocator_extension.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace allocator {
+
+bool GetAllocatorWasteSize(size_t* size) {
+  thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function =
+      thunks::GetGetAllocatorWasteSizeFunction();
+  return get_allocator_waste_size_function != NULL &&
+         get_allocator_waste_size_function(size);
+}
+
+void GetStats(char* buffer, int buffer_length) {
+  DCHECK_GT(buffer_length, 0);
+  thunks::GetStatsFunction get_stats_function = thunks::GetGetStatsFunction();
+  if (get_stats_function)
+    get_stats_function(buffer, buffer_length);
+  else
+    buffer[0] = '\0';
+}
+
+void ReleaseFreeMemory() {
+  thunks::ReleaseFreeMemoryFunction release_free_memory_function =
+      thunks::GetReleaseFreeMemoryFunction();
+  if (release_free_memory_function)
+    release_free_memory_function();
+}
+
+void SetGetAllocatorWasteSizeFunction(
+    thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function) {
+  DCHECK_EQ(thunks::GetGetAllocatorWasteSizeFunction(),
+            reinterpret_cast<thunks::GetAllocatorWasteSizeFunction>(NULL));
+  thunks::SetGetAllocatorWasteSizeFunction(get_allocator_waste_size_function);
+}
+
+void SetGetStatsFunction(thunks::GetStatsFunction get_stats_function) {
+  DCHECK_EQ(thunks::GetGetStatsFunction(),
+            reinterpret_cast<thunks::GetStatsFunction>(NULL));
+  thunks::SetGetStatsFunction(get_stats_function);
+}
+
+void SetReleaseFreeMemoryFunction(
+    thunks::ReleaseFreeMemoryFunction release_free_memory_function) {
+  DCHECK_EQ(thunks::GetReleaseFreeMemoryFunction(),
+            reinterpret_cast<thunks::ReleaseFreeMemoryFunction>(NULL));
+  thunks::SetReleaseFreeMemoryFunction(release_free_memory_function);
+}
+
+}  // namespace allocator
+}  // namespace base
diff --git a/src/base/allocator/allocator_extension.h b/src/base/allocator/allocator_extension.h
new file mode 100644
index 0000000..de3119f
--- /dev/null
+++ b/src/base/allocator/allocator_extension.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H
+#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H
+
+#include <stddef.h> // for size_t
+
+#include "base/allocator/allocator_extension_thunks.h"
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace allocator {
+
+// Request the allocator to report value of its waste memory size.
+// Waste size corresponds to memory that has been allocated from the OS but
+// not passed up to the application. It e.g. includes memory retained by free
+// lists, internal data, chunks padding, etc.
+//
+// |size| pointer to the returned value, must be not NULL.
+// Returns true if the value has been returned, false otherwise.
+BASE_EXPORT bool GetAllocatorWasteSize(size_t* size);
+
+// Request that the allocator print a human-readable description of the current
+// state of the allocator into a null-terminated string in the memory segment
+// buffer[0,buffer_length-1].
+//
+// |buffer| must point to a valid piece of memory
+// |buffer_length| must be > 0.
+BASE_EXPORT void GetStats(char* buffer, int buffer_length);
+
+// Request that the allocator release any free memory it knows about to the
+// system.
+BASE_EXPORT void ReleaseFreeMemory();
+
+
+// These settings allow specifying a callback used to implement the allocator
+// extension functions.  These are optional, but if set they must only be set
+// once.  These will typically called in an allocator-specific initialization
+// routine.
+//
+// No threading promises are made.  The caller is responsible for making sure
+// these pointers are set before any other threads attempt to call the above
+// functions.
+BASE_EXPORT void SetGetAllocatorWasteSizeFunction(
+    thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function);
+
+BASE_EXPORT void SetGetStatsFunction(
+    thunks::GetStatsFunction get_stats_function);
+
+BASE_EXPORT void SetReleaseFreeMemoryFunction(
+    thunks::ReleaseFreeMemoryFunction release_free_memory_function);
+
+}  // namespace allocator
+}  // namespace base
+
+#endif
diff --git a/src/base/allocator/allocator_extension_thunks.cc b/src/base/allocator/allocator_extension_thunks.cc
new file mode 100644
index 0000000..e4024fb
--- /dev/null
+++ b/src/base/allocator/allocator_extension_thunks.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/allocator_extension_thunks.h"
+
+#include <cstddef> // for NULL
+
+namespace base {
+namespace allocator {
+namespace thunks {
+
+// This slightly odd translation unit exists because of the peculularity of how
+// allocator_unittests work on windows.  That target has to perform
+// tcmalloc-specific initialization on windows, but it cannot depend on base
+// otherwise. This target sits in the middle - base and allocator_unittests
+// can depend on it. This file can't depend on anything else in base, including
+// logging.
+
+static GetAllocatorWasteSizeFunction g_get_allocator_waste_size_function = NULL;
+static GetStatsFunction g_get_stats_function = NULL;
+static ReleaseFreeMemoryFunction g_release_free_memory_function = NULL;
+
+void SetGetAllocatorWasteSizeFunction(
+    GetAllocatorWasteSizeFunction get_allocator_waste_size_function) {
+  g_get_allocator_waste_size_function = get_allocator_waste_size_function;
+}
+
+GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction() {
+  return g_get_allocator_waste_size_function;
+}
+
+void SetGetStatsFunction(GetStatsFunction get_stats_function) {
+  g_get_stats_function = get_stats_function;
+}
+
+GetStatsFunction GetGetStatsFunction() {
+  return g_get_stats_function;
+}
+
+void SetReleaseFreeMemoryFunction(
+    ReleaseFreeMemoryFunction release_free_memory_function) {
+  g_release_free_memory_function = release_free_memory_function;
+}
+
+ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction() {
+  return g_release_free_memory_function;
+}
+
+}  // namespace thunks
+}  // namespace allocator
+}  // namespace base
diff --git a/src/base/allocator/allocator_extension_thunks.h b/src/base/allocator/allocator_extension_thunks.h
new file mode 100644
index 0000000..1e97a84
--- /dev/null
+++ b/src/base/allocator/allocator_extension_thunks.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_ALLOCATOR_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 (*GetAllocatorWasteSizeFunction)(size_t* size);
+void SetGetAllocatorWasteSizeFunction(
+    GetAllocatorWasteSizeFunction get_allocator_waste_size_function);
+GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction();
+
+typedef void (*GetStatsFunction)(char* buffer, int buffer_length);
+void SetGetStatsFunction(GetStatsFunction get_stats_function);
+GetStatsFunction GetGetStatsFunction();
+
+typedef void (*ReleaseFreeMemoryFunction)();
+void SetReleaseFreeMemoryFunction(
+    ReleaseFreeMemoryFunction release_free_memory_function);
+ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction();
+
+}  // namespace thunks
+}  // namespace allocator
+}  // namespace base
+
+#endif
diff --git a/src/base/allocator/allocator_shim.cc b/src/base/allocator/allocator_shim.cc
new file mode 100644
index 0000000..6e41327
--- /dev/null
+++ b/src/base/allocator/allocator_shim.cc
@@ -0,0 +1,431 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "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 "debugallocation_shim.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_allocator_waste_size_thunk(size_t* size) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+  switch (allocator) {
+    case JEMALLOC:
+    case WINHEAP:
+    case WINLFH:
+      // TODO(alexeif): Implement for allocators other than tcmalloc.
+      return false;
+  }
+#endif
+  size_t heap_size, allocated_bytes, unmapped_bytes;
+  MallocExtension* ext = MallocExtension::instance();
+  if (ext->GetNumericProperty("generic.heap_size", &heap_size) &&
+      ext->GetNumericProperty("generic.current_allocated_bytes",
+                              &allocated_bytes) &&
+      ext->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes",
+                              &unmapped_bytes)) {
+    *size = heap_size - allocated_bytes - unmapped_bytes;
+    return true;
+  }
+  return false;
+}
+
+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::SetGetAllocatorWasteSizeFunction(
+      get_allocator_waste_size_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/src/base/allocator/allocator_shim.h b/src/base/allocator/allocator_shim.h
new file mode 100644
index 0000000..e10fa8d
--- /dev/null
+++ b/src/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/src/base/allocator/allocator_unittests.cc b/src/base/allocator/allocator_unittests.cc
new file mode 100644
index 0000000..3c455ba
--- /dev/null
+++ b/src/base/allocator/allocator_unittests.cc
@@ -0,0 +1,555 @@
+// Copyright (c) 2012 The Chromium Authors. 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);
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+// 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);
+#endif
+
+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;
+  }
+}
+
+#if defined(__LB_SHELL__) || defined(OS_STARBOARD)
+#if defined(GG_ULONGLONG)
+// GG_ULONGLONG is already defined in base/port.h
+#undef GG_ULONGLONG
+#endif
+
+// namespace resolution for typedefs
+using base::subtle::AtomicWord;
+using base::subtle::Atomic32;
+#endif
+
+#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 {
+  // TODO(__LB_SHELL__): This behavior is not defined by c++ standard.
+  // However it is possible that chromium expects it. We need to make sure
+  // these functions work the same way as expected by chromium when we override
+  // memory functions.
+    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);
+  }
+}
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+// Exceptions are disabled on lbshell and Starboard.
+
+// 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);
+}
+#endif
+}  // 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);
+}
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+// Exceptions are disabled on lbshell.
+TEST(Allocators, New) {
+  TestNothrowNew(&::operator new);
+  TestNothrowNew(&::operator new[]);
+}
+#endif
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+// The test assumes the memory space to be very empty
+// and doesn't work on lb_shell platforms.
+
+// 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);
+  }
+}
+#endif
+
+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);
+}
+
+// TODO(__LB_SHELL__): This behavior is not defined by c++ standard.
+// However it is possible that chromium expects it. We need to make sure
+// these functions work the same way as expected by chromium when we override
+// memory functions.
+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
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+// main defined in run_all_unittests
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
+#endif
diff --git a/src/base/allocator/debugallocation_shim.cc b/src/base/allocator/debugallocation_shim.cc
new file mode 100644
index 0000000..d1cf52a
--- /dev/null
+++ b/src/base/allocator/debugallocation_shim.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(TCMALLOC_FOR_DEBUGALLOCATION)
+#include "third_party/tcmalloc/chromium/src/debugallocation.cc"
+#else
+#include "third_party/tcmalloc/chromium/src/tcmalloc.cc"
+#endif
diff --git a/src/base/allocator/generic_allocators.cc b/src/base/allocator/generic_allocators.cc
new file mode 100644
index 0000000..d4cf19e
--- /dev/null
+++ b/src/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/src/base/allocator/prep_libc.py b/src/base/allocator/prep_libc.py
new file mode 100755
index 0000000..be7030f
--- /dev/null
+++ b/src/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/src/base/allocator/tcmalloc_unittest.cc b/src/base/allocator/tcmalloc_unittest.cc
new file mode 100644
index 0000000..053a9d5
--- /dev/null
+++ b/src/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/src/base/allocator/type_profiler.cc b/src/base/allocator/type_profiler.cc
new file mode 100644
index 0000000..635fbcf
--- /dev/null
+++ b/src/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/src/base/allocator/type_profiler.h b/src/base/allocator/type_profiler.h
new file mode 100644
index 0000000..86b5711
--- /dev/null
+++ b/src/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/src/base/allocator/type_profiler_control.cc b/src/base/allocator/type_profiler_control.cc
new file mode 100644
index 0000000..6be7984
--- /dev/null
+++ b/src/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/src/base/allocator/type_profiler_control.h b/src/base/allocator/type_profiler_control.h
new file mode 100644
index 0000000..17cf5b6
--- /dev/null
+++ b/src/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/src/base/allocator/type_profiler_map_unittests.cc b/src/base/allocator/type_profiler_map_unittests.cc
new file mode 100644
index 0000000..ff74e11
--- /dev/null
+++ b/src/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
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
+
+#endif  // defined(TYPE_PROFILING)
diff --git a/src/base/allocator/type_profiler_tcmalloc.cc b/src/base/allocator/type_profiler_tcmalloc.cc
new file mode 100644
index 0000000..e5e10e0
--- /dev/null
+++ b/src/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/src/base/allocator/type_profiler_tcmalloc.h b/src/base/allocator/type_profiler_tcmalloc.h
new file mode 100644
index 0000000..ac55995
--- /dev/null
+++ b/src/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/src/base/allocator/type_profiler_unittests.cc b/src/base/allocator/type_profiler_unittests.cc
new file mode 100644
index 0000000..16af86d
--- /dev/null
+++ b/src/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
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
+
+#endif  // defined(TYPE_PROFILING)
diff --git a/src/base/allocator/unittest_utils.cc b/src/base/allocator/unittest_utils.cc
new file mode 100644
index 0000000..130ba15
--- /dev/null
+++ b/src/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/src/base/allocator/win_allocator.cc b/src/base/allocator/win_allocator.cc
new file mode 100644
index 0000000..899b867
--- /dev/null
+++ b/src/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/src/base/android/base_jni_registrar.cc b/src/base/android/base_jni_registrar.cc
new file mode 100644
index 0000000..2395d98
--- /dev/null
+++ b/src/base/android/base_jni_registrar.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/android/base_jni_registrar.h"
+
+#include "base/basictypes.h"
+#include "base/android/build_info.h"
+#include "base/android/cpu_features.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 },
+  { "CpuFeatures", base::android::RegisterCpuFeatures },
+  { "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/src/base/android/base_jni_registrar.h b/src/base/android/base_jni_registrar.h
new file mode 100644
index 0000000..fdaf5f2
--- /dev/null
+++ b/src/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/src/base/android/build_info.cc b/src/base/android/build_info.cc
new file mode 100644
index 0000000..cdde6a9
--- /dev/null
+++ b/src/base/android/build_info.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/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()))),
+      sdk_int_(Java_BuildInfo_getSdkInt(env)),
+      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/src/base/android/build_info.h b/src/base/android/build_info.h
new file mode 100644
index 0000000..6273d3e
--- /dev/null
+++ b/src/base/android/build_info.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_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_;
+  }
+
+  int sdk_int() const {
+    return sdk_int_;
+  }
+
+  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_;
+  const int sdk_int_;
+  // This is set via set_java_exception_info, not at constructor time.
+  const char* java_exception_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(BuildInfo);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_BUILD_INFO_H_
diff --git a/src/base/android/cpu_features.cc b/src/base/android/cpu_features.cc
new file mode 100644
index 0000000..6a18695
--- /dev/null
+++ b/src/base/android/cpu_features.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cpu-features.h>
+
+#include "base/android/jni_android.h"
+#include "jni/CpuFeatures_jni.h"
+
+namespace base {
+namespace android {
+
+jint GetCoreCount(JNIEnv*, jclass) {
+  return android_getCpuCount();
+}
+
+jlong GetCpuFeatures(JNIEnv*, jclass) {
+  return android_getCpuFeatures();
+}
+
+bool RegisterCpuFeatures(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/src/base/android/cpu_features.h b/src/base/android/cpu_features.h
new file mode 100644
index 0000000..0a27822
--- /dev/null
+++ b/src/base/android/cpu_features.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_CPU_FEATURES_H_
+#define BASE_ANDROID_CPU_FEATURES_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterCpuFeatures(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_CPU_FEATURES_H_
diff --git a/src/base/android/java/src/org/chromium/base/AccessedByNative.java b/src/base/android/java/src/org/chromium/base/AccessedByNative.java
new file mode 100644
index 0000000..8248cc6
--- /dev/null
+++ b/src/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/src/base/android/java/src/org/chromium/base/ActivityStatus.java b/src/base/android/java/src/org/chromium/base/ActivityStatus.java
new file mode 100644
index 0000000..e728870
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/ActivityStatus.java
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.os.Looper;
+
+import java.util.ArrayList;
+
+/**
+ * Provides information about the parent activity's status.
+ */
+public class ActivityStatus {
+
+    // Constants matching activity states reported to StateListener.onStateChange
+    public static final int CREATED = 1;
+    public static final int STARTED = 2;
+    public static final int RESUMED = 3;
+    public static final int PAUSED = 4;
+    public static final int STOPPED = 5;
+    public static final int DESTROYED = 6;
+
+    // Current main activity, or null if none.
+    private static Activity sActivity;
+
+    // Current main activity's state. This can be set even if sActivity is null, to simplify unit
+    // testing.
+    private static int sActivityState;
+
+    private static final ArrayList<StateListener> sStateListeners = new ArrayList<StateListener>();
+
+    // Use this interface to listen to all state changes.
+    public interface StateListener {
+        /**
+         * Called when the activity's state changes.
+         * @param newState New activity state.
+         */
+        public void onActivityStateChange(int newState);
+    }
+
+    private ActivityStatus() {}
+
+    /**
+     * Must be called by the main activity when it changes state.
+     * @param activity Current activity.
+     * @param newState New state value.
+     */
+    public static void onStateChange(Activity activity, int newState) {
+        if (newState == CREATED) {
+            sActivity = activity;
+        }
+        sActivityState = newState;
+        for (StateListener listener : sStateListeners) {
+            listener.onActivityStateChange(newState);
+        }
+        if (newState == DESTROYED) {
+            sActivity = null;
+        }
+    }
+
+    /**
+     * Indicates that the parent activity is currently paused.
+     */
+    public static boolean isPaused() {
+        return sActivityState == PAUSED;
+    }
+
+    /**
+     * Returns the current main application activity.
+     */
+    public static Activity getActivity() {
+        return sActivity;
+    }
+
+    /**
+     * Returns the current main application activity's state.
+     */
+    public static int getState() {
+        return sActivityState;
+    }
+
+    /**
+     * Registers the given listener to receive activity state changes.
+     * @param listener Listener to receive state changes.
+     */
+    public static void registerStateListener(StateListener listener) {
+        sStateListeners.add(listener);
+    }
+
+    /**
+     * Unregisters the given listener from receiving activity state changes.
+     * @param listener Listener that doesn't want to receive state changes.
+     */
+    public static void unregisterStateListener(StateListener listener) {
+        sStateListeners.remove(listener);
+    }
+}
diff --git a/src/base/android/java/src/org/chromium/base/BuildInfo.java b/src/base/android/java/src/org/chromium/base/BuildInfo.java
new file mode 100644
index 0000000..2314051
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -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.
+
+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 : "";
+    }
+
+    @CalledByNative
+    public static int getSdkInt() {
+        return Build.VERSION.SDK_INT;
+    }
+}
diff --git a/src/base/android/java/src/org/chromium/base/CalledByNative.java b/src/base/android/java/src/org/chromium/base/CalledByNative.java
new file mode 100644
index 0000000..8d3dcad
--- /dev/null
+++ b/src/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/src/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java b/src/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java
new file mode 100644
index 0000000..cc264a2
--- /dev/null
+++ b/src/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/src/base/android/java/src/org/chromium/base/ChromiumActivity.java b/src/base/android/java/src/org/chromium/base/ChromiumActivity.java
new file mode 100644
index 0000000..65f5ce9
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/ChromiumActivity.java
@@ -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.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+// All Chromium main activities should extend this class. This allows various sub-systems to
+// properly react to activity state changes.
+public class ChromiumActivity extends Activity {
+
+  @Override
+  protected void onCreate(Bundle savedInstance) {
+    super.onCreate(savedInstance);
+    ActivityStatus.onStateChange(this, ActivityStatus.CREATED);
+  }
+
+  @Override
+  protected void onStart() {
+    super.onStart();
+    ActivityStatus.onStateChange(this, ActivityStatus.STARTED);
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    ActivityStatus.onStateChange(this, ActivityStatus.RESUMED);
+  }
+
+  @Override
+  protected void onPause() {
+    ActivityStatus.onStateChange(this, ActivityStatus.PAUSED);
+    super.onPause();
+  }
+
+  @Override
+  protected void onStop() {
+    ActivityStatus.onStateChange(this, ActivityStatus.STOPPED);
+    super.onStop();
+  }
+
+  @Override
+  protected void onDestroy() {
+    ActivityStatus.onStateChange(this, ActivityStatus.DESTROYED);
+    super.onDestroy();
+  }
+}
diff --git a/src/base/android/java/src/org/chromium/base/CpuFeatures.java b/src/base/android/java/src/org/chromium/base/CpuFeatures.java
new file mode 100644
index 0000000..f298fb1
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/CpuFeatures.java
@@ -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.
+
+package org.chromium.base;
+
+// The only purpose of this class is to allow sending CPU properties
+// from the browser process to sandboxed renderer processes. This is
+// needed because sandboxed processes cannot, on ARM, query the kernel
+// about the CPU's properties by parsing /proc, so this operation must
+// be performed in the browser process, and the result passed to
+// renderer ones.
+//
+// For more context, see http://crbug.com/164154
+//
+// Technically, this is a wrapper around the native NDK cpufeatures
+// library. The exact CPU features bits are never used in Java so
+// there is no point in duplicating their definitions here.
+//
+@JNINamespace("base::android")
+public abstract class CpuFeatures {
+    /**
+     * Return the number of CPU Cores on the device.
+     */
+    public static int getCount() {
+        return nativeGetCoreCount();
+    }
+
+    /**
+     * Return the CPU feature mask.
+     * This is a 64-bit integer that corresponds to the CPU's features.
+     * The value comes directly from android_getCpuFeatures().
+     */
+     public static long getMask() {
+        return nativeGetCpuFeatures();
+     }
+
+    private static native int nativeGetCoreCount();
+    private static native long nativeGetCpuFeatures();
+}
diff --git a/src/base/android/java/src/org/chromium/base/JNINamespace.java b/src/base/android/java/src/org/chromium/base/JNINamespace.java
new file mode 100644
index 0000000..cfffc91
--- /dev/null
+++ b/src/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/src/base/android/java/src/org/chromium/base/LocaleUtils.java b/src/base/android/java/src/org/chromium/base/LocaleUtils.java
new file mode 100644
index 0000000..6bca1f7
--- /dev/null
+++ b/src/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/src/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java b/src/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
new file mode 100644
index 0000000..309169b
--- /dev/null
+++ b/src/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/src/base/android/java/src/org/chromium/base/PathService.java b/src/base/android/java/src/org/chromium/base/PathService.java
new file mode 100644
index 0000000..dfda736
--- /dev/null
+++ b/src/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/src/base/android/java/src/org/chromium/base/PathUtils.java b/src/base/android/java/src/org/chromium/base/PathUtils.java
new file mode 100644
index 0000000..c3503a4
--- /dev/null
+++ b/src/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/src/base/android/java/src/org/chromium/base/PowerStatusReceiver.java b/src/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
new file mode 100644
index 0000000..89594b8
--- /dev/null
+++ b/src/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/src/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/src/base/android/java/src/org/chromium/base/SystemMessageHandler.java
new file mode 100644
index 0000000..f7bb19f
--- /dev/null
+++ b/src/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/src/base/android/java/src/org/chromium/base/SystemMonitor.java b/src/base/android/java/src/org/chromium/base/SystemMonitor.java
new file mode 100644
index 0000000..30f61a6
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/SystemMonitor.java
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.Looper;
+
+
+/**
+ * Integrates native SystemMonitor with the java side.
+ */
+@JNINamespace("base::android")
+public class SystemMonitor implements ActivityStatus.StateListener {
+    private static final long SUSPEND_DELAY_MS = 1 * 60 * 1000;  // 1 minute.
+    private static SystemMonitor sInstance;
+
+    private boolean mIsBatteryPower;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    // Asynchronous task used to fire the "paused" event to the native side 1 minute after the main
+    // activity transitioned to the "paused" state. This event is not sent immediately because it
+    // would be too aggressive. An Android activity can be in the "paused" state quite often. This
+    // can happen when a dialog window shows up for instance.
+    private static final Runnable sSuspendTask = new Runnable() {
+            @Override
+            public void run() {
+                nativeOnMainActivitySuspended();
+            }
+        };
+
+    public static void createForTests(Context context) {
+        // Applications will create this once the JNI side has been fully wired up both sides. For
+        // tests, we just need native -> java, that is, we don't need to notify java -> native on
+        // creation.
+        sInstance = new SystemMonitor();
+    }
+
+    public static void create(Context context) {
+        if (sInstance == null) {
+            sInstance = new SystemMonitor();
+            ActivityStatus.registerStateListener(sInstance);
+            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();
+    }
+
+    @Override
+    public void onActivityStateChange(int newState) {
+        if (newState == ActivityStatus.RESUMED) {
+            // Remove the callback from the message loop in case it hasn't been executed yet.
+            mHandler.removeCallbacks(sSuspendTask);
+            nativeOnMainActivityResumed();
+        } else if (newState == ActivityStatus.PAUSED) {
+            mHandler.postDelayed(sSuspendTask, SUSPEND_DELAY_MS);
+        }
+    }
+
+    @CalledByNative
+    private static boolean isBatteryPower() {
+        return sInstance.mIsBatteryPower;
+    }
+
+    private static native void nativeOnBatteryChargingChanged();
+    private static native void nativeOnMainActivitySuspended();
+    private static native void nativeOnMainActivityResumed();
+}
diff --git a/src/base/android/java/src/org/chromium/base/ThreadUtils.java b/src/base/android/java/src/org/chromium/base/ThreadUtils.java
new file mode 100644
index 0000000..70232c4
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -0,0 +1,152 @@
+// Copyright (c) 2012 The Chromium 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;
+    }
+
+    /**
+     * Post the supplied Runnable to run on the main thread. The method will
+     * not block, even if called on the UI thread.
+     *
+     * @param task The Runnable to run
+     */
+    public static void postOnUiThread(Runnable r) {
+        LazyHolder.sUiThreadHandler.post(r);
+    }
+
+    /**
+     * 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/src/base/android/java/src/org/chromium/base/WeakContext.java b/src/base/android/java/src/org/chromium/base/WeakContext.java
new file mode 100644
index 0000000..d660cc9
--- /dev/null
+++ b/src/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/src/base/android/jni_android.cc b/src/base/android/jni_android.cc
new file mode 100644
index 0000000..fdc2170
--- /dev/null
+++ b/src/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/src/base/android/jni_android.h b/src/base/android/jni_android.h
new file mode 100644
index 0000000..16b85af
--- /dev/null
+++ b/src/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/src/base/android/jni_android_unittest.cc b/src/base/android/jni_android_unittest.cc
new file mode 100644
index 0000000..920b395
--- /dev/null
+++ b/src/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/src/base/android/jni_array.cc b/src/base/android/jni_array.cc
new file mode 100644
index 0000000..fe2aadb
--- /dev/null
+++ b/src/base/android/jni_array.cc
@@ -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.
+
+#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);
+  size_t back = out->size();
+  out->resize(back + len);
+  for (jsize i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jstring> str(env,
+        static_cast<jstring>(env->GetObjectArrayElement(array, i)));
+    ConvertJavaStringToUTF16(env, str.obj(), &((*out)[back + i]));
+  }
+}
+
+void AppendJavaStringArrayToStringVector(JNIEnv* env,
+                                         jobjectArray array,
+                                         std::vector<std::string>* out) {
+  DCHECK(out);
+  if (!array)
+    return;
+  jsize len = env->GetArrayLength(array);
+  size_t back = out->size();
+  out->resize(back + len);
+  for (jsize i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jstring> str(env,
+        static_cast<jstring>(env->GetObjectArrayElement(array, i)));
+    ConvertJavaStringToUTF8(env, str.obj(), &((*out)[back + i]));
+  }
+}
+
+void AppendJavaByteArrayToByteVector(JNIEnv* env,
+                                     jbyteArray byte_array,
+                                     std::vector<uint8>* out) {
+  DCHECK(out);
+  if (!byte_array)
+    return;
+  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);
+}
+
+void JavaArrayOfByteArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::string>* out) {
+  DCHECK(out);
+  out->clear();
+  jsize len = env->GetArrayLength(array);
+  out->resize(len);
+  for (jsize i = 0; i < len; ++i) {
+    jbyteArray bytes_array = static_cast<jbyteArray>(
+        env->GetObjectArrayElement(array, i));
+    jsize bytes_len = env->GetArrayLength(bytes_array);
+    jbyte* bytes = env->GetByteArrayElements(bytes_array, NULL);
+    (*out)[i].assign(reinterpret_cast<const char*>(bytes), bytes_len);
+    env->ReleaseByteArrayElements(bytes_array, bytes, JNI_ABORT);
+  }
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/src/base/android/jni_array.h b/src/base/android/jni_array.h
new file mode 100644
index 0000000..fbc131e
--- /dev/null
+++ b/src/base/android/jni_array.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_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);
+
+// Assuming |array| is an byte[][] (array of byte arrays), replaces the
+// content of |out| with the corresponding vector of strings. No UTF-8
+// conversion is performed.
+void JavaArrayOfByteArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::string>* out);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_ARRAY_H_
diff --git a/src/base/android/jni_array_unittest.cc b/src/base/android/jni_array_unittest.cc
new file mode 100644
index 0000000..a4e3025
--- /dev/null
+++ b/src/base/android/jni_array_unittest.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/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());
+}
+
+TEST(JniArray, JavaArrayOfByteArrayToStringVector) {
+  const int kMaxItems = 50;
+  JNIEnv* env = AttachCurrentThread();
+
+  // Create a byte[][] object.
+  ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
+  ASSERT_TRUE(byte_array_clazz.obj());
+
+  ScopedJavaLocalRef<jobjectArray> array(
+      env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), NULL));
+  ASSERT_TRUE(array.obj());
+
+  // Create kMaxItems byte buffers.
+  char text[16];
+  for (int i = 0; i < kMaxItems; ++i) {
+    snprintf(text, sizeof text, "%d", i);
+    ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(
+        env, reinterpret_cast<uint8*>(text),
+        static_cast<size_t>(strlen(text)));
+    ASSERT_TRUE(byte_array.obj());
+
+    env->SetObjectArrayElement(array.obj(), i, byte_array.obj());
+    ASSERT_FALSE(HasException(env));
+  }
+
+  // Convert to std::vector<std::string>, check the content.
+  std::vector<std::string> vec;
+  JavaArrayOfByteArrayToStringVector(env, array.obj(), &vec);
+
+  EXPECT_EQ(static_cast<size_t>(kMaxItems), vec.size());
+  for (int i = 0; i < kMaxItems; ++i) {
+    snprintf(text, sizeof text, "%d", i);
+    EXPECT_STREQ(text, vec[i].c_str());
+  }
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/src/base/android/jni_generator/SampleForTests.java b/src/base/android/jni_generator/SampleForTests.java
new file mode 100644
index 0000000..341f0ea
--- /dev/null
+++ b/src/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/src/base/android/jni_generator/golden_sample_for_tests_jni.h b/src/base/android/jni_generator/golden_sample_for_tests_jni.h
new file mode 100644
index 0000000..08f25a7
--- /dev/null
+++ b/src/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/src/base/android/jni_generator/jni_generator.gyp b/src/base/android/jni_generator/jni_generator.gyp
new file mode 100644
index 0000000..dc32d22
--- /dev/null
+++ b/src/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/src/base/android/jni_generator/jni_generator.py b/src/base/android/jni_generator/jni_generator.py
new file mode 100755
index 0000000..18312c6
--- /dev/null
+++ b/src/base/android/jni_generator/jni_generator.py
@@ -0,0 +1,1005 @@
+#!/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',
+      'Class': 'jclass',
+      'java/lang/Class': 'jclass',
+  }
+
+  if java_type in java_pod_type_map:
+    return java_pod_type_map[java_type]
+  elif java_type in java_type_map:
+    return java_type_map[java_type]
+  elif java_type.endswith('[]'):
+    if java_type[:-2] in java_pod_type_map:
+      return java_pod_type_map[java_type[:-2]] + 'Array'
+    return 'jobjectArray'
+  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',
+        'Ljava/lang/Class',
+    ]
+    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._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 + ';'
+
+    # Is it from an import? (e.g. referecing Class from import pkg.Class;
+    # note that referencing an inner class Inner from import pkg.Class.Inner
+    # is not supported).
+    for qualified_name in JniParams._imports:
+      if qualified_name.endswith('/' + param):
+        # Ensure it's not an inner class.
+        components = qualified_name.split('/')
+        if len(components) > 2 and components[-2][0].isupper():
+          raise SyntaxError('Inner class (%s) can not be imported '
+                            'and used by JNI (%s). Please import the outer '
+                            'class and use Outer.Inner instead.' %
+                            (qualified_name, param))
+        return prefix + qualified_name + ';'
+
+    # Is it an inner class from an outer class import? (e.g. referencing
+    # Class.Inner from import pkg.Class).
+    if '.' in param:
+      components = param.split('.')
+      outer = '/'.join(components[:-1])
+      inner = components[-1]
+      for qualified_name in JniParams._imports:
+        if qualified_name.endswith('/' + outer):
+          return prefix + qualified_name + '$' + inner
+
+    # 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/src/base/android/jni_generator/jni_generator_tests.py b/src/base/android/jni_generator/jni_generator_tests.py
new file mode 100755
index 0000000..5863977
--- /dev/null
+++ b/src/base/android/jni_generator/jni_generator_tests.py
@@ -0,0 +1,1590 @@
+#!/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 org.chromium.content.common.WillNotRaise.AnException;
+import org.chromium.content.common.WillRaise.AnException;
+
+import static org.chromium.Bar.Zoo;
+
+class Foo {
+  public static class BookmarkNode implements Parcelable {
+  }
+  public interface PasswordListObserver {
+  }
+}
+    """
+    jni_generator.JniParams.SetFullyQualifiedClass(
+        'org/chromium/content/app/Foo')
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(import_header)
+    self.assertTrue('Lorg/chromium/content/common/ISandboxedProcessService' in
+                    jni_generator.JniParams._imports)
+    self.assertTrue('Lorg/chromium/Bar/Zoo' in
+                    jni_generator.JniParams._imports)
+    self.assertTrue('Lorg/chromium/content/app/Foo$BookmarkNode' in
+                    jni_generator.JniParams._inner_classes)
+    self.assertTrue('Lorg/chromium/content/app/Foo$PasswordListObserver' in
+                    jni_generator.JniParams._inner_classes)
+    self.assertEquals('Lorg/chromium/content/app/ContentMain$Inner',
+                      jni_generator.JniParams.JavaToJni('ContentMain.Inner'))
+    self.assertRaises(SyntaxError,
+                      jni_generator.JniParams.JavaToJni,
+                      'AnException')
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/src/base/android/jni_generator/sample_for_tests.cc b/src/base/android/jni_generator/sample_for_tests.cc
new file mode 100644
index 0000000..5b5cfc5
--- /dev/null
+++ b/src/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/src/base/android/jni_helper.cc b/src/base/android/jni_helper.cc
new file mode 100644
index 0000000..c0833c9
--- /dev/null
+++ b/src/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/src/base/android/jni_helper.h b/src/base/android/jni_helper.h
new file mode 100644
index 0000000..895bf95
--- /dev/null
+++ b/src/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/src/base/android/jni_registrar.cc b/src/base/android/jni_registrar.cc
new file mode 100644
index 0000000..696924a
--- /dev/null
+++ b/src/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/src/base/android/jni_registrar.h b/src/base/android/jni_registrar.h
new file mode 100644
index 0000000..849d07f
--- /dev/null
+++ b/src/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/src/base/android/jni_string.cc b/src/base/android/jni_string.cc
new file mode 100644
index 0000000..ac3975f
--- /dev/null
+++ b/src/base/android/jni_string.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+#include "base/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 {
+
+void ConvertJavaStringToUTF8(JNIEnv* env, jstring str, std::string* result) {
+  if (!str) {
+    LOG(WARNING) << "ConvertJavaStringToUTF8 called with null string.";
+    result->clear();
+    return;
+  }
+  // JNI's GetStringUTFChars() returns strings in Java "modified" UTF8, so
+  // instead get the String in UTF16 and convert using chromium's conversion
+  // function that yields plain (non Java-modified) UTF8.
+  const jchar* chars = env->GetStringChars(str, NULL);
+  DCHECK(chars);
+  UTF16ToUTF8(chars, env->GetStringLength(str), result);
+  env->ReleaseStringChars(str, chars);
+  CheckException(env);
+}
+
+std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) {
+  std::string result;
+  ConvertJavaStringToUTF8(env, str, &result);
+  return result;
+}
+
+std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str) {
+  return ConvertJavaStringToUTF8(AttachCurrentThread(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece& str) {
+  // JNI's NewStringUTF expects "modified" UTF8 so instead create the string
+  // via our own UTF16 conversion utility.
+  // Further, Dalvik requires the string passed into NewStringUTF() to come from
+  // a trusted source. We can't guarantee that all UTF8 will be sanitized before
+  // it gets here, so constructing via UTF16 side-steps this issue.
+  // (Dalvik stores strings internally as UTF16 anyway, so there shouldn't be
+  // a significant performance hit by doing it this way).
+  return ScopedJavaLocalRef<jstring>(env, ConvertUTF16ToJavaStringImpl(
+      env, UTF8ToUTF16(str)));
+}
+
+void ConvertJavaStringToUTF16(JNIEnv* env, jstring str, string16* result) {
+  if (!str) {
+    LOG(WARNING) << "ConvertJavaStringToUTF16 called with null string.";
+    result->clear();
+    return;
+  }
+  const jchar* chars = env->GetStringChars(str, NULL);
+  DCHECK(chars);
+  // GetStringChars isn't required to NULL-terminate the strings
+  // it returns, so the length must be explicitly checked.
+  result->assign(chars, env->GetStringLength(str));
+  env->ReleaseStringChars(str, chars);
+  CheckException(env);
+}
+
+string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) {
+  string16 result;
+  ConvertJavaStringToUTF16(env, str, &result);
+  return result;
+}
+
+string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str) {
+  return ConvertJavaStringToUTF16(AttachCurrentThread(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece16& str) {
+  return ScopedJavaLocalRef<jstring>(env,
+                                     ConvertUTF16ToJavaStringImpl(env, str));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/src/base/android/jni_string.h b/src/base/android/jni_string.h
new file mode 100644
index 0000000..222b78d
--- /dev/null
+++ b/src/base/android/jni_string.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_STRING_H_
+#define BASE_ANDROID_JNI_STRING_H_
+
+#include <jni.h>
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+#include "base/string_piece.h"
+
+namespace base {
+namespace android {
+
+// Convert a Java string to UTF8. Returns a std string.
+BASE_EXPORT void ConvertJavaStringToUTF8(JNIEnv* env,
+                                         jstring str,
+                                         std::string* result);
+BASE_EXPORT std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str);
+BASE_EXPORT std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str);
+
+// Convert a std string to Java string.
+BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece& str);
+
+// Convert a Java string to UTF16. Returns a string16.
+BASE_EXPORT void ConvertJavaStringToUTF16(JNIEnv* env,
+                                          jstring str,
+                                          string16* result);
+BASE_EXPORT string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str);
+BASE_EXPORT string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str);
+
+// Convert a string16 to a Java string.
+BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece16& str);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_STRING_H_
diff --git a/src/base/android/jni_string_unittest.cc b/src/base/android/jni_string_unittest.cc
new file mode 100644
index 0000000..59a847e
--- /dev/null
+++ b/src/base/android/jni_string_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(JniString, BasicConversionsUTF8) {
+  const std::string kSimpleString = "SimpleTest8";
+  JNIEnv* env = AttachCurrentThread();
+  std::string result =
+      ConvertJavaStringToUTF8(ConvertUTF8ToJavaString(env, kSimpleString));
+  EXPECT_EQ(kSimpleString, result);
+}
+
+TEST(JniString, BasicConversionsUTF16) {
+  const string16 kSimpleString = UTF8ToUTF16("SimpleTest16");
+  JNIEnv* env = AttachCurrentThread();
+  string16 result =
+      ConvertJavaStringToUTF16(ConvertUTF16ToJavaString(env, kSimpleString));
+  EXPECT_EQ(kSimpleString, result);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/src/base/android/locale_utils.cc b/src/base/android/locale_utils.cc
new file mode 100644
index 0000000..60b8f84
--- /dev/null
+++ b/src/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/src/base/android/locale_utils.h b/src/base/android/locale_utils.h
new file mode 100644
index 0000000..cef39f4
--- /dev/null
+++ b/src/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/src/base/android/path_service_android.cc b/src/base/android/path_service_android.cc
new file mode 100644
index 0000000..a9bf92d
--- /dev/null
+++ b/src/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/src/base/android/path_service_android.h b/src/base/android/path_service_android.h
new file mode 100644
index 0000000..26040f9
--- /dev/null
+++ b/src/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/src/base/android/path_utils.cc b/src/base/android/path_utils.cc
new file mode 100644
index 0000000..3d86177
--- /dev/null
+++ b/src/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/src/base/android/path_utils.h b/src/base/android/path_utils.h
new file mode 100644
index 0000000..78f0267
--- /dev/null
+++ b/src/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'.
+BASE_EXPORT bool GetNativeLibraryDirectory(FilePath* result);
+
+// Retrieves the absolute path to the external storage directory. The result
+// is placed in the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetExternalStorageDirectory(FilePath* result);
+
+bool RegisterPathUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_PATH_UTILS_H_
diff --git a/src/base/android/path_utils_unittest.cc b/src/base/android/path_utils_unittest.cc
new file mode 100644
index 0000000..636e3fa
--- /dev/null
+++ b/src/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 "base/file_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+typedef testing::Test PathUtilsTest;
+
+TEST_F(PathUtilsTest, TestGetDataDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that we are packaged in
+  // org.chromium.native_test
+  FilePath path;
+  GetDataDirectory(&path);
+  EXPECT_STREQ("/data/data/org.chromium.native_test/app_chrome",
+               path.value().c_str());
+}
+
+TEST_F(PathUtilsTest, TestGetCacheDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that we are packaged in
+  // org.chromium.native_test
+  FilePath path;
+  GetCacheDirectory(&path);
+  EXPECT_STREQ("/data/data/org.chromium.native_test/cache",
+               path.value().c_str());
+}
+
+TEST_F(PathUtilsTest, TestGetNativeLibraryDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that the directory contains
+  // the base tests shared object.
+  FilePath path;
+  GetNativeLibraryDirectory(&path);
+  EXPECT_TRUE(file_util::PathExists(path.Append(("libbase_unittests.so"))));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/src/base/android/scoped_java_ref.cc b/src/base/android/scoped_java_ref.cc
new file mode 100644
index 0000000..21b466e
--- /dev/null
+++ b/src/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/src/base/android/scoped_java_ref.h b/src/base/android/scoped_java_ref.h
new file mode 100644
index 0000000..a5d71e2
--- /dev/null
+++ b/src/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/src/base/android/scoped_java_ref_unittest.cc b/src/base/android/scoped_java_ref_unittest.cc
new file mode 100644
index 0000000..36f253c
--- /dev/null
+++ b/src/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/src/base/at_exit.cc b/src/base/at_exit.cc
new file mode 100644
index 0000000..0fba355
--- /dev/null
+++ b/src/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/src/base/at_exit.h b/src/base/at_exit.h
new file mode 100644
index 0000000..6b28ae9
--- /dev/null
+++ b/src/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(__LB_SHELL__) || defined(UNIT_TEST) || defined(COBALT)
+class ShadowingAtExitManager : public AtExitManager {
+ public:
+  ShadowingAtExitManager() : AtExitManager(true) {}
+};
+#endif  // defined(UNIT_TEST)
+
+}  // namespace base
+
+#endif  // BASE_AT_EXIT_H_
diff --git a/src/base/at_exit_unittest.cc b/src/base/at_exit_unittest.cc
new file mode 100644
index 0000000..cda7340
--- /dev/null
+++ b/src/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/src/base/atomic_ref_count.h b/src/base/atomic_ref_count.h
new file mode 100644
index 0000000..5130860
--- /dev/null
+++ b/src/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/src/base/atomic_sequence_num.h b/src/base/atomic_sequence_num.h
new file mode 100644
index 0000000..7bf2778
--- /dev/null
+++ b/src/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/src/base/atomicops.h b/src/base/atomicops.h
new file mode 100644
index 0000000..230a601
--- /dev/null
+++ b/src/base/atomicops.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.
+
+// 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"
+
+#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || defined(__LB_XB360__) || defined(__LB_XB1__)
+// windows.h #defines this (only on x64). This causes problems because the
+// public API also uses MemoryBarrier at the public name for this fence. So, on
+// X64, undef it, and call its documented
+// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
+// implementation directly.
+#undef MemoryBarrier
+#endif
+
+namespace base {
+namespace subtle {
+
+typedef int32 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(OS_STARBOARD)
+#include "base/atomicops_internals_starboard.h"
+#elif defined(__LB_SHELL__)
+#define SHELL_BEGIN_ATOMICOPS_NAMESPACES namespace base { namespace subtle {
+#define SHELL_END_ATOMICOPS_NAMESPACES } }
+#include "atomicops_internals_shell.h"  // from the platform lib
+#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/src/base/atomicops_internals_atomicword_compat.h b/src/base/atomicops_internals_atomicword_compat.h
new file mode 100644
index 0000000..e02d11d
--- /dev/null
+++ b/src/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/src/base/atomicops_internals_gcc.h b/src/base/atomicops_internals_gcc.h
new file mode 100644
index 0000000..ed1b2d7
--- /dev/null
+++ b/src/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/src/base/atomicops_internals_mac.h b/src/base/atomicops_internals_mac.h
new file mode 100644
index 0000000..658ed54
--- /dev/null
+++ b/src/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/src/base/atomicops_internals_mips_gcc.h b/src/base/atomicops_internals_mips_gcc.h
new file mode 100644
index 0000000..505597e
--- /dev/null
+++ b/src/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/src/base/atomicops_internals_starboard.h b/src/base/atomicops_internals_starboard.h
new file mode 100644
index 0000000..cb1c759
--- /dev/null
+++ b/src/base/atomicops_internals_starboard.h
@@ -0,0 +1,151 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+// This is the Starboard implementation, which defers all specific
+// implementation decisions for atomic operations to the Starboard port.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_STARBOARD_H_
+#define BASE_ATOMICOPS_INTERNALS_STARBOARD_H_
+
+#include "starboard/atomic.h"
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  return SbAtomicNoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
+                                         Atomic32 new_value) {
+  return SbAtomicNoBarrier_Exchange(ptr, new_value);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
+                                          Atomic32 increment) {
+  return SbAtomicNoBarrier_Increment(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
+                                        Atomic32 increment) {
+  return SbAtomicBarrier_Increment(ptr, increment);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return SbAtomicAcquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return SbAtomicRelease_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  SbAtomicNoBarrier_Store(ptr, value);
+}
+
+inline void MemoryBarrier() {
+  SbAtomicMemoryBarrier();
+}
+
+inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  SbAtomicAcquire_Store(ptr, value);
+}
+
+inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  SbAtomicRelease_Store(ptr, value);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
+  return SbAtomicNoBarrier_Load(ptr);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
+  return SbAtomicAcquire_Load(ptr);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
+  return SbAtomicRelease_Load(ptr);
+}
+
+#if SB_IS(64_BIT)
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  return SbAtomicNoBarrier_CompareAndSwap64(ptr, old_value, new_value);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
+                                         Atomic64 new_value) {
+  return SbAtomicNoBarrier_Exchange64(ptr, new_value);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
+                                          Atomic64 increment) {
+  return SbAtomicNoBarrier_Increment64(ptr, increment);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
+                                        Atomic64 increment) {
+  return SbAtomicBarrier_Increment64(ptr, increment);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return SbAtomicAcquire_CompareAndSwap64(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return SbAtomicRelease_CompareAndSwap64(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  SbAtomicNoBarrier_Store64(ptr, value);
+}
+
+inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  SbAtomicAcquire_Store64(ptr, value);
+}
+
+inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  SbAtomicRelease_Store64(ptr, value);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
+  return SbAtomicNoBarrier_Load64(ptr);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
+  return SbAtomicAcquire_Load64(ptr);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
+  return SbAtomicRelease_Load64(ptr);
+}
+#endif  // SB_IS(64_BIT)
+
+}  // namespace base::subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_STARBOARD_H_
diff --git a/src/base/atomicops_internals_tsan.h b/src/base/atomicops_internals_tsan.h
new file mode 100644
index 0000000..44d6400
--- /dev/null
+++ b/src/base/atomicops_internals_tsan.h
@@ -0,0 +1,378 @@
+// Copyright (c) 2012 The Chromium 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
+
+#if defined(__SIZEOF_INT128__) \
+    || (__clang_major__ * 100 + __clang_minor__ >= 302)
+typedef __int128 __tsan_atomic128;
+#define __TSAN_HAS_INT128 1
+#else
+typedef char     __tsan_atomic128;
+#define __TSAN_HAS_INT128 0
+#endif
+
+typedef enum {
+  __tsan_memory_order_relaxed,
+  __tsan_memory_order_consume,
+  __tsan_memory_order_acquire,
+  __tsan_memory_order_release,
+  __tsan_memory_order_acq_rel,
+  __tsan_memory_order_seq_cst,
+} __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);
+__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *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);
+void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 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_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 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_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 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_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 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_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 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);
+__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 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,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+
+int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+
+__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
+    volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
+    __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
+    volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
+    __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
+    volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
+    __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
+    volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
+    __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic128 __tsan_atomic128_compare_exchange_val(
+    volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v,
+    __tsan_memory_order mo, __tsan_memory_order fail_mo);
+
+void __tsan_atomic_thread_fence(__tsan_memory_order mo);
+void __tsan_atomic_signal_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, __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, __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, __tsan_memory_order_relaxed);
+  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, __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, __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, __tsan_memory_order_relaxed);
+  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/src/base/atomicops_internals_x86_gcc.cc b/src/base/atomicops_internals_x86_gcc.cc
new file mode 100644
index 0000000..933ca51
--- /dev/null
+++ b/src/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/src/base/atomicops_internals_x86_gcc.h b/src/base/atomicops_internals_x86_gcc.h
new file mode 100644
index 0000000..ac02b17
--- /dev/null
+++ b/src/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/src/base/atomicops_internals_x86_msvc.h b/src/base/atomicops_internals_x86_msvc.h
new file mode 100644
index 0000000..2f428b6
--- /dev/null
+++ b/src/base/atomicops_internals_x86_msvc.h
@@ -0,0 +1,224 @@
+// 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_
+
+#if defined(__LB_XB1__) && !defined(WIN32)
+# include <intrin.h>
+// These are normally defined by windows.h:
+typedef long LONG;
+typedef long long LONGLONG;
+typedef void* PVOID;
+void __faststorefence(void);
+#pragma intrinsic(__faststorefence)
+inline void MemoryBarrier() {
+  __faststorefence();
+}
+#define InterlockedCompareExchange _InterlockedCompareExchange
+#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer
+#define InterlockedExchangePointer _InterlockedExchangePointer
+#define InterlockedExchange _InterlockedExchange
+#define InterlockedExchangeAdd _InterlockedExchangeAdd
+#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64
+
+#else
+# include <windows.h>
+
+#if defined(ARCH_CPU_64_BITS) || defined(__LB_XB360__)
+// windows.h #defines this (only on x64). This causes problems because the
+// public API also uses MemoryBarrier at the public name for this fence. So, on
+// X64, undef it, and call its documented
+// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
+// implementation directly.
+#undef MemoryBarrier
+#endif
+
+#endif
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  LONG result = InterlockedCompareExchange(
+      reinterpret_cast<volatile LONG*>(ptr),
+      static_cast<LONG>(new_value),
+      static_cast<LONG>(old_value));
+  return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  LONG result = InterlockedExchange(
+      reinterpret_cast<volatile LONG*>(ptr),
+      static_cast<LONG>(new_value));
+  return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  return InterlockedExchangeAdd(
+      reinterpret_cast<volatile LONG*>(ptr),
+      static_cast<LONG>(increment)) + increment;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+#if !(defined(_MSC_VER) && _MSC_VER >= 1400)
+#error "We require at least vs2005 for MemoryBarrier"
+#endif
+inline void MemoryBarrier() {
+#if defined(ARCH_CPU_64_BITS) || defined(__LB_XB360__)
+  // See #undef and note at the top of this file.
+  __faststorefence();
+#else
+  // We use MemoryBarrier from WinNT.h
+  ::MemoryBarrier();
+#endif
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  NoBarrier_AtomicExchange(ptr, value);
+              // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+  // See comments in Atomic64 version of Release_Store() below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#if defined(_WIN64)
+
+// 64-bit low-level operations on 64-bit platform.
+
+COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  PVOID result = InterlockedCompareExchangePointer(
+    reinterpret_cast<volatile PVOID*>(ptr),
+    reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
+  return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  PVOID result = InterlockedExchangePointer(
+    reinterpret_cast<volatile PVOID*>(ptr),
+    reinterpret_cast<PVOID>(new_value));
+  return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  return InterlockedExchangeAdd64(
+      reinterpret_cast<volatile LONGLONG*>(ptr),
+      static_cast<LONGLONG>(increment)) + increment;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  NoBarrier_AtomicExchange(ptr, value);
+              // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+
+  // When new chips come out, check:
+  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+  //  System Programming Guide, Chatper 7: Multiple-processor management,
+  //  Section 7.2, Memory Ordering.
+  // Last seen at:
+  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr;
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+
+#endif  // defined(_WIN64)
+
+}  // namespace base::subtle
+}  // namespace base
+
+#if defined(__LB_XB1__)
+#undef InterlockedCompareExchange
+#undef InterlockedCompareExchangePointer
+#undef InterlockedExchangePointer
+#undef InterlockedExchange
+#undef InterlockedExchangeAdd
+#undef InterlockedExchangeAdd64
+#endif
+
+#endif  // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
diff --git a/src/base/atomicops_unittest.cc b/src/base/atomicops_unittest.cc
new file mode 100644
index 0000000..d73a098
--- /dev/null
+++ b/src/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/src/base/auto_reset.h b/src/base/auto_reset.h
new file mode 100644
index 0000000..32f138e
--- /dev/null
+++ b/src/base/auto_reset.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_AUTO_RESET_H_
+#define BASE_AUTO_RESET_H_
+
+#include "base/basictypes.h"
+
+// base::AutoReset<> is useful for setting a variable to a new value only within
+// a particular scope. An base::AutoReset<> object resets a variable to its
+// original value upon destruction, making it an alternative to writing
+// "var = false;" or "var = old_val;" at all of a block's exit points.
+//
+// This should be obvious, but note that an base::AutoReset<> instance should
+// have a shorter lifetime than its scoped_variable, to prevent invalid memory
+// writes when the base::AutoReset<> object is destroyed.
+
+namespace base {
+
+template<typename T>
+class AutoReset {
+ public:
+  AutoReset(T* scoped_variable, T new_value)
+      : scoped_variable_(scoped_variable),
+        original_value_(*scoped_variable) {
+    *scoped_variable_ = new_value;
+  }
+
+  ~AutoReset() { *scoped_variable_ = original_value_; }
+
+ private:
+  T* scoped_variable_;
+  T original_value_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutoReset);
+};
+
+}
+
+#endif  // BASE_AUTO_RESET_H_
diff --git a/src/base/base.gyp b/src/base/base.gyp
new file mode 100644
index 0000000..3838ff6
--- /dev/null
+++ b/src/base/base.gyp
@@ -0,0 +1,1322 @@
+# Copyright (c) 2012 The Chromium 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" or ((OS == "lb_shell" or OS == "starboard") and target_arch == "android")) and _toolset == "target"', {
+          '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',
+          ],
+          'conditions' : [
+            ['target_arch == "ia32"', {
+              'sources/': [
+                ['include', '^atomicops_internals_x86_gcc\\.cc$'],
+              ],
+            }],
+            ['target_arch != "android"', {
+              'includes': [
+                '../build/android/cpufeatures.gypi',
+              ],
+            }],
+          ],
+        }],
+        ['(OS == "android" or ((OS == "lb_shell" or OS == "starboard") and target_arch == "android")) and _toolset == "target" and android_build_type == 0', {
+          'dependencies': [
+            'base_java',
+          ],
+        }],
+        ['((OS == "lb_shell" or OS == "starboard") and target_arch == "android")', {
+          'link_settings': {
+            'libraries': [
+              # for android_getCpuCount
+              '-lportable',
+            ],
+          },
+        }],
+        ['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" and OS != "ios"', {
+            'dependencies': ['../third_party/libevent/libevent.gyp:libevent'],
+        },],
+        ['component=="shared_library"', {
+          'conditions': [
+            ['OS=="win"', {
+              'sources!': [
+                'debug/debug_on_start_win.cc',
+              ],
+            }],
+          ],
+        }],
+        ['OS == "lb_shell"', {
+          'conditions': [
+            ['target_arch != "android"', {
+              'dependencies!': [
+                '../third_party/libevent/libevent.gyp:libevent'
+              ],
+            }],
+            ['target_arch == "linux"', {
+              'defines': [
+                'USE_SYMBOLIZE',
+              ],
+              'dependencies': [
+                'symbolize',
+              ],
+            }],
+            ['target_arch == "ps3" and _toolset == "target"', {
+              # Script for resolving symbols, for use by stack_trace_ps3.cc
+              'copies': [
+                {
+                  'destination': '<(PRODUCT_DIR)',
+                  'files': [
+                    'debug/addr2line_ps3.py',
+                  ],
+                },
+              ],
+              'dependencies': [
+                # On PS3, we use both posix emulation and starboard for
+                # threading.  We depend on starboard for its TLS implementation.
+                # Eventually this will replace the posix_emulation below.
+                '<(DEPTH)/starboard/starboard.gyp:starboard',
+              ],
+            }],
+            # toolset can be host or target.
+            # (host in the case of e.g. protobuf compiler.)
+            # We only want posix_emulation for target builds.
+            ['_toolset == "target"', {
+              'dependencies': [
+                '<(lbshell_root)/build/projects/posix_emulation.gyp:posix_emulation',
+              ],
+            }],  # _toolset == "target"
+          ],
+          'sources': [
+            'debug/debugger_shell.cc',
+            'debug/stack_trace_shell.cc',
+            'guid_shell.cc',
+            'safe_strerror_shell.cc',
+            'sys_string_conversions_shell.cc',
+            'test/test_file_util_shell.cc',
+            'threading/thread_local_shell.cc',
+            'threading/thread_local_storage_shell.cc',
+            'threading/worker_pool_shell.cc',
+          ],
+        }],  # OS=="lb_shell"
+        ['OS == "starboard"', {
+          'conditions': [
+            ['_toolset == "target"', {
+              'dependencies': [
+                '<(DEPTH)/starboard/starboard.gyp:starboard',
+                '<(DEPTH)/starboard/client_porting/eztime/eztime.gyp:eztime',
+               ],
+            }],  # _toolset == "target"
+          ],
+          'dependencies!': [
+            '../third_party/libevent/libevent.gyp:libevent'
+          ],
+          'sources': [
+            'base_paths_starboard.cc',
+            'test/test_file_util_starboard.cc',
+          ],
+        }],  # OS=="starboard"
+        ['OS == "lb_shell" or OS == "starboard"', {
+          'sources!': [
+            'file_descriptor_shuffle.cc',
+          ],
+        }],  # OS == "lb_shell" or OS == "starboard"
+      ],
+      '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_io_ios.cc',
+        'message_pump_io_ios.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',
+          ],
+        }],
+        ['OS=="lb_shell"', {
+          'dependencies': [
+            '<(lbshell_root)/build/projects/posix_emulation.gyp:posix_emulation',
+          ],
+        }],
+        ['OS=="starboard"', {
+          'dependencies': [
+            '<(DEPTH)/starboard/starboard.gyp:starboard',
+            '<(DEPTH)/starboard/client_porting/icu_init/icu_init.gyp:icu_init',
+          ],
+        }],
+      ],
+      '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_observer.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_member.cc',
+        'prefs/public/pref_member.h',
+        'prefs/public/pref_service_base.h',
+        'prefs/value_map_pref_store.cc',
+        'prefs/value_map_pref_store.h',
+      ],
+      'conditions': [
+        ['OS == "starboard"', {
+          'sources!': [
+            # Uses ImportantFileWriter, which is not supported by Starboard.
+            'prefs/json_pref_store.cc',
+            'prefs/json_pref_store.h',
+          ],
+        }],  # OS=="starboard"
+      ],
+    },
+    {
+      # 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': [
+        '..',
+      ],
+      'conditions': [
+        ['OS == "lb_shell" or OS=="starboard"', {
+          'sources/': [
+            ['exclude', '^win/'],
+          ],
+        }],
+      ],
+    },
+    {
+      # 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/jni_string_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/mru_cache_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',
+        'files/scoped_temp_dir_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/libdispatch_task_runner_unittest.cc',
+        '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/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_io_ios_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',
+        'object_tracker.h',
+        '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',
+        'sha1_unittest.cc',
+        'shared_memory_unittest.cc',
+        'stl_util_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',
+        'test/time_helpers.cc',
+        'test/time_helpers.h',
+        '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',
+              ],
+            }],
+          ],
+          'sources!': [
+            # Broken on Android, and already disabled there.
+            'debug/stack_trace_unittest.cc',
+          ],
+        }],
+        ['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$'],
+            # iOS does not use message_pump_libevent.
+            ['exclude', '^message_pump_libevent_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' ],
+            },
+          ],
+        }],
+        ['cobalt==1', {
+          'actions': [
+            {
+              'action_name': 'copy_test_data',
+              'variables': {
+                'input_files': [
+                  'data/json',
+                  'data/file_util_unittest',
+                ],
+                'output_dir': 'base/data',
+              },
+              'includes': [ '../cobalt/build/copy_test_data.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',
+          ],
+        }],
+        ['OS == "lb_shell" or OS == "starboard"', {
+          'sources!': [
+            'environment_unittest.cc',
+            'files/important_file_writer_unittest.cc',
+            # We don't use field trials (an experiments framework) in Cobalt,
+            # and these tests depend on the current date being set correctly,
+            # so do not run them.
+            'metrics/field_trial_unittest.cc',
+            'metrics/stats_table_unittest.cc',
+            'process_util_unittest.cc',
+            'scoped_native_library_unittest.cc',
+            'shared_memory_unittest.cc',
+            'synchronization/waitable_event_watcher_unittest.cc',
+          ],
+          'sources': [
+            'circular_buffer_shell_unittest.cc',
+            'optional_unittest.cc',
+            'state_machine_shell_unittest.cc',
+          ],
+          'conditions': [
+            ['target_arch != "android" or OS == "starboard"', {
+              'dependencies!': [
+                '../third_party/libevent/libevent.gyp:libevent'
+              ],
+              'sources!': [
+                'message_pump_libevent_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
+      'msvs_disabled_warnings': [
+        4800,  # forcing value to bool 'true' or 'false' (performance warning)
+      ],
+    },
+    {
+      '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': [
+        ['cobalt==1', {
+          'dependencies': [
+            # Platform delegate is used to perform system specific
+            # initialization logic. This is a temporary solution and the code
+            # should eventually move into the chromium/base code.
+            '<(DEPTH)/cobalt/deprecated/deprecated.gyp:platform_delegate',
+          ],
+        }],
+        ['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$'],
+          ],
+        }],
+        ['OS == "lb_shell" or OS=="starboard"', {
+          'sources/': [
+            ['exclude', 'test/multiprocess_test'],
+          ],
+          'sources!': [
+            'perftimer.cc',
+          ],
+          'sources': [
+            'perftimer_starboard.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',
+          ],
+        }],
+        ['OS=="starboard"', {
+          'sources!': [
+            'perftimer.cc',
+          ],
+          'sources': [
+            'perftimer_starboard.cc',
+          ],
+        }],
+      ],
+    },
+  ],
+  '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" and (OS!="lb_shell" or target_arch in ("android", "linux"))', {
+      '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" or ((OS == "lb_shell" or OS == "starboard") and target_arch == "android")', {
+      'targets': [
+        {
+          'target_name': 'base_jni_headers',
+          'type': 'none',
+          'sources': [
+            'android/java/src/org/chromium/base/BuildInfo.java',
+            'android/java/src/org/chromium/base/CpuFeatures.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
+            },
+          },
+        },
+      ],
+    }],
+    ['cobalt==1', {
+      'targets': [
+        {
+          'target_name': 'base_unittests_deploy',
+          'type': 'none',
+          'dependencies': [
+            'base_unittests',
+          ],
+          'variables': {
+            'executable_name': 'base_unittests',
+          },
+          'includes': [ '../cobalt/build/deploy.gypi' ],
+        },
+      ],
+    }],
+    # 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") or ((OS == "lb_shell" or OS == "starboard") and target_arch == "android")', {
+      '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/src/base/base.gypi b/src/base/base.gypi
new file mode 100644
index 0000000..fde1a96
--- /dev/null
+++ b/src/base/base.gypi
@@ -0,0 +1,858 @@
+# Copyright (c) 2012 The Chromium 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/cpu_features.cc',
+          '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_functor.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_hash_map.h',
+          'containers/linked_list.h',
+          'containers/mru_cache.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',
+          # This file depends on files from the 'allocator' target,
+          # but this target does not depend on 'allocator' (see
+          # allocator.gyp for details).
+          'debug/leak_annotations.h',
+          'debug/leak_tracker.h',
+          'debug/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',
+          '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_dirent.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',
+          'files/scoped_temp_dir.cc',
+          'files/scoped_temp_dir.h',
+          '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/libdispatch_task_runner.cc',
+          'mac/libdispatch_task_runner.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/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/eintr_wrapper.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',
+          '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/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,
+        ],
+        'conditions': [
+          ['OS=="lb_shell"', {
+            'sources': [
+              'base_paths_shell.cc',
+              'circular_buffer_shell.h',
+              'circular_buffer_shell.cc',
+              'message_pump_shell.cc',
+              'message_pump_shell.h',
+              'native_library_shell.cc',  # Stub implementation
+              'object_watcher_shell.cc',
+              'object_watcher_shell.h',
+              'optional.cc',
+              'optional.h',
+              'optional_internal.h',
+              'shared_memory_shell.cc',  # Stub implementation
+              'state_machine_shell.h',
+              'state_machine_shell.cc',
+              'synchronization/condition_variable_shell.cc',
+              'synchronization/lock_impl_shell.cc',
+              'synchronization/waitable_event_shell.cc',
+              'threading/thread_checker_impl_atomic.cc',
+              '<!@(find <(lbshell_root)/src/platform/<(target_arch)/chromium/base -type f)',
+            ],
+            'sources!': [
+               'threading/thread_checker_impl.cc',
+            ],
+            'sources/': [
+              ['include', 'sys_string_conversions_linux.cc'],
+            ],
+          }],
+          [ 'OS=="lb_shell" and target_arch!="linux" and target_arch!="android"', {
+            'sources!': [
+              'string16.cc',  # wchar_t is 2-bytes wide, string16 == wstring here.
+            ],
+          }],
+          [ 'OS=="lb_shell" and target_arch=="android"', {
+            'sources/' : [
+              ['exclude', 'message_pump_shell.cc'],
+              ['exclude', 'message_pump_shell.h'],
+              ['exclude', 'native_library_shell.cc'],
+              ['exclude', 'process_util.cc'],
+              ['exclude', '<(lbshell_root)/src/object_watcher_shell.cc'],
+              ['exclude', '<(lbshell_root)/src/object_watcher_shell.h'],
+              ['include', 'message_pump_libevent.cc'],
+              ['include', 'message_pump_libevent.h'],
+              ['include', 'native_library_posix.cc'],
+            ],
+          }],
+          # For Starboard, we are going to build this back up as necessary.
+          ['OS=="starboard"', {
+            'sources': [
+              'base_paths_starboard.cc',
+              'circular_buffer_shell.cc',
+              'circular_buffer_shell.h',
+              'debug/debugger_starboard.cc',
+              'debug/stack_trace_starboard.cc',
+              'file_util_starboard.cc',
+              'guid_starboard.cc',
+              'message_pump_io_starboard.cc',
+              'message_pump_io_starboard.h',
+              'message_pump_ui_starboard.cc',
+              'message_pump_ui_starboard.h',
+              'optional.cc',
+              'optional.h',
+              'optional_internal.h',
+              'platform_file_starboard.cc',
+              'process_starboard.cc',
+              'process_util_starboard.cc',
+              'rand_util_starboard.cc',
+              'state_machine_shell.cc',
+              'state_machine_shell.h',
+              'synchronization/condition_variable_starboard.cc',
+              'synchronization/lock_impl_starboard.cc',
+              'synchronization/waitable_event_starboard.cc',
+              'sys_info_starboard.cc',
+              'sys_string_conversions_starboard.cc',
+              'system_monitor/system_monitor_starboard.cc',
+              'threading/platform_thread_starboard.cc',
+              'threading/thread_checker_impl_atomic.cc',
+              'threading/thread_local_starboard.cc',
+              'threading/thread_local_storage_starboard.cc',
+              'threading/worker_pool_starboard.cc',
+              'time_starboard.cc',
+            ],
+            'sources!': [
+              # Uses file_util::ReplaceFile, which isn't implemented in
+              # Starboard, and isn't otherwise used in Cobalt.
+              'files/important_file_writer.cc',
+              'files/important_file_writer.h',
+
+              # All the common functions have been removed for Starboard, so we
+              # don't even want to compile this.
+              'process_util.cc',
+
+              # Tricky to support cross-platform, and not used by Cobalt.
+              'scoped_native_library.cc',
+              'scoped_native_library.h',
+
+              # We use thread_checker_impl_atomic.cc instead.
+              'threading/thread_checker_impl.cc',
+            ],
+            'conditions': [
+              ['target_os!="linux" and target_arch!="android"', {
+                'sources!': [
+                  # Since wchar_t is 2-bytes wide, string16 == wstring here.
+                  'string16.cc',
+                ],
+              }],
+            ],
+          }],  # OS == "starboard"
+          [ 'OS=="lb_shell" or OS=="starboard"', {
+            'sources!': [
+              'environment.cc',
+              'file_descriptor_shuffle.cc',
+              'files/file_path_watcher.cc',
+              'files/file_path_watcher_kqueue.cc',
+              'files/file_path_watcher_stub.cc',
+              'message_pump_libevent.cc',
+              'message_pump_libevent.h',
+              'metrics/stats_table.cc',
+              'metrics/stats_table.h',
+            ],
+          }],  # OS == "lb_shell" or OS == "starboard"
+        ],
+        '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',
+               'files/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$'],
+            ],
+            'sources!': [
+              'message_pump_libevent.cc'
+            ],
+          }],
+          ['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) and (OS != "lb_shell" or "<(target_arch)" != "android")', {
+              '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/src/base/base64.cc b/src/base/base64.cc
new file mode 100644
index 0000000..1907978
--- /dev/null
+++ b/src/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/src/base/base64.h b/src/base/base64.h
new file mode 100644
index 0000000..983d5e2
--- /dev/null
+++ b/src/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/src/base/base64_unittest.cc b/src/base/base64_unittest.cc
new file mode 100644
index 0000000..9a5dd81
--- /dev/null
+++ b/src/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/src/base/base_export.h b/src/base/base_export.h
new file mode 100644
index 0000000..fdfa5f9
--- /dev/null
+++ b/src/base/base_export.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_EXPORT_H_
+#define BASE_BASE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(_MSC_VER)
+#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/src/base/base_paths.cc b/src/base/base_paths.cc
new file mode 100644
index 0000000..80105b6
--- /dev/null
+++ b/src/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/src/base/base_paths.h b/src/base/base_paths.h
new file mode 100644
index 0000000..7bc23a8
--- /dev/null
+++ b/src/base/base_paths.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_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) || defined(__LB_ANDROID__)
+#include "base/base_paths_android.h"
+#elif defined(OS_STARBOARD)
+#include "base/base_paths_starboard.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/src/base/base_paths_android.cc b/src/base/base_paths_android.cc
new file mode 100644
index 0000000..9905200
--- /dev/null
+++ b/src/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/src/base/base_paths_android.h b/src/base/base_paths_android.h
new file mode 100644
index 0000000..7a9ac4a
--- /dev/null
+++ b/src/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/src/base/base_paths_mac.h b/src/base/base_paths_mac.h
new file mode 100644
index 0000000..ac75402
--- /dev/null
+++ b/src/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/src/base/base_paths_mac.mm b/src/base/base_paths_mac.mm
new file mode 100644
index 0000000..630f742
--- /dev/null
+++ b/src/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/src/base/base_paths_posix.cc b/src/base/base_paths_posix.cc
new file mode 100644
index 0000000..834dee3
--- /dev/null
+++ b/src/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/src/base/base_paths_posix.h b/src/base/base_paths_posix.h
new file mode 100644
index 0000000..811c8cb
--- /dev/null
+++ b/src/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/src/base/base_paths_shell.cc b/src/base/base_paths_shell.cc
new file mode 100644
index 0000000..aae1d80
--- /dev/null
+++ b/src/base/base_paths_shell.cc
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "base/base_paths.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "cobalt/deprecated/platform_delegate.h"
+
+namespace base {
+
+// this is where we can control the path for placement
+// of a lot of file resources for lbshell.
+bool PathProviderShell(int key, FilePath* result) {
+  cobalt::deprecated::PlatformDelegate* plat =
+      cobalt::deprecated::PlatformDelegate::Get();
+  switch (key) {
+    case base::DIR_EXE:
+    case base::DIR_MODULE:
+      DCHECK(!plat->game_content_path().empty());
+      *result = FilePath(plat->game_content_path());
+      return true;
+
+#if defined(ENABLE_DIR_SOURCE_ROOT_ACCESS)
+    case base::DIR_SOURCE_ROOT:
+      if (plat->dir_source_root().length() > 0) {
+        *result = FilePath(plat->dir_source_root());
+        return true;
+      } else {
+        DLOG(INFO) << "DIR_SOURCE_ROOT not defined - skipping.";
+        return false;
+      }
+#endif  // ENABLE_DIR_SOURCE_ROOT_ACCESS
+
+    case base::DIR_TEMP:
+      DCHECK(!plat->temp_path().empty());
+      *result = FilePath(plat->temp_path());
+      return true;
+
+    case base::DIR_CACHE:
+      DCHECK(!plat->temp_path().empty());
+      *result = FilePath(plat->temp_path()).Append("cache");
+      return true;
+    case base::DIR_HOME: {
+#if defined(COBALT_LINUX)
+      const char* home_dir = getenv("HOME");
+      if (home_dir && home_dir[0]) {
+        *result = FilePath(home_dir);
+        return true;
+      } else {
+        return PathProviderShell(base::DIR_TEMP, result);
+      }
+#else
+      return PathProviderShell(base::DIR_EXE, result);
+#endif  // defined(COBALT_LINUX)
+    }
+  }
+
+  return false;
+}
+
+}  // namespace base
+
diff --git a/src/base/base_paths_starboard.cc b/src/base/base_paths_starboard.cc
new file mode 100644
index 0000000..2b8a14a
--- /dev/null
+++ b/src/base/base_paths_starboard.cc
@@ -0,0 +1,98 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "base/base_paths.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "starboard/system.h"
+
+namespace base {
+
+// This is where we can control the path for placement of a lot of file
+// resources for cobalt.
+bool PathProviderStarboard(int key, FilePath *result) {
+  char path[SB_FILE_MAX_PATH];
+  switch (key) {
+    case base::FILE_EXE: {
+      bool success = SbSystemGetPath(kSbSystemPathExecutableFile, path,
+                      SB_ARRAY_SIZE_INT(path));
+      DCHECK(success);
+      if (success) {
+        *result = FilePath(path);
+        return true;
+      }
+      DLOG(ERROR) << "FILE_EXE not defined.";
+      return false;
+    }
+
+    case base::DIR_EXE:
+    case base::DIR_MODULE: {
+      bool success = SbSystemGetPath(kSbSystemPathContentDirectory, path,
+                                     SB_ARRAY_SIZE_INT(path));
+      DCHECK(success);
+      if (success) {
+        *result = FilePath(path);
+        return true;
+      }
+      DLOG(ERROR) << "DIR_EXE/DIR_MODULE not defined.";
+      return false;
+    }
+
+#if defined(ENABLE_DIR_SOURCE_ROOT_ACCESS)
+    case base::DIR_SOURCE_ROOT: {
+      bool success = SbSystemGetPath(kSbSystemPathSourceDirectory, path,
+                                     SB_ARRAY_SIZE_INT(path));
+      DCHECK(success);
+      if (success) {
+        *result = FilePath(path);
+        return true;
+      }
+      DLOG(ERROR) << "DIR_SOURCE_ROOT not defined.";
+      return false;
+    }
+#endif  // ENABLE_DIR_SOURCE_ROOT_ACCESS
+
+    case base::DIR_CACHE: {
+      bool success = SbSystemGetPath(kSbSystemPathCacheDirectory, path,
+                                     SB_ARRAY_SIZE_INT(path));
+      if (success) {
+        *result = FilePath(path);
+        return true;
+      }
+      DLOG(INFO) << "DIR_CACHE not defined.";
+      return false;
+    }
+
+    case base::DIR_TEMP: {
+      bool success = SbSystemGetPath(kSbSystemPathTempDirectory, path,
+                                     SB_ARRAY_SIZE_INT(path));
+      DCHECK(success);
+      if (success) {
+        *result = FilePath(path);
+        return true;
+      }
+      DLOG(ERROR) << "DIR_TEMP not defined.";
+      return false;
+    }
+
+    case base::DIR_HOME:
+      // TODO: Add a home directory to SbSystemPathId and get it from there.
+      return PathProviderStarboard(base::DIR_CACHE, result);
+  }
+
+  NOTREACHED() << "key = " << key;
+  return false;
+}
+
+}
diff --git a/src/base/base_paths_starboard.h b/src/base/base_paths_starboard.h
new file mode 100644
index 0000000..cfa9099
--- /dev/null
+++ b/src/base/base_paths_starboard.h
@@ -0,0 +1,39 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef BASE_BASE_PATHS_STARBOARD_H_
+#define BASE_BASE_PATHS_STARBOARD_H_
+
+// This file declares Starboard-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_STARBOARD_START = 500,
+
+  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.
+
+  DIR_HOME,     // The root of the primary directory for a user (and their
+                // programs) to place their personal files.
+
+  PATH_STARBOARD_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_STARBOARD_H_
diff --git a/src/base/base_paths_win.cc b/src/base/base_paths_win.cc
new file mode 100644
index 0000000..a06d908
--- /dev/null
+++ b/src/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/src/base/base_paths_win.h b/src/base/base_paths_win.h
new file mode 100644
index 0000000..11bc111
--- /dev/null
+++ b/src/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/src/base/base_switches.cc b/src/base/base_switches.cc
new file mode 100644
index 0000000..7c7b061
--- /dev/null
+++ b/src/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/src/base/base_switches.h b/src/base/base_switches.h
new file mode 100644
index 0000000..558a5cf
--- /dev/null
+++ b/src/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/src/base/base_unittests.isolate b/src/base/base_unittests.isolate
new file mode 100644
index 0000000..f13e66b
--- /dev/null
+++ b/src/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/src/base/base_untrusted.gyp b/src/base/base_untrusted.gyp
new file mode 100644
index 0000000..8b64c7d
--- /dev/null
+++ b/src/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/src/base/basictypes.h b/src/base/basictypes.h
new file mode 100644
index 0000000..c393fd7
--- /dev/null
+++ b/src/base/basictypes.h
@@ -0,0 +1,365 @@
+// Copyright (c) 2011 The Chromium Authors. All 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;
+typedef int                 int32;
+
+// 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;
+typedef unsigned int       uint32;
+
+// 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;
+
+#if defined(COBALT_WIN)
+#pragma warning(push)
+#pragma warning(disable : 4310)  // Cast truncates constant value.
+#endif
+
+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));
+
+#if defined(COBALT_WIN)
+#pragma warning(pop)
+#endif
+
+// 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
+
+#if defined(COMPILER_GHS)
+// GHS does not support local types as template arguments, so we must fall back to the unsafe version
+#define arraysize ARRAYSIZE_UNSAFE
+#else
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+#endif
+
+// 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/src/base/bind.h b/src/base/bind.h
new file mode 100644
index 0000000..5cf124d
--- /dev/null
+++ b/src/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/src/base/bind.h.pump b/src/base/bind.h.pump
new file mode 100644
index 0000000..b321649
--- /dev/null
+++ b/src/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/src/base/bind_helpers.cc b/src/base/bind_helpers.cc
new file mode 100644
index 0000000..f2fc3bb
--- /dev/null
+++ b/src/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/src/base/bind_helpers.h b/src/base/bind_helpers.h
new file mode 100644
index 0000000..b60a56e
--- /dev/null
+++ b/src/base/bind_helpers.h
@@ -0,0 +1,563 @@
+// Copyright (c) 2011 The Chromium 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) || defined(COBALT_WIN)
+#pragma warning(push)
+#pragma warning(disable : 4624)
+#endif
+  struct Base : public T, public BaseMixin {
+  };
+#if defined(OS_WIN) || defined(COBALT_WIN)
+#pragma warning(pop)
+#endif
+
+  template <void(BaseMixin::*)(void)> struct Helper {};
+
+  template <typename C>
+  static No& Check(Helper<&C::AddRef>*);
+
+  template <typename >
+  static Yes& Check(...);
+
+ public:
+  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>&) {}
+  static void Release(const scoped_refptr<T>&) {}
+};
+
+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/src/base/bind_helpers_unittest.cc b/src/base/bind_helpers_unittest.cc
new file mode 100644
index 0000000..3ef2d75
--- /dev/null
+++ b/src/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/src/base/bind_internal.h b/src/base/bind_internal.h
new file mode 100644
index 0000000..b87879f
--- /dev/null
+++ b/src/base/bind_internal.h
@@ -0,0 +1,2800 @@
+// 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(__LB_SHELL__) || defined(OS_STARBOARD)
+// Check for C++11 support
+#if (_MSC_VER >=  1700) || (__cplusplus > 199711L)
+#include "base/bind_internal_functor.h"
+#endif
+#endif
+
+#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) {
+  DCHECK(!t.is_null());
+  return t;
+}
+
+
+// InvokeHelper<>
+//
+// There are 3 logical InvokeHelper<> specializations: normal, void-return,
+// WeakCalls.
+//
+// The normal type just calls the underlying runnable.
+//
+// We need a InvokeHelper to handle void return types in order to support
+// IgnoreResult().  Normally, if the Runnable's RunType had a void return,
+// the template system would just accept "return functor.Run()" ignoring
+// the fact that a void function is being used with return. This piece of
+// sugar breaks though when the Runnable's RunType is not void.  Thus, we
+// need a partial specialization to change the syntax to drop the "return"
+// from the invocation call.
+//
+// WeakCalls similarly need special syntax that is applied to the first
+// argument to check if they should no-op themselves.
+template <bool IsWeakCall, typename ReturnType, typename Runnable,
+          typename ArgsType>
+struct InvokeHelper;
+
+template <typename ReturnType, typename Runnable>
+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/src/base/bind_internal.h.pump b/src/base/bind_internal.h.pump
new file mode 100644
index 0000000..4760af7
--- /dev/null
+++ b/src/base/bind_internal.h.pump
@@ -0,0 +1,504 @@
+$$ 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(__LB_SHELL__) || defined(OS_STARBOARD)
+// Check for C++11 support
+#if (_MSC_VER >=  1700) || (__cplusplus > 199711L)
+#include "base/bind_internal_functor.h"
+#endif
+#endif
+
+#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) {
+  DCHECK(!t.is_null());
+  return t;
+}
+
+
+// InvokeHelper<>
+//
+// There are 3 logical InvokeHelper<> specializations: normal, void-return,
+// WeakCalls.
+//
+// The normal type just calls the underlying runnable.
+//
+// We need a InvokeHelper to handle void return types in order to support
+// IgnoreResult().  Normally, if the Runnable's RunType had a void return,
+// the template system would just accept "return functor.Run()" ignoring
+// the fact that a void function is being used with return. This piece of
+// sugar breaks though when the Runnable's RunType is not void.  Thus, we
+// need a partial specialization to change the syntax to drop the "return"
+// from the invocation call.
+//
+// WeakCalls similarly need special syntax that is applied to the first
+// argument to check if they should no-op themselves.
+template <bool IsWeakCall, typename ReturnType, typename Runnable,
+          typename ArgsType>
+struct InvokeHelper;
+
+$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/src/base/bind_internal_functor.h b/src/base/bind_internal_functor.h
new file mode 100644
index 0000000..ede69bc
--- /dev/null
+++ b/src/base/bind_internal_functor.h
@@ -0,0 +1,221 @@
+// This file was GENERATED by command:
+//     pump.py bind_internal_functor.h.pump
+// DO NOT EDIT BY HAND!!!
+
+
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIND_INTERNAL_FUNCTOR_H_
+#define BASE_BIND_INTERNAL_FUNCTOR_H_
+
+namespace base {
+namespace internal {
+
+// The RunnableAdapterFunctor<> template is used in a template specialization
+// for RunnableAdapter<> which enables support for functor objects, including
+// C++11 lambdas. The functor signature is deduced from the type of the
+// operator() method using decltype().
+//
+// All supported functors are assumed to have a const qualifier in their
+// operator() method.
+
+template <typename Functor>
+class RunnableAdapter;
+
+template <typename Functor, typename Sig>
+class RunnableAdapterFunctor;
+
+template <typename Functor>
+class RunnableAdapter
+    : public RunnableAdapterFunctor<Functor, decltype(&Functor::operator())> {
+ public:
+  typedef RunnableAdapterFunctor<Functor,
+      decltype(&Functor::operator())> BaseType;
+
+  explicit RunnableAdapter(Functor functor)
+      : BaseType(functor) {}
+};
+
+// Functor: Arity 0.
+template <typename F, typename T, typename R>
+class RunnableAdapterFunctor<F, R(T::*)() const> {
+ public:
+  typedef R (RunType)();
+
+  explicit RunnableAdapterFunctor(F functor)
+      : functor_(functor) {
+  }
+
+  R Run() {
+    return functor_();
+  }
+
+ private:
+  F functor_;
+};
+
+// Functor: Arity 1.
+template <typename F, typename T, typename R, typename A1>
+class RunnableAdapterFunctor<F, R(T::*)(A1) const> {
+ public:
+  typedef R (RunType)(A1);
+
+  explicit RunnableAdapterFunctor(F functor)
+      : functor_(functor) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1) {
+    return functor_(CallbackForward(a1));
+  }
+
+ private:
+  F functor_;
+};
+
+// Functor: Arity 2.
+template <typename F, typename T, typename R, typename A1, typename A2>
+class RunnableAdapterFunctor<F, R(T::*)(A1, A2) const> {
+ public:
+  typedef R (RunType)(A1, A2);
+
+  explicit RunnableAdapterFunctor(F functor)
+      : functor_(functor) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2) {
+    return functor_(CallbackForward(a1), CallbackForward(a2));
+  }
+
+ private:
+  F functor_;
+};
+
+// Functor: Arity 3.
+template <typename F, typename T, typename R, typename A1, typename A2,
+    typename A3>
+class RunnableAdapterFunctor<F, R(T::*)(A1, A2, A3) const> {
+ public:
+  typedef R (RunType)(A1, A2, A3);
+
+  explicit RunnableAdapterFunctor(F functor)
+      : functor_(functor) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3) {
+    return functor_(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3));
+  }
+
+ private:
+  F functor_;
+};
+
+// Functor: Arity 4.
+template <typename F, typename T, typename R, typename A1, typename A2,
+    typename A3, typename A4>
+class RunnableAdapterFunctor<F, R(T::*)(A1, A2, A3, A4) const> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4);
+
+  explicit RunnableAdapterFunctor(F functor)
+      : functor_(functor) {
+  }
+
+  R Run(typename CallbackParamTraits<A1>::ForwardType a1,
+      typename CallbackParamTraits<A2>::ForwardType a2,
+      typename CallbackParamTraits<A3>::ForwardType a3,
+      typename CallbackParamTraits<A4>::ForwardType a4) {
+    return functor_(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4));
+  }
+
+ private:
+  F functor_;
+};
+
+// Functor: Arity 5.
+template <typename F, typename T, typename R, typename A1, typename A2,
+    typename A3, typename A4, typename A5>
+class RunnableAdapterFunctor<F, R(T::*)(A1, A2, A3, A4, A5) const> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5);
+
+  explicit RunnableAdapterFunctor(F functor)
+      : functor_(functor) {
+  }
+
+  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 functor_(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5));
+  }
+
+ private:
+  F functor_;
+};
+
+// Functor: Arity 6.
+template <typename F, typename T, typename R, typename A1, typename A2,
+    typename A3, typename A4, typename A5, typename A6>
+class RunnableAdapterFunctor<F, R(T::*)(A1, A2, A3, A4, A5, A6) const> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5, A6);
+
+  explicit RunnableAdapterFunctor(F functor)
+      : functor_(functor) {
+  }
+
+  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 functor_(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
+        CallbackForward(a6));
+  }
+
+ private:
+  F functor_;
+};
+
+// Functor: Arity 7.
+template <typename F, typename T, typename R, typename A1, typename A2,
+    typename A3, typename A4, typename A5, typename A6, typename A7>
+class RunnableAdapterFunctor<F, R(T::*)(A1, A2, A3, A4, A5, A6, A7) const> {
+ public:
+  typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7);
+
+  explicit RunnableAdapterFunctor(F functor)
+      : functor_(functor) {
+  }
+
+  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 functor_(CallbackForward(a1), CallbackForward(a2),
+        CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
+        CallbackForward(a6), CallbackForward(a7));
+  }
+
+ private:
+  F functor_;
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_BIND_INTERNAL_FUNCTOR_H_
diff --git a/src/base/bind_internal_functor.h.pump b/src/base/bind_internal_functor.h.pump
new file mode 100644
index 0000000..919521e
--- /dev/null
+++ b/src/base/bind_internal_functor.h.pump
@@ -0,0 +1,74 @@
+$$ 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) 2013 The Chromium Authors. All 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_FUNCTOR_H_
+#define BASE_BIND_INTERNAL_FUNCTOR_H_
+
+namespace base {
+namespace internal {
+
+// The RunnableAdapterFunctor<> template is used in a template specialization
+// for RunnableAdapter<> which enables support for functor objects, including
+// C++11 lambdas. The functor signature is deduced from the type of the
+// operator() method using decltype().
+//
+// All supported functors are assumed to have a const qualifier in their
+// operator() method.
+
+template <typename Functor>
+class RunnableAdapter;
+
+template <typename Functor, typename Sig>
+class RunnableAdapterFunctor;
+
+template <typename Functor>
+class RunnableAdapter
+    : public RunnableAdapterFunctor<Functor, decltype(&Functor::operator())> {
+ public:
+  typedef RunnableAdapterFunctor<Functor,
+      decltype(&Functor::operator())> BaseType;
+
+  explicit RunnableAdapter(Functor functor)
+      : BaseType(functor) {}
+};
+
+$for ARITY [[
+$range ARG 1..ARITY
+
+// Functor: Arity $(ARITY).
+template <typename F, typename T, typename R[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
+class RunnableAdapterFunctor<F, R(T::*)($for ARG , [[A$(ARG)]]) const> {
+ public:
+  typedef R (RunType)($for ARG , [[A$(ARG)]]);
+
+  explicit RunnableAdapterFunctor(F functor)
+      : functor_(functor) {
+  }
+
+  R Run($for ARG , [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
+    return functor_($for ARG , [[CallbackForward(a$(ARG))]]);
+  }
+
+ private:
+  F functor_;
+};
+
+]]  $$ for ARITY
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_BIND_INTERNAL_FUNCTOR_H_
diff --git a/src/base/bind_internal_win.h b/src/base/bind_internal_win.h
new file mode 100644
index 0000000..7a8486a
--- /dev/null
+++ b/src/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/src/base/bind_internal_win.h.pump b/src/base/bind_internal_win.h.pump
new file mode 100644
index 0000000..cd108b6
--- /dev/null
+++ b/src/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/src/base/bind_unittest.cc b/src/base/bind_unittest.cc
new file mode 100644
index 0000000..1d808a6
--- /dev/null
+++ b/src/base/bind_unittest.cc
@@ -0,0 +1,814 @@
+// Copyright (c) 2012 The Chromium Authors. All 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
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+// Test null callbacks cause a DCHECK.
+TEST(BindDeathTest, NullCallback) {
+  base::Callback<void(int)> null_cb;
+  ASSERT_TRUE(null_cb.is_null());
+  EXPECT_DEATH(base::Bind(null_cb, 42), "");
+}
+
+#endif  // (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) &&
+        //     GTEST_HAS_DEATH_TEST
+
+}  // namespace
+}  // namespace base
diff --git a/src/base/bind_unittest.nc b/src/base/bind_unittest.nc
new file mode 100644
index 0000000..069092c
--- /dev/null
+++ b/src/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/src/base/bits.h b/src/base/bits.h
new file mode 100644
index 0000000..b2209e8
--- /dev/null
+++ b/src/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/src/base/bits_unittest.cc b/src/base/bits_unittest.cc
new file mode 100644
index 0000000..e913d6a
--- /dev/null
+++ b/src/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/src/base/build_time.cc b/src/base/build_time.cc
new file mode 100644
index 0000000..bb2274b
--- /dev/null
+++ b/src/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/src/base/build_time.h b/src/base/build_time.h
new file mode 100644
index 0000000..e7bbb39
--- /dev/null
+++ b/src/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/src/base/build_time_unittest.cc b/src/base/build_time_unittest.cc
new file mode 100644
index 0000000..399a53f
--- /dev/null
+++ b/src/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/src/base/callback.h b/src/base/callback.h
new file mode 100644
index 0000000..18c1c6c
--- /dev/null
+++ b/src/base/callback.h
@@ -0,0 +1,893 @@
+// 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 partial application of functions.

+//

+// Partial application (or "currying") is the process of binding a subset of

+// a function's arguments to produce another function that takes fewer

+// arguments. This can be used to pass around a unit of delayed execution,

+// much like lexical closures are used in other languages. For example, it

+// is used in Chromium code to schedule tasks on different MessageLoops.

+//

+// A callback with no unbound input parameters (base::Callback<void(void)>)

+// is called a base::Closure. Note that this is NOT the same as what other

+// languages refer to as a closure -- it does not retain a reference to its

+// enclosing environment.

+//

+// MEMORY MANAGEMENT AND PASSING

+//

+// The Callback objects themselves should be passed by const-reference, and

+// stored by copy. They internally store their state via a refcounted class

+// and thus do not need to be deleted.

+//

+// The reason to pass via a const-reference is to avoid unnecessary

+// AddRef/Release pairs to the internal state.

+//

+//

+// -----------------------------------------------------------------------------

+// Quick reference for basic stuff

+// -----------------------------------------------------------------------------

+//

+// BINDING A BARE FUNCTION

+//

+//   int Return5() { return 5; }

+//   base::Callback<int(void)> func_cb = base::Bind(&Return5);

+//   LOG(INFO) << func_cb.Run();  // Prints 5.

+//

+// BINDING A CLASS METHOD

+//

+//   The first argument to bind is the member function to call, the second is

+//   the object on which to call it.

+//

+//   class Ref : public base::RefCountedThreadSafe<Ref> {

+//    public:

+//     int Foo() { return 3; }

+//     void PrintBye() { LOG(INFO) << "bye."; }

+//   };

+//   scoped_refptr<Ref> ref = new Ref();

+//   base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);

+//   LOG(INFO) << ref_cb.Run();  // Prints out 3.

+//

+//   By default the object must support RefCounted or you will get a compiler

+//   error. If you're passing between threads, be sure it's

+//   RefCountedThreadSafe! See "Advanced binding of member functions" below if

+//   you don't want to use reference counting.

+//

+// RUNNING A CALLBACK

+//

+//   Callbacks can be run with their "Run" method, which has the same

+//   signature as the template argument to the callback.

+//

+//   void DoSomething(const base::Callback<void(int, std::string)>& callback) {

+//     callback.Run(5, "hello");

+//   }

+//

+//   Callbacks can be run more than once (they don't get deleted or marked when

+//   run). However, this precludes using base::Passed (see below).

+//

+//   void DoSomething(const base::Callback<double(double)>& callback) {

+//     double myresult = callback.Run(3.14159);

+//     myresult += callback.Run(2.71828);

+//   }

+//

+// PASSING UNBOUND INPUT PARAMETERS

+//

+//   Unbound parameters are specified at the time a callback is Run(). They are

+//   specified in the Callback template type:

+//

+//   void MyFunc(int i, const std::string& str) {}

+//   base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);

+//   cb.Run(23, "hello, world");

+//

+// PASSING BOUND INPUT PARAMETERS

+//

+//   Bound parameters are specified when you create thee callback as arguments

+//   to Bind(). They will be passed to the function and the Run()ner of the

+//   callback doesn't see those values or even know that the function it's

+//   calling.

+//

+//   void MyFunc(int i, const std::string& str) {}

+//   base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");

+//   cb.Run();

+//

+//   A callback with no unbound input parameters (base::Callback<void(void)>)

+//   is called a base::Closure. So we could have also written:

+//

+//   base::Closure cb = base::Bind(&MyFunc, 23, "hello world");

+//

+//   When calling member functions, bound parameters just go after the object

+//   pointer.

+//

+//   base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");

+//

+// PARTIAL BINDING OF PARAMETERS

+//

+//   You can specify some parameters when you create the callback, and specify

+//   the rest when you execute the callback.

+//

+//   void MyFunc(int i, const std::string& str) {}

+//   base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);

+//   cb.Run("hello world");

+//

+//   When calling a function bound parameters are first, followed by unbound

+//   parameters.

+//

+//

+// -----------------------------------------------------------------------------

+// Quick reference for advanced binding

+// -----------------------------------------------------------------------------

+//

+// BINDING A CLASS METHOD WITH WEAK POINTERS

+//

+//   base::Bind(&MyClass::Foo, GetWeakPtr());

+//

+//   The callback will not be 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;

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+  }

+

+  bool Equals(const Callback& other) const {

+    return CallbackBase::Equals(other);

+  }

+

+  R Run() const {

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    PolymorphicInvoke f =

+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+

+    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;

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+  }

+

+  bool Equals(const Callback& other) const {

+    return CallbackBase::Equals(other);

+  }

+

+  R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1) const {

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    PolymorphicInvoke f =

+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+

+    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;

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+  }

+

+  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 {

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    PolymorphicInvoke f =

+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+

+    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;

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+  }

+

+  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 {

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    PolymorphicInvoke f =

+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+

+    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;

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+  }

+

+  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 {

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    PolymorphicInvoke f =

+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+

+    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;

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+  }

+

+  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 {

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    PolymorphicInvoke f =

+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+

+    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;

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+  }

+

+  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 {

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    PolymorphicInvoke f =

+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+

+    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;

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+  }

+

+  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 {

+#if defined(COBALT_WIN)

+#pragma warning(push)

+#pragma warning(disable : 4191)  // Calling this function through the result

+                                 // pointer may cause your program to fail.

+#endif

+    PolymorphicInvoke f =

+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);

+#if defined(COBALT_WIN)

+#pragma warning(pop)

+#endif

+

+    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/src/base/callback.h.pump b/src/base/callback.h.pump
new file mode 100644
index 0000000..b6a0aee
--- /dev/null
+++ b/src/base/callback.h.pump
@@ -0,0 +1,452 @@
+$$ 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 partial application of functions.
+//
+// Partial application (or "currying") is the process of binding a subset of
+// a function's arguments to produce another function that takes fewer
+// arguments. This can be used to pass around a unit of delayed execution,
+// much like lexical closures are used in other languages. For example, it
+// is used in Chromium code to schedule tasks on different MessageLoops.
+//
+// A callback with no unbound input parameters (base::Callback<void(void)>)
+// is called a base::Closure. Note that this is NOT the same as what other
+// languages refer to as a closure -- it does not retain a reference to its
+// enclosing environment.
+//
+// MEMORY MANAGEMENT AND PASSING
+//
+// The Callback objects themselves should be passed by const-reference, and
+// stored by copy. They internally store their state via a refcounted class
+// and thus do not need to be deleted.
+//
+// The reason to pass via a const-reference is to avoid unnecessary
+// AddRef/Release pairs to the internal state.
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for basic stuff
+// -----------------------------------------------------------------------------
+//
+// BINDING A BARE FUNCTION
+//
+//   int Return5() { return 5; }
+//   base::Callback<int(void)> func_cb = base::Bind(&Return5);
+//   LOG(INFO) << func_cb.Run();  // Prints 5.
+//
+// BINDING A CLASS METHOD
+//
+//   The first argument to bind is the member function to call, the second is
+//   the object on which to call it.
+//
+//   class Ref : public base::RefCountedThreadSafe<Ref> {
+//    public:
+//     int Foo() { return 3; }
+//     void PrintBye() { LOG(INFO) << "bye."; }
+//   };
+//   scoped_refptr<Ref> ref = new Ref();
+//   base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
+//   LOG(INFO) << ref_cb.Run();  // Prints out 3.
+//
+//   By default the object must support RefCounted or you will get a compiler
+//   error. If you're passing between threads, be sure it's
+//   RefCountedThreadSafe! See "Advanced binding of member functions" below if
+//   you don't want to use reference counting.
+//
+// RUNNING A CALLBACK
+//
+//   Callbacks can be run with their "Run" method, which has the same
+//   signature as the template argument to the callback.
+//
+//   void DoSomething(const base::Callback<void(int, std::string)>& callback) {
+//     callback.Run(5, "hello");
+//   }
+//
+//   Callbacks can be run more than once (they don't get deleted or marked when
+//   run). However, this precludes using base::Passed (see below).
+//
+//   void DoSomething(const base::Callback<double(double)>& callback) {
+//     double myresult = callback.Run(3.14159);
+//     myresult += callback.Run(2.71828);
+//   }
+//
+// PASSING UNBOUND INPUT PARAMETERS
+//
+//   Unbound parameters are specified at the time a callback is Run(). They are
+//   specified in the Callback template type:
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
+//   cb.Run(23, "hello, world");
+//
+// PASSING BOUND INPUT PARAMETERS
+//
+//   Bound parameters are specified when you create thee callback as arguments
+//   to Bind(). They will be passed to the function and the Run()ner of the
+//   callback doesn't see those values or even know that the function it's
+//   calling.
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
+//   cb.Run();
+//
+//   A callback with no unbound input parameters (base::Callback<void(void)>)
+//   is called a base::Closure. So we could have also written:
+//
+//   base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
+//
+//   When calling member functions, bound parameters just go after the object
+//   pointer.
+//
+//   base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");
+//
+// PARTIAL BINDING OF PARAMETERS
+//
+//   You can specify some parameters when you create the callback, and specify
+//   the rest when you execute the callback.
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);
+//   cb.Run("hello world");
+//
+//   When calling a function bound parameters are first, followed by unbound
+//   parameters.
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for advanced binding
+// -----------------------------------------------------------------------------
+//
+// BINDING A CLASS METHOD WITH WEAK POINTERS
+//
+//   base::Bind(&MyClass::Foo, GetWeakPtr());
+//
+//   The callback will not be 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-$(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;
+#if defined(COBALT_WIN)
+#pragma warning(push)
+#pragma warning(disable : 4191)  // Calling this function through the result
+                                 // pointer may cause your program to fail.
+#endif
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+#if defined(COBALT_WIN)
+#pragma warning(pop)
+#endif
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run($for ARG ,
+        [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const {
+#if defined(COBALT_WIN)
+#pragma warning(push)
+#pragma warning(disable : 4191)  // Calling this function through the result
+                                 // pointer may cause your program to fail.
+#endif
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+#if defined(COBALT_WIN)
+#pragma warning(pop)
+#endif
+
+    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/src/base/callback_forward.h b/src/base/callback_forward.h
new file mode 100644
index 0000000..7983248
--- /dev/null
+++ b/src/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/src/base/callback_helpers.h b/src/base/callback_helpers.h
new file mode 100644
index 0000000..52cb71b
--- /dev/null
+++ b/src/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/src/base/callback_internal.cc b/src/base/callback_internal.cc
new file mode 100644
index 0000000..2dde402
--- /dev/null
+++ b/src/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/src/base/callback_internal.h b/src/base/callback_internal.h
new file mode 100644
index 0000000..2f834c3
--- /dev/null
+++ b/src/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/src/base/callback_unittest.cc b/src/base/callback_unittest.cc
new file mode 100644
index 0000000..2c2bef1
--- /dev/null
+++ b/src/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/src/base/callback_unittest.nc b/src/base/callback_unittest.nc
new file mode 100644
index 0000000..9bddd1f
--- /dev/null
+++ b/src/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/src/base/cancelable_callback.h b/src/base/cancelable_callback.h
new file mode 100644
index 0000000..b781677
--- /dev/null
+++ b/src/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/src/base/cancelable_callback_unittest.cc b/src/base/cancelable_callback_unittest.cc
new file mode 100644
index 0000000..51a2a09
--- /dev/null
+++ b/src/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/src/base/check_example.cc b/src/base/check_example.cc
new file mode 100644
index 0000000..4b3f428
--- /dev/null
+++ b/src/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/src/base/chromeos/chromeos_version.cc b/src/base/chromeos/chromeos_version.cc
new file mode 100644
index 0000000..4a70cd5
--- /dev/null
+++ b/src/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/src/base/chromeos/chromeos_version.h b/src/base/chromeos/chromeos_version.h
new file mode 100644
index 0000000..25acd43
--- /dev/null
+++ b/src/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/src/base/circular_buffer_shell.cc b/src/base/circular_buffer_shell.cc
new file mode 100644
index 0000000..a41d89a
--- /dev/null
+++ b/src/base/circular_buffer_shell.cc
@@ -0,0 +1,251 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/circular_buffer_shell.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(OS_STARBOARD)
+#include "starboard/memory.h"
+#define malloc SbMemoryAllocate
+#define realloc SbMemoryReallocate
+#define free SbMemoryFree
+#endif
+
+static inline void* add_to_pointer(void* pointer, size_t amount) {
+  return static_cast<uint8_t*>(pointer) + amount;
+}
+
+static inline const void* add_to_pointer(const void* pointer, size_t amount) {
+  return static_cast<const uint8_t*>(pointer) + amount;
+}
+
+namespace base {
+
+CircularBufferShell::CircularBufferShell(
+    size_t max_capacity,
+    ReserveType reserve_type /*= kDoNotReserve*/)
+    : max_capacity_(max_capacity),
+      buffer_(NULL),
+      capacity_(0),
+      length_(0),
+      read_position_(0) {
+  if (reserve_type == kReserve) {
+    IncreaseCapacityTo(max_capacity_);
+  }
+}
+
+CircularBufferShell::~CircularBufferShell() {
+  Clear();
+}
+
+void CircularBufferShell::Clear() {
+  base::AutoLock l(lock_);
+  if (buffer_ != NULL) {
+    free(buffer_);
+    buffer_ = NULL;
+  }
+
+  capacity_ = 0;
+  length_ = 0;
+  read_position_ = 0;
+}
+
+void CircularBufferShell::Read(void* destination,
+                               size_t length,
+                               size_t* bytes_read) {
+  base::AutoLock l(lock_);
+  DCHECK(destination != NULL || length == 0);
+  if (destination == NULL)
+    length = 0;
+
+  ReadAndAdvanceUnchecked(destination, length, bytes_read);
+}
+
+void CircularBufferShell::Peek(void* destination,
+                               size_t length,
+                               size_t source_offset,
+                               size_t* bytes_peeked) const {
+  base::AutoLock l(lock_);
+  DCHECK(destination != NULL || length == 0);
+  if (destination == NULL)
+    length = 0;
+
+  ReadUnchecked(destination, length, source_offset, bytes_peeked);
+}
+
+void CircularBufferShell::Skip(size_t length, size_t* bytes_skipped) {
+  base::AutoLock l(lock_);
+  ReadAndAdvanceUnchecked(NULL, length, bytes_skipped);
+}
+
+bool CircularBufferShell::Write(const void* source,
+                                size_t length,
+                                size_t* bytes_written) {
+  base::AutoLock l(lock_);
+  DCHECK(source != NULL || length == 0);
+  if (source == NULL)
+    length = 0;
+
+  if (!EnsureCapacityToWrite(length)) {
+    return false;
+  }
+
+  size_t produced = 0;
+  while (true) {
+    size_t remaining = length - produced;
+
+    // In this pass, write up to the contiguous space left.
+    size_t to_write = std::min(remaining, capacity_ - GetWritePosition());
+    if (to_write == 0)
+      break;
+
+    // Copy this segment and do the accounting.
+    void* destination = GetWritePointer();
+    const void* src = add_to_pointer(source, produced);
+    memcpy(destination, src, to_write);
+    length_ += to_write;
+    produced += to_write;
+  }
+
+  if (bytes_written)
+    *bytes_written = produced;
+  return true;
+}
+
+size_t CircularBufferShell::GetLength() const {
+  base::AutoLock l(lock_);
+  return length_;
+}
+
+void CircularBufferShell::ReadUnchecked(void* destination,
+                                        size_t destination_length,
+                                        size_t source_offset,
+                                        size_t* bytes_read) const {
+  DCHECK(destination != NULL || bytes_read != NULL);
+
+  size_t dummy = 0;
+  if (!bytes_read) {
+    bytes_read = &dummy;
+  }
+
+  // Return immediately if the CircularBuffer is empty or if |source_offset| is
+  // greater or equal than |length_|.
+  if (capacity_ == 0 || source_offset >= length_) {
+    *bytes_read = 0;
+    return;
+  }
+
+  size_t consumed = 0;
+  size_t source_length = length_ - source_offset;
+  size_t read_position = (read_position_ + source_offset) % capacity_;
+
+  while (true) {
+    size_t remaining = std::min(source_length, destination_length - consumed);
+
+    // In this pass, read the remaining data that is contiguous.
+    size_t to_read = std::min(remaining, capacity_ - read_position);
+    if (to_read == 0)
+      break;
+
+    // Copy this segment and do the accounting.
+    const void* source = add_to_pointer(buffer_, read_position);
+    if (destination) {
+      void* dest = add_to_pointer(destination, consumed);
+      memcpy(dest, source, to_read);
+    }
+    source_length -= to_read;
+    read_position = (read_position + to_read) % capacity_;
+    consumed += to_read;
+  }
+
+  *bytes_read = consumed;
+}
+
+void CircularBufferShell::ReadAndAdvanceUnchecked(void* destination,
+                                                  size_t destination_length,
+                                                  size_t* bytes_read) {
+  size_t dummy = 0;
+  if (!bytes_read) {
+    bytes_read = &dummy;
+  }
+
+  // Return immediately if the CircularBuffer is empty.
+  if (capacity_ == 0) {
+    *bytes_read = 0;
+    return;
+  }
+
+  ReadUnchecked(destination, destination_length, 0, bytes_read);
+  length_ -= *bytes_read;
+  read_position_ = (read_position_ + *bytes_read) % capacity_;
+}
+
+void* CircularBufferShell::GetWritePointer() const {
+  return add_to_pointer(buffer_, GetWritePosition());
+}
+
+size_t CircularBufferShell::GetWritePosition() const {
+  return (read_position_ + length_) % capacity_;
+}
+
+bool CircularBufferShell::EnsureCapacityToWrite(size_t length) {
+  if (capacity_ - length_ < length) {
+    size_t capacity = std::max(2 * capacity_, length_ + length);
+    if (capacity > max_capacity_)
+      capacity = max_capacity_;
+
+    // New capacity still won't be enough.
+    if (capacity - length_ < length) {
+      return false;
+    }
+
+    return IncreaseCapacityTo(capacity);
+  }
+
+  return true;
+}
+
+bool CircularBufferShell::IncreaseCapacityTo(size_t capacity) {
+  if (capacity <= capacity_) {
+    return true;
+  }
+
+  // If the data isn't wrapped, we can just use realloc.
+  if (buffer_ != NULL && read_position_ + length_ <= capacity_) {
+    void* result = realloc(buffer_, capacity);
+    if (result == NULL) {
+      return false;
+    }
+    capacity_ = capacity;
+    buffer_ = result;
+    return true;
+  }
+
+  void* buffer = malloc(capacity);
+  if (buffer == NULL) {
+    return false;
+  }
+
+  // Read does everything we want, but it will trounce length_.
+  size_t length = length_;
+
+  // Copy the data over to the new buffer.
+  ReadUnchecked(buffer, length_, 0, NULL);
+
+  // Adjust the accounting.
+  length_ = length;
+  read_position_ = 0;
+  capacity_ = capacity;
+  free(buffer_);
+  buffer_ = buffer;
+  return true;
+}
+
+}  // namespace base
diff --git a/src/base/circular_buffer_shell.h b/src/base/circular_buffer_shell.h
new file mode 100644
index 0000000..4350af1
--- /dev/null
+++ b/src/base/circular_buffer_shell.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CIRCULAR_BUFFER_SHELL_H_
+#define BASE_CIRCULAR_BUFFER_SHELL_H_
+
+#include "base/base_export.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// A thread-safe circular buffer implementation.
+// TODO: Returns the size in Read(), Peek(), and Skip() as a return
+// value.
+class BASE_EXPORT CircularBufferShell {
+ public:
+  enum ReserveType { kDoNotReserve, kReserve };
+
+  CircularBufferShell(size_t max_capacity,
+                      ReserveType reserve_type = kDoNotReserve);
+  ~CircularBufferShell();
+
+  // Clears out all data in the buffer, releasing any allocated memory.
+  // Idempotent.
+  void Clear();
+
+  // Reads the requested amount of data into the given buffer, writing the
+  // number of bytes actually read into the bytes_read paramter. If there is
+  // less data then requested, then the remaining data will be consumed.
+  void Read(void* destination, size_t length, size_t* bytes_read);
+
+  // It works the same as Read() except:
+  // 1. It doesn't modify the buffer in any way.
+  // 2. It allows the caller to specify an offset inside the buffer where the
+  // peek starts.
+  void Peek(void* destination,
+            size_t length,
+            size_t source_offset,
+            size_t* bytes_peeked) const;
+
+  // Advance the buffer cursor without reading any data.
+  void Skip(size_t length, size_t* bytes_skipped);
+
+  // Writes the given data into the circular buffer. Returns false if the buffer
+  // could not be expanded to hold the new data. If returning false,
+  // bytes_written will not be set, and the buffer will remain unchanged.
+  // TODO: Remove bytes_written.  Because Write returns false when
+  // the buffer cannot hold all data, bytes_written isn't useful here unless we
+  // allow partial write.
+  bool Write(const void* source, size_t length, size_t* bytes_written);
+
+  // Returns the length of the data left in the buffer to read.
+  size_t GetLength() const;
+
+ private:
+  // Ensures that there is enough capacity to write length bytes to the
+  // buffer. Returns false if it was unable to ensure that capacity due to an
+  // allocation error, or if it would surpass the configured maximum capacity.
+  bool EnsureCapacityToWrite(size_t length);
+
+  // Increases the capacity to the given absolute size in bytes. Returns false
+  // if there was an allocation error, or it would surpass the configured
+  // maximum capacity.
+  bool IncreaseCapacityTo(size_t capacity);
+
+  // Private workhorse for Read without the parameter validation or locking.
+  // When |destination| is NULL, it purely calculates the the bytes that would
+  // have been read.
+  // Note that the function doesn't advance the read cursor or modify the
+  // length.  It is caller's responsibility to adjust |read_position_| and
+  // |length_| according to the return value, which is the actual number of
+  // bytes read.
+  void ReadUnchecked(void* destination,
+                     size_t destination_length,
+                     size_t source_offset,
+                     size_t* bytes_read) const;
+
+  // The same the as above functions except that it also advance the
+  // |read_position_| and adjust the |length_| accordingly.
+  void ReadAndAdvanceUnchecked(void* destination,
+                               size_t destination_length,
+                               size_t* bytes_read);
+
+  // Gets a pointer to the current write position.
+  void* GetWritePointer() const;
+
+  // Gets the current write position.
+  size_t GetWritePosition() const;
+
+  const size_t max_capacity_;
+  void* buffer_;
+  size_t capacity_;
+  size_t length_;
+  size_t read_position_;
+  mutable base::Lock lock_;
+};
+
+}  // namespace base
+
+#endif  // BASE_CIRCULAR_BUFFER_SHELL_H_
diff --git a/src/base/circular_buffer_shell_unittest.cc b/src/base/circular_buffer_shell_unittest.cc
new file mode 100644
index 0000000..0d4aa1c
--- /dev/null
+++ b/src/base/circular_buffer_shell_unittest.cc
@@ -0,0 +1,454 @@
+/*
+ * Copyright 2014 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "base/circular_buffer_shell.h"
+
+#include <string.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// 100 characters, repeating every 16 characters.
+const char kTestData[] =
+    "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
+    "01234567890ABCDEF0123456789ABCDEF0123";
+
+// 100 characters, repeating every 17 characters.
+#define UNSET_DATA                                      \
+  "GHIJKLMNOPQRSTUVWGHIJKLMNOPQRSTUVWGHIJKLMNOPQRSTUVW" \
+  "GHIJKLMNOPQRSTUVWGHIJKLMNOPQRSTUVWGHIJKLMNOPQRSTU"
+
+const char kUnsetData[] = UNSET_DATA;
+const size_t kUnsetSize = 1024;
+
+// Like memcmp, but reports which index and values failed.
+void IsSame(const char* expected, const char* actual, size_t length) {
+  for (size_t i = 0; i < length; ++i) {
+    if (expected[i] != actual[i]) {
+      EXPECT_EQ(expected[i], actual[i]) << "at " << i;
+      return;
+    }
+  }
+}
+
+size_t read_pos = 0;
+size_t write_pos = 0;
+
+// If the test uses testWrite and TestRead, then it needs to call ClearPos to
+// avoid contamination from previous tests.
+void ClearPos() {
+  read_pos = 0;
+  write_pos = 0;
+}
+
+void TestWrite(base::CircularBufferShell* circular_buffer, size_t to_write) {
+  size_t before_length = circular_buffer->GetLength();
+  size_t bytes_written = kUnsetSize;
+  bool result =
+      circular_buffer->Write(kTestData + write_pos, to_write, &bytes_written);
+  EXPECT_EQ(true, result);
+  EXPECT_EQ(to_write, bytes_written);
+  EXPECT_EQ(before_length + to_write, circular_buffer->GetLength());
+  write_pos += to_write;
+}
+
+void TestRead(base::CircularBufferShell* circular_buffer, size_t to_read) {
+  size_t before_length = circular_buffer->GetLength();
+  char data[] = UNSET_DATA UNSET_DATA;
+  char* buffer = data + strlen(kUnsetData);
+  size_t bytes_read = kUnsetSize;
+  circular_buffer->Read(buffer, to_read, &bytes_read);
+  EXPECT_EQ(to_read, bytes_read);
+  EXPECT_EQ(before_length - to_read, circular_buffer->GetLength());
+  IsSame(kTestData + read_pos, buffer, to_read);
+  IsSame(kUnsetData + to_read, buffer + to_read, to_read);
+  IsSame(kUnsetData + strlen(kUnsetData) - to_read,
+         buffer - to_read, to_read);
+  read_pos += to_read;
+}
+
+}  // namespace
+
+// --- Sunny Day Tests ---
+
+TEST(CircularBufferShellTest, Construct) {
+  ClearPos();
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(20));
+}
+
+TEST(CircularBufferShellTest, SimpleWriteAndRead) {
+  ClearPos();
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(20));
+
+  TestWrite(circular_buffer.get(), 15);
+  TestRead(circular_buffer.get(), 5);
+  TestRead(circular_buffer.get(), 4);
+  TestRead(circular_buffer.get(), 3);
+  TestRead(circular_buffer.get(), 2);
+  TestRead(circular_buffer.get(), 1);
+}
+
+TEST(CircularBufferShellTest, ReadWriteOverBoundary) {
+  ClearPos();
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(20));
+
+  // Fill the buffer.
+  TestWrite(circular_buffer.get(), 20);
+
+  // Read half the data from the front.
+  TestRead(circular_buffer.get(), 10);
+
+  // Fill the back half, making the data wrap around the end.
+  TestWrite(circular_buffer.get(), 10);
+
+  // Read the whole thing, which should require two memcpys.
+  TestRead(circular_buffer.get(), 20);
+
+  // Fill the buffer, again around the end, should require two memcpys.
+  TestWrite(circular_buffer.get(), 20);
+
+  // Read the buffer to verify, should again require two memcpys.
+  TestRead(circular_buffer.get(), 20);
+}
+
+TEST(CircularBufferShellTest, ExpandWhileNotWrapped) {
+  ClearPos();
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(20));
+
+  // Set the size with the first write.
+  TestWrite(circular_buffer.get(), 5);
+
+  // Expand with the second write.
+  TestWrite(circular_buffer.get(), 5);
+
+  // Read to verify the data is intact
+  TestRead(circular_buffer.get(), 10);
+}
+
+TEST(CircularBufferShellTest, ExpandWhileNotWrapped2) {
+  ClearPos();
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(20));
+
+  // Set the size with the first write.
+  TestWrite(circular_buffer.get(), 5);
+
+  // Read a couple out so that the data doesn't start at the beginning of the
+  // buffer.
+  TestRead(circular_buffer.get(), 2);
+
+  // Expand with the second write.
+  TestWrite(circular_buffer.get(), 5);
+
+  // Read to verify the data is intact
+  TestRead(circular_buffer.get(), 8);
+}
+
+TEST(CircularBufferShellTest, ExpandWhileWrapped) {
+  ClearPos();
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(20));
+
+  // Set the size with the first write.
+  TestWrite(circular_buffer.get(), 10);
+
+  // Read front half.
+  TestRead(circular_buffer.get(), 5);
+
+  // Wrap with second write
+  TestWrite(circular_buffer.get(), 5);
+
+  // Write again to expand while wrapped.
+  TestWrite(circular_buffer.get(), 5);
+
+  // Read to verify the data is intact
+  TestRead(circular_buffer.get(), 15);
+}
+
+// --- Rainy Day Tests ---
+
+TEST(CircularBufferShellTest, WriteTooMuch) {
+  ClearPos();
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(20));
+
+  {
+    size_t bytes_written = kUnsetSize;
+    bool result = circular_buffer->Write(kTestData, 25, &bytes_written);
+    EXPECT_EQ(false, result);
+    EXPECT_EQ(kUnsetSize, bytes_written);
+    EXPECT_EQ(0, circular_buffer->GetLength());
+  }
+}
+
+TEST(CircularBufferShellTest, ReadEmpty) {
+  ClearPos();
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(20));
+
+  EXPECT_EQ(circular_buffer->GetLength(), 0);
+
+  {
+    char buffer[] = UNSET_DATA;
+    size_t bytes_read = kUnsetSize;
+    circular_buffer->Read(buffer, 0, &bytes_read);
+    EXPECT_EQ(0, bytes_read);
+    EXPECT_EQ(0, circular_buffer->GetLength());
+    IsSame(kUnsetData, buffer, 10);
+  }
+
+  {
+    char buffer[] = UNSET_DATA;
+    size_t bytes_read = kUnsetSize;
+    circular_buffer->Read(buffer, 10, &bytes_read);
+    EXPECT_EQ(0, bytes_read);
+    EXPECT_EQ(0, circular_buffer->GetLength());
+    IsSame(kUnsetData, buffer, 10);
+  }
+}
+
+TEST(CircularBufferShellTest, ReadToNull) {
+  ClearPos();
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(20));
+
+  {
+    size_t bytes_read = kUnsetSize;
+    circular_buffer->Read(NULL, 0, &bytes_read);
+    EXPECT_EQ(0, bytes_read);
+  }
+}
+
+TEST(CircularBufferShellTest, Peek) {
+  const size_t kMaxCapacity = 20;
+  base::CircularBufferShell circular_buffer(kMaxCapacity);
+  size_t bytes_peeked;
+  size_t peek_offset = 0;
+
+  circular_buffer.Write(kTestData, kMaxCapacity, NULL);
+
+  // Peek with offset 0.
+  {
+    char destination[] = UNSET_DATA;
+    circular_buffer.Peek(destination + 9, 10, peek_offset, &bytes_peeked);
+
+    EXPECT_EQ(10, bytes_peeked);
+    IsSame(UNSET_DATA, destination, 9);
+    IsSame(UNSET_DATA + 9 + bytes_peeked,
+           destination + 9 + bytes_peeked,
+           sizeof(UNSET_DATA) - 9 - bytes_peeked);
+    IsSame(kTestData, destination + 9, 10);
+    peek_offset += bytes_peeked;
+  }
+
+  // Peek with non-zero offset.
+  {
+    char destination[] = UNSET_DATA;
+    circular_buffer.Peek(destination + 9, 7, peek_offset, &bytes_peeked);
+
+    EXPECT_EQ(7, bytes_peeked);
+    IsSame(UNSET_DATA, destination, 9);
+    IsSame(UNSET_DATA + 9 + bytes_peeked,
+           destination + 9 + bytes_peeked,
+           sizeof(UNSET_DATA) - 9 - bytes_peeked);
+    IsSame(kTestData + peek_offset, destination + 9, bytes_peeked);
+    peek_offset += bytes_peeked;
+  }
+
+  // Peek more data than available.
+  {
+    char destination[] = UNSET_DATA;
+    circular_buffer.Peek(destination + 9, 7, peek_offset, &bytes_peeked);
+
+    EXPECT_EQ(3, bytes_peeked);
+    IsSame(UNSET_DATA, destination, 9);
+    IsSame(UNSET_DATA + 9 + bytes_peeked,
+           destination + 9 + bytes_peeked,
+           sizeof(UNSET_DATA) - 9 - bytes_peeked);
+    IsSame(kTestData + peek_offset, destination + 9, bytes_peeked);
+    peek_offset += bytes_peeked;
+  }
+
+  // Peek an empty buffer.
+  {
+    char destination[] = UNSET_DATA;
+    circular_buffer.Peek(destination + 9, 7, peek_offset, &bytes_peeked);
+
+    IsSame(UNSET_DATA, destination, sizeof(destination));
+    EXPECT_EQ(0, bytes_peeked);
+    // Verify that we are actually peeking instead of reading.
+    EXPECT_EQ(kMaxCapacity, circular_buffer.GetLength());
+  }
+}
+
+TEST(CircularBufferShellTest, Skip) {
+  const size_t kMaxCapacity = 20;
+  base::CircularBufferShell circular_buffer(kMaxCapacity);
+  char destination[] = UNSET_DATA UNSET_DATA;
+  size_t bytes;
+
+  circular_buffer.Write(kTestData, kMaxCapacity, NULL);
+  circular_buffer.Skip(10, &bytes);
+  EXPECT_EQ(10, bytes);
+  EXPECT_EQ(kMaxCapacity - 10, circular_buffer.GetLength());
+
+  circular_buffer.Read(destination, kMaxCapacity, &bytes);
+
+  EXPECT_EQ(kMaxCapacity - 10, bytes);
+  IsSame(kTestData + 10, destination, bytes);
+}
+
+TEST(CircularBufferShellTest, PeekWrapped) {
+  const size_t kMaxCapacity = 20;
+  base::CircularBufferShell circular_buffer(kMaxCapacity);
+  char destination[] = UNSET_DATA;
+  size_t bytes_peeked;
+
+  circular_buffer.Write(kTestData, kMaxCapacity, NULL);
+
+  // Skip 10 bytes to free some space.
+  circular_buffer.Skip(10, &bytes_peeked);
+
+  // Fill the free space with new data.
+  circular_buffer.Write(kTestData + kMaxCapacity, 10, NULL);
+  EXPECT_EQ(kMaxCapacity, circular_buffer.GetLength());
+
+  // Peek with a non-zero offset.
+  circular_buffer.Peek(destination, kMaxCapacity, 5, &bytes_peeked);
+
+  EXPECT_EQ(kMaxCapacity - 5, bytes_peeked);
+  IsSame(kTestData + 15, destination, bytes_peeked);
+}
+
+TEST(CircularBufferShellTest, SkipWrapped) {
+  const size_t kMaxCapacity = 20;
+  base::CircularBufferShell circular_buffer(kMaxCapacity);
+  char destination[] = UNSET_DATA;
+  size_t bytes;
+
+  circular_buffer.Write(kTestData, kMaxCapacity, NULL);
+  circular_buffer.Skip(10, &bytes);
+
+  circular_buffer.Write(kTestData + kMaxCapacity, 10, NULL);
+  EXPECT_EQ(kMaxCapacity, circular_buffer.GetLength());
+
+  circular_buffer.Skip(kMaxCapacity - 5, NULL);
+  EXPECT_EQ(5, circular_buffer.GetLength());
+
+  circular_buffer.Read(destination, 5, &bytes);
+  EXPECT_EQ(5, bytes);
+  IsSame(kTestData + kMaxCapacity + 5, destination, 5);
+}
+
+// --- Legacy Tests ---
+
+TEST(CircularBufferShellTest, Basic) {
+  const int max_buffer_length = 10;
+  const int kReadSize1 = 4;
+  const int kReadSize2 = 2;
+  const int kReadSize3 = 4;
+  const int kReadSize4 = 6;
+
+  // Create a Circular Buffer.
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(max_buffer_length));
+  ASSERT_TRUE(circular_buffer);
+  EXPECT_EQ(circular_buffer->GetLength(), 0);
+
+  char read_buffer[20];
+  size_t bytes_read = 0;
+  size_t bytes_written = 0;
+  // Read 4 bytes, got read_pos 0, write_pos 0
+  circular_buffer->Read(read_buffer, kReadSize1, &bytes_read);
+  EXPECT_EQ(bytes_read, 0);
+
+  // Write 5 bytes, got read_pos 0, write_pos 5
+  const char write_buffer[] = "hello";
+  circular_buffer->Write(write_buffer, strlen(write_buffer), &bytes_written);
+  EXPECT_EQ(bytes_written, strlen(write_buffer));
+  EXPECT_EQ(circular_buffer->GetLength(), strlen(write_buffer));
+
+  // Write 1 byte, increased buffer size to 10, read_pos 0, write_pos 6
+  const char write_buffer2[] = " ";
+  circular_buffer->Write(write_buffer2, strlen(write_buffer2), &bytes_written);
+  EXPECT_EQ(bytes_written, strlen(write_buffer2));
+  EXPECT_EQ(circular_buffer->GetLength(),
+            strlen(write_buffer) + strlen(write_buffer2));
+
+  // Read 2 bytes, got read_pos 2, write_pos 6
+  circular_buffer->Read(read_buffer, kReadSize2, &bytes_read);
+  EXPECT_EQ(0, memcmp(read_buffer, "he", kReadSize2));
+  EXPECT_EQ(bytes_read, kReadSize2);
+  EXPECT_EQ(circular_buffer->GetLength(),
+            strlen(write_buffer) + strlen(write_buffer2) - kReadSize2);
+
+  // Write 6 bytes, got read_pos 2, write_pos 2, full of data
+  const char write_buffer3[] = "world!";
+  circular_buffer->Write(write_buffer3, strlen(write_buffer3), &bytes_written);
+  EXPECT_EQ(bytes_written, strlen(write_buffer3));
+  EXPECT_EQ(circular_buffer->GetLength(),
+            strlen(write_buffer) + strlen(write_buffer2) +
+                strlen(write_buffer3) - kReadSize2);
+
+  // Read 4 bytes, got read_pos 6, write_pos 2
+  circular_buffer->Read(read_buffer, kReadSize3, &bytes_read);
+  EXPECT_EQ(bytes_read, kReadSize3);
+  EXPECT_EQ(0, memcmp(read_buffer, "llo ", kReadSize3));
+  EXPECT_EQ(circular_buffer->GetLength(),
+            strlen(write_buffer) + strlen(write_buffer2) +
+                strlen(write_buffer3) - kReadSize2 - kReadSize3);
+
+  // Read 6 bytes, got read_pos 2, write_pos 2, empty
+  circular_buffer->Read(read_buffer, kReadSize4, &bytes_read);
+  EXPECT_EQ(bytes_read, kReadSize4);
+  EXPECT_EQ(0, memcmp(read_buffer, "world!", kReadSize4));
+  EXPECT_EQ(circular_buffer->GetLength(), 0);
+}
+
+TEST(CircularBufferShellTest, CycleReadWrite) {
+  const int max_buffer_length = 5000;
+  // Create a Circular Buffer.
+  scoped_ptr<base::CircularBufferShell> circular_buffer(
+      new base::CircularBufferShell(max_buffer_length));
+  ASSERT_TRUE(circular_buffer);
+  EXPECT_EQ(circular_buffer->GetLength(), 0);
+
+  size_t bytes_written = 0;
+  size_t bytes_read = 0;
+  char write_buffer[500];
+  char read_buffer[2000];
+
+  for (int i = 0; i < 50; ++i) {
+    circular_buffer->Write(write_buffer, sizeof(write_buffer), &bytes_written);
+    EXPECT_EQ(bytes_written, sizeof(write_buffer));
+    EXPECT_EQ(circular_buffer->GetLength(), sizeof(write_buffer));
+
+    circular_buffer->Write(write_buffer, sizeof(write_buffer), &bytes_written);
+    EXPECT_EQ(bytes_written, sizeof(write_buffer));
+    EXPECT_EQ(circular_buffer->GetLength(),
+              sizeof(write_buffer) + sizeof(write_buffer));
+
+    circular_buffer->Read(read_buffer, sizeof(read_buffer), &bytes_read);
+    EXPECT_EQ(bytes_read, sizeof(write_buffer) + sizeof(write_buffer));
+    EXPECT_EQ(circular_buffer->GetLength(), 0);
+  }
+}
diff --git a/src/base/command_line.cc b/src/base/command_line.cc
new file mode 100644
index 0000000..66fe11a
--- /dev/null
+++ b/src/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) || defined(OS_STARBOARD)
+// 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) || defined(OS_STARBOARD)
+      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) || defined(OS_STARBOARD)
+  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) || defined(OS_STARBOARD)
+  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) || defined(OS_STARBOARD)
+  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) || defined(OS_STARBOARD)
+  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) || defined(OS_STARBOARD)
+  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/src/base/command_line.h b/src/base/command_line.h
new file mode 100644
index 0000000..fcb7032
--- /dev/null
+++ b/src/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) || defined(OS_STARBOARD)
+  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/src/base/command_line_unittest.cc b/src/base/command_line_unittest.cc
new file mode 100644
index 0000000..b9ee650
--- /dev/null
+++ b/src/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) || defined(OS_STARBOARD)
+  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/src/base/compiler_specific.h b/src/base/compiler_specific.h
new file mode 100644
index 0000000..789aa1e
--- /dev/null
+++ b/src/base/compiler_specific.h
@@ -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.
+
+#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
+
+#if !defined(UNREFERENCED_PARAMETER)
+#define UNREFERENCED_PARAMETER(x) (x)
+#endif
+#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
+#if !defined(UNREFERENCED_PARAMETER)
+#define UNREFERENCED_PARAMETER(x) \
+  do {                            \
+    (void)(x);                    \
+  } while (0)
+#endif
+#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) || defined(COMPILER_GCC)
+#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/src/base/containers/linked_hash_map.h b/src/base/containers/linked_hash_map.h
new file mode 100644
index 0000000..070e121
--- /dev/null
+++ b/src/base/containers/linked_hash_map.h
@@ -0,0 +1,241 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This is a simplistic insertion-ordered map.  It behaves similarly to an STL
+// map, but only implements a small subset of the map's methods.  Internally, we
+// just keep a map and a list going in parallel.
+//
+// This class provides no thread safety guarantees, beyond what you would
+// normally see with std::list.
+//
+// Iterators should be stable in the face of mutations, except for an
+// iterator pointing to an element that was just deleted.
+
+#ifndef BASE_CONTAINERS_LINKED_HASH_MAP_H_
+#define BASE_CONTAINERS_LINKED_HASH_MAP_H_
+
+#include <list>
+#include <utility>
+
+#include "base/hash_tables.h"
+#include "base/logging.h"
+
+namespace base {
+
+// This holds a list of pair<Key, Value> items.  This list is what gets
+// traversed, and it's iterators from this list that we return from
+// begin/end/find.
+//
+// We also keep a map<Key, list::iterator> for find.  Since std::list is a
+// doubly-linked list, the iterators should remain stable.
+template<class Key, class Value>
+class linked_hash_map {
+ private:
+  typedef std::list<std::pair<Key, Value> > ListType;
+  typedef base::hash_map<Key, typename ListType::iterator> MapType;
+
+ public:
+  typedef typename ListType::iterator iterator;
+  typedef typename ListType::reverse_iterator reverse_iterator;
+  typedef typename ListType::const_iterator const_iterator;
+  typedef typename ListType::const_reverse_iterator const_reverse_iterator;
+  typedef typename MapType::key_type key_type;
+  typedef typename ListType::value_type value_type;
+  typedef typename ListType::size_type size_type;
+
+  linked_hash_map() : map_(), list_() {
+  }
+
+  // Returns an iterator to the first (insertion-ordered) element.  Like a map,
+  // this can be dereferenced to a pair<Key, Value>.
+  iterator begin() {
+    return list_.begin();
+  }
+  const_iterator begin() const {
+    return list_.begin();
+  }
+
+  // Returns an iterator beyond the last element.
+  iterator end() {
+    return list_.end();
+  }
+  const_iterator end() const {
+    return list_.end();
+  }
+
+  // Returns an iterator to the last (insertion-ordered) element.  Like a map,
+  // this can be dereferenced to a pair<Key, Value>.
+  reverse_iterator rbegin() {
+    return list_.rbegin();
+  }
+  const_reverse_iterator rbegin() const {
+    return list_.rbegin();
+  }
+
+  // Returns an iterator beyond the first element.
+  reverse_iterator rend() {
+    return list_.rend();
+  }
+  const_reverse_iterator rend() const {
+    return list_.rend();
+  }
+
+  // Front and back accessors common to many stl containers.
+
+  // Returns the earliest-inserted element
+  const value_type& front() const {
+    return list_.front();
+  }
+
+  // Returns the earliest-inserted element.
+  value_type& front() {
+    return list_.front();
+  }
+
+  // Returns the most-recently-inserted element.
+  const value_type& back() const {
+    return list_.back();
+  }
+
+  // Returns the most-recently-inserted element.
+  value_type& back() {
+    return list_.back();
+  }
+
+  // Clears the map of all values.
+  void clear() {
+    map_.clear();
+    list_.clear();
+  }
+
+  // Returns true iff the map is empty.
+  bool empty() const {
+    return list_.empty();
+  }
+
+  // Erases values with the provided key.  Returns the number of elements
+  // erased.  In this implementation, this will be 0 or 1.
+  size_type erase(const Key& key) {
+    typename MapType::iterator found = map_.find(key);
+    if (found == map_.end()) return 0;
+
+    list_.erase(found->second);
+    map_.erase(found);
+
+    return 1;
+  }
+
+  // Erases the item that 'position' points to. Returns an iterator that points
+  // to the item that comes immediately after the deleted item in the list, or
+  // end().
+  // If the provided iterator is invalid or there is inconsistency between the
+  // map and list, a CHECK() error will occur.
+  iterator erase(iterator position) {
+    typename MapType::iterator found = map_.find(position->first);
+    CHECK(found->second == position)
+        << "Inconsisent iterator for map and list, or the iterator is invalid.";
+
+    map_.erase(found);
+    return list_.erase(position);
+  }
+
+  // Erases all the items in the range [first, last).  Returns an iterator that
+  // points to the item that comes immediately after the last deleted item in
+  // the list, or end().
+  iterator erase(iterator first, iterator last) {
+    while (first != last && first != end()) {
+      first = erase(first);
+    }
+    return first;
+  }
+
+  // Finds the element with the given key.  Returns an iterator to the
+  // value found, or to end() if the value was not found.  Like a map, this
+  // iterator points to a pair<Key, Value>.
+  iterator find(const Key& key) {
+    typename MapType::iterator found = map_.find(key);
+    if (found == map_.end()) {
+      return end();
+    }
+    return found->second;
+  }
+
+  const_iterator find(const Key& key) const {
+    typename MapType::const_iterator found = map_.find(key);
+    if (found == map_.end()) {
+      return end();
+    }
+    return found->second;
+  }
+
+  // Returns the bounds of a range that includes all the elements in the
+  // container with a key that compares equal to x.
+  std::pair<iterator, iterator> equal_range(const key_type& key) {
+    std::pair<typename MapType::iterator, typename MapType::iterator> eq_range =
+        map_.equal_range(key);
+
+    return std::make_pair(eq_range.first->second, eq_range.second->second);
+  }
+
+  std::pair<const_iterator, const_iterator> equal_range(
+      const key_type& key) const {
+    std::pair<typename MapType::const_iterator,
+        typename MapType::const_iterator> eq_range =
+        map_.equal_range(key);
+    const const_iterator& start_iter = eq_range.first != map_.end() ?
+        eq_range.first->second : end();
+    const const_iterator& end_iter = eq_range.second != map_.end() ?
+        eq_range.second->second : end();
+
+    return std::make_pair(start_iter, end_iter);
+  }
+
+  // Returns the value mapped to key, or an inserted iterator to that position
+  // in the map.
+  Value& operator[](const key_type& key) {
+    return (*((this->insert(std::make_pair(key, Value()))).first)).second;
+  }
+
+  // Inserts an element into the map
+  std::pair<iterator, bool> insert(const std::pair<Key, Value>& pair) {
+    // First make sure the map doesn't have a key with this value.  If it does,
+    // return a pair with an iterator to it, and false indicating that we
+    // didn't insert anything.
+    typename MapType::iterator found = map_.find(pair.first);
+    if (found != map_.end()) return std::make_pair(found->second, false);
+
+    // Otherwise, insert into the list first.
+    list_.push_back(pair);
+
+    // Obtain an iterator to the newly added element.  We do -- instead of -
+    // since list::iterator doesn't implement operator-().
+    typename ListType::iterator last = list_.end();
+    --last;
+
+    CHECK(map_.insert(std::make_pair(pair.first, last)).second)
+        << "Map and list are inconsistent";
+
+    return std::make_pair(last, true);
+  }
+
+  size_type size() const {
+    return list_.size();
+  }
+
+  void swap(linked_hash_map& other) {
+    map_.swap(other.map_);
+    list_.swap(other.list_);
+  }
+
+ private:
+  // The map component, used for speedy lookups
+  MapType map_;
+
+  // The list component, used for maintaining insertion order
+  ListType list_;
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_LINKED_HASH_MAP_H_
diff --git a/src/base/containers/linked_list.h b/src/base/containers/linked_list.h
new file mode 100644
index 0000000..25bbe76
--- /dev/null
+++ b/src/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/src/base/containers/linked_list_unittest.cc b/src/base/containers/linked_list_unittest.cc
new file mode 100644
index 0000000..801e302
--- /dev/null
+++ b/src/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/src/base/containers/mru_cache.h b/src/base/containers/mru_cache.h
new file mode 100644
index 0000000..f9fb308
--- /dev/null
+++ b/src/base/containers/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_CONTAINERS_MRU_CACHE_H_
+#define BASE_CONTAINERS_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_CONTAINERS_MRU_CACHE_H_
diff --git a/src/base/containers/mru_cache_unittest.cc b/src/base/containers/mru_cache_unittest.cc
new file mode 100644
index 0000000..644f38a
--- /dev/null
+++ b/src/base/containers/mru_cache_unittest.cc
@@ -0,0 +1,271 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/containers/mru_cache.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int cached_item_live_count = 0;
+
+struct CachedItem {
+  CachedItem() : value(0) {
+    cached_item_live_count++;
+  }
+
+  explicit CachedItem(int new_value) : value(new_value) {
+    cached_item_live_count++;
+  }
+
+  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/src/base/containers/small_map.h b/src/base/containers/small_map.h
new file mode 100644
index 0000000..e00e012
--- /dev/null
+++ b/src/base/containers/small_map.h
@@ -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.
+
+#ifndef BASE_CONTAINERS_SMALL_MAP_H_
+#define BASE_CONTAINERS_SMALL_MAP_H_
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/manual_constructor.h"
+
+// Disable warning about conversion from '__int64' to 'int'. This value is based
+// on the number of elements in the array, and the program would crash from
+// running out of memory long before the max int value was reached.
+MSVC_PUSH_DISABLE_WARNING(4244)
+// Disable warning about calling an uninitialized object's methods.  In this
+// case, the uninitialized object is ManualConstructor and its method is
+// aware that it is uninitialized.
+MSVC_PUSH_DISABLE_WARNING(6001)
+// Disable warning about reading invalid data from the array. The array offset
+// index is determined by the array_iter, which will not go past the end of
+// the array.
+MSVC_PUSH_DISABLE_WARNING(6385)
+
+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) {
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
+      int i = position.array_iter_ - array_;
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+      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
+
+MSVC_POP_WARNING()
+MSVC_POP_WARNING()
+MSVC_POP_WARNING()
+
+#endif  // BASE_CONTAINERS_SMALL_MAP_H_
diff --git a/src/base/containers/small_map_unittest.cc b/src/base/containers/small_map_unittest.cc
new file mode 100644
index 0000000..d1c8680
--- /dev/null
+++ b/src/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/src/base/containers/stack_container.h b/src/base/containers/stack_container.h
new file mode 100644
index 0000000..b3e508b
--- /dev/null
+++ b/src/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/src/base/containers/stack_container_unittest.cc b/src/base/containers/stack_container_unittest.cc
new file mode 100644
index 0000000..3a1b3ed
--- /dev/null
+++ b/src/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/src/base/cpu.cc b/src/base/cpu.cc
new file mode 100644
index 0000000..cf4f2f1
--- /dev/null
+++ b/src/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/src/base/cpu.h b/src/base/cpu.h
new file mode 100644
index 0000000..957b1a5
--- /dev/null
+++ b/src/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/src/base/cpu_unittest.cc b/src/base/cpu_unittest.cc
new file mode 100644
index 0000000..d059dee
--- /dev/null
+++ b/src/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/src/base/critical_closure.h b/src/base/critical_closure.h
new file mode 100644
index 0000000..ca51ed5
--- /dev/null
+++ b/src/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/src/base/critical_closure_ios.mm b/src/base/critical_closure_ios.mm
new file mode 100644
index 0000000..156612b
--- /dev/null
+++ b/src/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/src/base/data/file_util_unittest/binary_file.bin b/src/base/data/file_util_unittest/binary_file.bin
new file mode 100644
index 0000000..f53cc82
--- /dev/null
+++ b/src/base/data/file_util_unittest/binary_file.bin
Binary files differ
diff --git a/src/base/data/file_util_unittest/binary_file_diff.bin b/src/base/data/file_util_unittest/binary_file_diff.bin
new file mode 100644
index 0000000..103b26d
--- /dev/null
+++ b/src/base/data/file_util_unittest/binary_file_diff.bin
Binary files differ
diff --git a/src/base/data/file_util_unittest/binary_file_same.bin b/src/base/data/file_util_unittest/binary_file_same.bin
new file mode 100644
index 0000000..f53cc82
--- /dev/null
+++ b/src/base/data/file_util_unittest/binary_file_same.bin
Binary files differ
diff --git a/src/base/data/file_util_unittest/blank_line.txt b/src/base/data/file_util_unittest/blank_line.txt
new file mode 100644
index 0000000..8892069
--- /dev/null
+++ b/src/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/src/base/data/file_util_unittest/blank_line_crlf.txt b/src/base/data/file_util_unittest/blank_line_crlf.txt
new file mode 100644
index 0000000..3aefe52
--- /dev/null
+++ b/src/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/src/base/data/file_util_unittest/crlf.txt b/src/base/data/file_util_unittest/crlf.txt
new file mode 100644
index 0000000..0e62728
--- /dev/null
+++ b/src/base/data/file_util_unittest/crlf.txt
@@ -0,0 +1 @@
+This file is the same.

diff --git a/src/base/data/file_util_unittest/different.txt b/src/base/data/file_util_unittest/different.txt
new file mode 100644
index 0000000..5b9f9c4
--- /dev/null
+++ b/src/base/data/file_util_unittest/different.txt
@@ -0,0 +1 @@
+This file is different.
diff --git a/src/base/data/file_util_unittest/different_first.txt b/src/base/data/file_util_unittest/different_first.txt
new file mode 100644
index 0000000..8661d66
--- /dev/null
+++ b/src/base/data/file_util_unittest/different_first.txt
@@ -0,0 +1 @@
+this file is the same.
diff --git a/src/base/data/file_util_unittest/different_last.txt b/src/base/data/file_util_unittest/different_last.txt
new file mode 100644
index 0000000..e8b3e5a
--- /dev/null
+++ b/src/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/src/base/data/file_util_unittest/empty1.txt b/src/base/data/file_util_unittest/empty1.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/base/data/file_util_unittest/empty1.txt
diff --git a/src/base/data/file_util_unittest/empty2.txt b/src/base/data/file_util_unittest/empty2.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/base/data/file_util_unittest/empty2.txt
diff --git a/src/base/data/file_util_unittest/first1.txt b/src/base/data/file_util_unittest/first1.txt
new file mode 100644
index 0000000..2c6e300
--- /dev/null
+++ b/src/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/src/base/data/file_util_unittest/first2.txt b/src/base/data/file_util_unittest/first2.txt
new file mode 100644
index 0000000..e39b5ec
--- /dev/null
+++ b/src/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/src/base/data/file_util_unittest/original.txt b/src/base/data/file_util_unittest/original.txt
new file mode 100644
index 0000000..4422f57
--- /dev/null
+++ b/src/base/data/file_util_unittest/original.txt
@@ -0,0 +1 @@
+This file is the same.
diff --git a/src/base/data/file_util_unittest/same.txt b/src/base/data/file_util_unittest/same.txt
new file mode 100644
index 0000000..4422f57
--- /dev/null
+++ b/src/base/data/file_util_unittest/same.txt
@@ -0,0 +1 @@
+This file is the same.
diff --git a/src/base/data/file_util_unittest/same_length.txt b/src/base/data/file_util_unittest/same_length.txt
new file mode 100644
index 0000000..157405c
--- /dev/null
+++ b/src/base/data/file_util_unittest/same_length.txt
@@ -0,0 +1 @@
+This file is not same.
diff --git a/src/base/data/file_util_unittest/shortened.txt b/src/base/data/file_util_unittest/shortened.txt
new file mode 100644
index 0000000..2bee82c
--- /dev/null
+++ b/src/base/data/file_util_unittest/shortened.txt
@@ -0,0 +1 @@
+This file is the
\ No newline at end of file
diff --git a/src/base/data/file_version_info_unittest/FileVersionInfoTest1.dll b/src/base/data/file_version_info_unittest/FileVersionInfoTest1.dll
new file mode 100755
index 0000000..bdf8dc0
--- /dev/null
+++ b/src/base/data/file_version_info_unittest/FileVersionInfoTest1.dll
Binary files differ
diff --git a/src/base/data/file_version_info_unittest/FileVersionInfoTest2.dll b/src/base/data/file_version_info_unittest/FileVersionInfoTest2.dll
new file mode 100755
index 0000000..51e7966
--- /dev/null
+++ b/src/base/data/file_version_info_unittest/FileVersionInfoTest2.dll
Binary files differ
diff --git a/src/base/data/json/bom_feff.json b/src/base/data/json/bom_feff.json
new file mode 100644
index 0000000..b05ae50
--- /dev/null
+++ b/src/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/src/base/debug/alias.cc b/src/base/debug/alias.cc
new file mode 100644
index 0000000..6b0caaa
--- /dev/null
+++ b/src/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/src/base/debug/alias.h b/src/base/debug/alias.h
new file mode 100644
index 0000000..3b2ab64
--- /dev/null
+++ b/src/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/src/base/debug/debug_on_start_win.cc b/src/base/debug/debug_on_start_win.cc
new file mode 100644
index 0000000..6ca88dd
--- /dev/null
+++ b/src/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/src/base/debug/debug_on_start_win.h b/src/base/debug/debug_on_start_win.h
new file mode 100644
index 0000000..edcaa0a
--- /dev/null
+++ b/src/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/src/base/debug/debugger.cc b/src/base/debug/debugger.cc
new file mode 100644
index 0000000..a297ed1
--- /dev/null
+++ b/src/base/debug/debugger.cc
@@ -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.
+
+#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) {
+#if defined(__LB_ANDROID__)
+        // Hack around a race condition where the debugger is still attaching
+        // and isn't ready to catch the trap thrown by BreakDebugger yet.
+        PlatformThread::Sleep(TimeDelta::FromSeconds(5));
+#endif
+        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/src/base/debug/debugger.h b/src/base/debug/debugger.h
new file mode 100644
index 0000000..4f368d9
--- /dev/null
+++ b/src/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/src/base/debug/debugger_posix.cc b/src/base/debug/debugger_posix.cc
new file mode 100644
index 0000000..edfbbe1
--- /dev/null
+++ b/src/base/debug/debugger_posix.cc
@@ -0,0 +1,273 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/debugger.h"
+#include "build/build_config.h"
+
+#if defined(__LB_SHELL__)
+#include "lb_platform.h"
+#endif
+
+#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/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.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 || defined(__LB_SHELL__)
+  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() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+  //
+  // While some code used below may be async-signal unsafe, note how
+  // the result is cached (see |is_set| and |being_debugged| static variables
+  // right below). If this code is properly warmed-up early
+  // in the start-up process, it should be safe to use later.
+
+  // If the process is sandboxed then we can't use the sysctl, so cache the
+  // value.
+  static bool is_set = false;
+  static bool being_debugged = false;
+
+  if (is_set)
+    return being_debugged;
+
+  // Initialize mib, which tells sysctl what info we want.  In this case,
+  // we're looking for information about a specific process ID.
+  int mib[] = {
+    CTL_KERN,
+    KERN_PROC,
+    KERN_PROC_PID,
+    getpid()
+#if defined(OS_OPENBSD)
+    , sizeof(struct kinfo_proc),
+    0
+#endif
+  };
+
+  // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE.  The source and
+  // binary interfaces may change.
+  struct kinfo_proc info;
+  size_t info_size = sizeof(info);
+
+#if defined(OS_OPENBSD)
+  if (sysctl(mib, arraysize(mib), NULL, &info_size, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (info_size / sizeof(struct kinfo_proc));
+#endif
+
+  int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
+  DCHECK_EQ(sysctl_result, 0);
+  if (sysctl_result != 0) {
+    is_set = true;
+    being_debugged = false;
+    return being_debugged;
+  }
+
+  // This process is being debugged if the P_TRACED flag is set.
+  is_set = true;
+#if defined(OS_FREEBSD)
+  being_debugged = (info.ki_flag & P_TRACED) != 0;
+#elif defined(OS_BSD)
+  being_debugged = (info.p_flag & P_TRACED) != 0;
+#else
+  being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
+#endif
+  return being_debugged;
+}
+
+#elif defined(OS_LINUX) || defined(OS_ANDROID)
+
+// We can look in /proc/self/status for TracerPid.  We are likely used in crash
+// handling, so we are careful not to use the heap or have side effects.
+// Another option that is common is to try to ptrace yourself, but then we
+// can't detach without forking(), and that's not so great.
+// static
+bool BeingDebugged() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+  int status_fd = open("/proc/self/status", O_RDONLY);
+  if (status_fd == -1)
+    return false;
+
+  // We assume our line will be in the first 1024 characters and that we can
+  // read this much all at once.  In practice this will generally be true.
+  // This simplifies and speeds up things considerably.
+  char buf[1024];
+
+  ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
+  if (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';
+}
+
+#elif defined(__LB_SHELL__)
+
+bool BeingDebugged() {
+  return LB::Platform::BeingDebugged();
+}
+
+#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(__LB_SHELL__)
+#define DEBUG_BREAK() LB::Platform::DEBUG_BREAK()
+#elif 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() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+  DEBUG_BREAK();
+#if (defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)) || \
+    (defined(__LB_ANDROID__) && !defined(__LB_SHELL__FOR_RELEASE__))
+  // 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/src/base/debug/debugger_shell.cc b/src/base/debug/debugger_shell.cc
new file mode 100644
index 0000000..855777b
--- /dev/null
+++ b/src/base/debug/debugger_shell.cc
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// We use the same code as posix version
+#if !defined(COBALT_WIN)
+#include "debugger_posix.cc"
+#endif
diff --git a/src/base/debug/debugger_starboard.cc b/src/base/debug/debugger_starboard.cc
new file mode 100644
index 0000000..ee9e762
--- /dev/null
+++ b/src/base/debug/debugger_starboard.cc
@@ -0,0 +1,41 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "base/debug/stack_trace.h"
+
+#include "base/logging.h"
+#include "starboard/system.h"
+
+namespace base {
+namespace debug {
+
+bool SpawnDebuggerOnProcess(unsigned process_id) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool BeingDebugged() {
+#if defined(__LB_SHELL__FOR_RELEASE__)
+  return false;
+#else
+  return SbSystemIsDebuggerAttached();
+#endif
+}
+
+void BreakDebugger() {
+  SbSystemBreakIntoDebugger();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/src/base/debug/debugger_win.cc b/src/base/debug/debugger_win.cc
new file mode 100644
index 0000000..b13dbfd
--- /dev/null
+++ b/src/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/src/base/debug/leak_annotations.h b/src/base/debug/leak_annotations.h
new file mode 100644
index 0000000..97be127
--- /dev/null
+++ b/src/base/debug/leak_annotations.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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)
+
+#elif defined(ADDRESS_SANITIZER)
+#include <sanitizer/lsan_interface.h>
+
+class ScopedLeakSanitizerDisabler {
+ public:
+  ScopedLeakSanitizerDisabler() { __lsan_disable(); }
+  ~ScopedLeakSanitizerDisabler() { __lsan_enable(); }
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedLeakSanitizerDisabler);
+};
+
+#define ANNOTATE_SCOPED_MEMORY_LEAK \
+    ScopedLeakSanitizerDisabler leak_sanitizer_disabler; static_cast<void>(0)
+
+#define ANNOTATE_LEAKING_OBJECT_PTR(X) __lsan_ignore_object(X);
+
+#else
+
+// 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/src/base/debug/leak_tracker.h b/src/base/debug/leak_tracker.h
new file mode 100644
index 0000000..93cea39
--- /dev/null
+++ b/src/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/src/base/debug/leak_tracker_unittest.cc b/src/base/debug/leak_tracker_unittest.cc
new file mode 100644
index 0000000..99df4c1
--- /dev/null
+++ b/src/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/src/base/debug/profiler.cc b/src/base/debug/profiler.cc
new file mode 100644
index 0000000..de79124
--- /dev/null
+++ b/src/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/src/base/debug/profiler.h b/src/base/debug/profiler.h
new file mode 100644
index 0000000..d703876
--- /dev/null
+++ b/src/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/src/base/debug/stack_trace.cc b/src/base/debug/stack_trace.cc
new file mode 100644
index 0000000..6fab183
--- /dev/null
+++ b/src/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/src/base/debug/stack_trace.h b/src/base/debug/stack_trace.h
new file mode 100644
index 0000000..be3395d
--- /dev/null
+++ b/src/base/debug/stack_trace.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_STACK_TRACE_H_
+#define BASE_DEBUG_STACK_TRACE_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+#endif
+
+#if defined(OS_WIN) || defined(COMPILER_MSVC)
+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) || defined(COMPILER_MSVC)
+  // 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 internal {
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+// POSIX doesn't define any async-signal safe function for converting
+// an integer to ASCII. We'll have to define our own version.
+// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
+// conversion was successful or NULL otherwise. It never writes more than "sz"
+// bytes. Output will be truncated as needed, and a NUL character is always
+// appended.
+BASE_EXPORT char *itoa_r(intptr_t i, char *buf, size_t sz, int base);
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+}  // namespace internal
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_STACK_TRACE_H_
diff --git a/src/base/debug/stack_trace_android.cc b/src/base/debug/stack_trace_android.cc
new file mode 100644
index 0000000..cc03d60
--- /dev/null
+++ b/src/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/src/base/debug/stack_trace_ios.mm b/src/base/debug/stack_trace_ios.mm
new file mode 100644
index 0000000..ab0abc4
--- /dev/null
+++ b/src/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/src/base/debug/stack_trace_posix.cc b/src/base/debug/stack_trace_posix.cc
new file mode 100644
index 0000000..fd0bb34
--- /dev/null
+++ b/src/base/debug/stack_trace_posix.cc
@@ -0,0 +1,425 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <ostream>
+
+#if defined(__GLIBCXX__)
+#include <cxxabi.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#endif
+
+#include "base/basictypes.h"
+#include "base/debug/debugger.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/string_number_conversions.h"
+
+#if defined(USE_SYMBOLIZE)
+#include "base/third_party/symbolize/symbolize.h"
+#endif
+
+namespace base {
+namespace debug {
+
+namespace {
+
+#if defined(__LB_SHELL__)
+typedef int sig_atomic_t;
+#endif
+
+volatile sig_atomic_t in_signal_handler = 0;
+
+// 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) {
+  // Note: code in this function is NOT async-signal safe (std::string uses
+  // malloc internally).
+
+#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)
+
+class BacktraceOutputHandler {
+ public:
+  virtual void HandleOutput(const char* output) = 0;
+
+ protected:
+  virtual ~BacktraceOutputHandler() {}
+};
+
+void OutputPointer(void* pointer, BacktraceOutputHandler* handler) {
+  char buf[1024] = { '\0' };
+  handler->HandleOutput(" [0x");
+  internal::itoa_r(reinterpret_cast<intptr_t>(pointer), buf, sizeof(buf), 16);
+  handler->HandleOutput(buf);
+  handler->HandleOutput("]");
+}
+
+void ProcessBacktrace(void *const *trace,
+                      int size,
+                      BacktraceOutputHandler* handler) {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+#if defined(USE_SYMBOLIZE)
+  for (int i = 0; i < size; ++i) {
+    handler->HandleOutput("\t");
+
+    char buf[1024] = { '\0' };
+
+    // Subtract by one as return address of function may be in the next
+    // function when a function is annotated as noreturn.
+    void* address = static_cast<char*>(trace[i]) - 1;
+    if (google::Symbolize(address, buf, sizeof(buf)))
+      handler->HandleOutput(buf);
+    else
+      handler->HandleOutput("<unknown>");
+
+    OutputPointer(trace[i], handler);
+    handler->HandleOutput("\n");
+  }
+#else
+  bool printed = false;
+
+  // Below part is async-signal unsafe (uses malloc), so execute it only
+  // when we are not executing the signal handler.
+  if (in_signal_handler == 0) {
+#if defined(__LB_PS3__)
+    std::string symbols;
+    bool success = ResolveSymbolsFromHostPS3(trace, size, &symbols);
+    if (success && symbols.length() > 0) {
+      handler->HandleOutput(symbols.c_str());
+      printed = true;
+    }
+#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);
+        handler->HandleOutput(trace_symbol.c_str());
+        handler->HandleOutput("\n");
+      }
+
+      printed = true;
+    }
+#endif
+  }
+
+  if (!printed) {
+    for (int i = 0; i < size; ++i) {
+      OutputPointer(trace[i], handler);
+      handler->HandleOutput("\n");
+    }
+  }
+#endif  // defined(USE_SYMBOLIZE)
+}
+
+#if !defined(__LB_SHELL__)
+void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) {
+  // NOTE: This code MUST be async-signal safe.
+  // NO malloc or stdio is allowed here.
+
+  // Record the fact that we are in the signal handler now, so that the rest
+  // of StackTrace can behave in an async-signal-safe manner.
+  in_signal_handler = 1;
+
+  if (BeingDebugged())
+    BreakDebugger();
+
+  char buf[1024] = "Received signal ";
+  size_t buf_len = strlen(buf);
+  internal::itoa_r(signal, buf + buf_len, sizeof(buf) - buf_len, 10);
+  RAW_LOG(ERROR, buf);
+
+  debug::StackTrace().PrintBacktrace();
+
+  // TODO(shess): Port to Linux.
+#if defined(OS_MACOSX)
+  // TODO(shess): Port to 64-bit.
+#if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS
+  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);
+}
+#endif
+
+class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
+ public:
+  PrintBacktraceOutputHandler() {}
+
+  virtual void HandleOutput(const char* output) {
+    // NOTE: This code MUST be async-signal safe (it's used by in-process
+    // stack dumping signal handler). NO malloc or stdio is allowed here.
+    ignore_result(HANDLE_EINTR(write(STDERR_FILENO, output, strlen(output))));
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrintBacktraceOutputHandler);
+};
+
+class StreamBacktraceOutputHandler : public BacktraceOutputHandler {
+ public:
+  StreamBacktraceOutputHandler(std::ostream* os) : os_(os) {
+  }
+
+  virtual void HandleOutput(const char* output) {
+    (*os_) << output;
+  }
+
+ private:
+  std::ostream* os_;
+
+  DISALLOW_COPY_AND_ASSIGN(StreamBacktraceOutputHandler);
+};
+
+void WarmUpBacktrace() {
+  // Warm up stack trace infrastructure. It turns out that on the first
+  // call glibc initializes some internal data structures using pthread_once,
+  // and even backtrace() can call malloc(), leading to hangs.
+  //
+  // Example stack trace snippet (with tcmalloc):
+  //
+  // #8  0x0000000000a173b5 in tc_malloc
+  //             at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161
+  // #9  0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517
+  // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262
+  // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
+  // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1")
+  //             at dl-open.c:639
+  // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89
+  // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
+  // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48
+  // #16 __GI___libc_dlopen_mode at dl-libc.c:165
+  // #17 0x00007ffff61ef8f5 in init
+  //             at ../sysdeps/x86_64/../ia64/backtrace.c:53
+  // #18 0x00007ffff6aad400 in pthread_once
+  //             at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104
+  // #19 0x00007ffff61efa14 in __GI___backtrace
+  //             at ../sysdeps/x86_64/../ia64/backtrace.c:104
+  // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace
+  //             at base/debug/stack_trace_posix.cc:175
+  // #21 0x00000000007a4ae5 in
+  //             base::(anonymous namespace)::StackDumpSignalHandler
+  //             at base/process_util_posix.cc:172
+  // #22 <signal handler called>
+  StackTrace stack_trace;
+}
+
+}  // namespace
+
+#if !defined(OS_IOS) && !defined(__LB_SHELL__)
+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);
+
+  // Avoid hangs during backtrace initialization, see above.
+  WarmUpBacktrace();
+
+  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() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+  // 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 {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+  PrintBacktraceOutputHandler handler;
+  ProcessBacktrace(trace_, count_, &handler);
+}
+
+void StackTrace::OutputToStream(std::ostream* os) const {
+  StreamBacktraceOutputHandler handler(os);
+  ProcessBacktrace(trace_, count_, &handler);
+}
+
+namespace internal {
+
+// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
+char *itoa_r(intptr_t i, char *buf, size_t sz, int base) {
+  // Make sure we can write at least one NUL byte.
+  size_t n = 1;
+  if (n > sz)
+    return NULL;
+
+  if (base < 2 || base > 16) {
+    buf[0] = '\000';
+    return NULL;
+  }
+
+  char *start = buf;
+
+  uintptr_t j = i;
+
+  // Handle negative numbers (only for base 10).
+  if (i < 0 && base == 10) {
+    j = -i;
+
+    // Make sure we can write the '-' character.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+    *start++ = '-';
+  }
+
+  // Loop until we have converted the entire number. Output at least one
+  // character (i.e. '0').
+  char *ptr = start;
+  do {
+    // Make sure there is still enough space left in our output buffer.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+
+    // Output the next digit.
+    *ptr++ = "0123456789abcdef"[j % base];
+    j /= base;
+  } while (j);
+
+  // Terminate the output with a NUL character.
+  *ptr = '\000';
+
+  // Conversion to ASCII actually resulted in the digits being in reverse
+  // order. We can't easily generate them in forward order, as we can't tell
+  // the number of characters needed until we are done converting.
+  // So, now, we reverse the string (except for the possible "-" sign).
+  while (--ptr > start) {
+    char ch = *ptr;
+    *ptr = *start;
+    *start++ = ch;
+  }
+  return buf;
+}
+
+}  // namespace internal
+
+}  // namespace debug
+}  // namespace base
diff --git a/src/base/debug/stack_trace_shell.cc b/src/base/debug/stack_trace_shell.cc
new file mode 100644
index 0000000..8c42ae6
--- /dev/null
+++ b/src/base/debug/stack_trace_shell.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.
+
+#if defined(__LB_XB1__) && !defined(__LB_SHELL__FOR_RELEASE__)
+
+// Stack tracing is using DbgHelp which doesn't support the TV_APP partition
+// at the moment. To make it work, we have to trick the headers into thinking
+// that they are compiled for a desktop application. This is the reason
+// why the functionality will only be enabled in internal builds.
+
+#if !defined(COBALT_WIN)
+#pragma push_macro("WINAPI_PARTITION_DESKTOP")
+#undef WINAPI_PARTITION_DESKTOP
+#define WINAPI_PARTITION_DESKTOP 1
+#endif
+
+#include "stack_trace_win.cc"
+
+#if !defined(COBALT_WIN)
+#pragma pop_macro("WINAPI_PARTITION_DESKTOP")
+#endif
+
+// EnableInProcessStackDumping is implemented in stack_trace_xb1.cc
+
+#elif !defined(__LB_ANDROID__)
+// stack_trace_android.cc is already compiled via base.gypi
+
+#if defined(__LB_PS3__)
+#include "stack_trace_ps3.cc"
+#endif
+#include "stack_trace_posix.cc"
+
+namespace base {
+namespace debug {
+
+// But re-implement this:
+bool EnableInProcessStackDumping() {
+  // We need this to return true to run unit tests
+  return true;
+}
+
+} // namespace debug
+} // namespace base
+
+#endif
diff --git a/src/base/debug/stack_trace_starboard.cc b/src/base/debug/stack_trace_starboard.cc
new file mode 100644
index 0000000..163105c
--- /dev/null
+++ b/src/base/debug/stack_trace_starboard.cc
@@ -0,0 +1,185 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "base/debug/stack_trace.h"
+
+#include <ostream>
+
+#include "base/basictypes.h"
+#include "starboard/log.h"
+#include "starboard/system.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+class BacktraceOutputHandler {
+ public:
+  virtual void HandleOutput(const char* output) = 0;
+
+ protected:
+  virtual ~BacktraceOutputHandler() {}
+};
+
+class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
+ public:
+  PrintBacktraceOutputHandler() {}
+
+  virtual void HandleOutput(const char* output) {
+    // NOTE: This code MUST be async-signal safe (it's used by in-process
+    // stack dumping signal handler). NO malloc or stdio is allowed here.
+    SbLogRaw(output);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrintBacktraceOutputHandler);
+};
+
+class StreamBacktraceOutputHandler : public BacktraceOutputHandler {
+ public:
+  StreamBacktraceOutputHandler(std::ostream* os) : os_(os) {}
+
+  virtual void HandleOutput(const char* output) { (*os_) << output; }
+
+ private:
+  std::ostream* os_;
+
+  DISALLOW_COPY_AND_ASSIGN(StreamBacktraceOutputHandler);
+};
+
+// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
+char* itoa_r(intptr_t i, char* buf, size_t sz, int base) {
+  // Make sure we can write at least one NUL byte.
+  size_t n = 1;
+  if (n > sz)
+    return NULL;
+
+  if (base < 2 || base > 16) {
+    buf[0] = '\000';
+    return NULL;
+  }
+
+  char* start = buf;
+
+  uintptr_t j = i;
+
+  // Handle negative numbers (only for base 10).
+  if (i < 0 && base == 10) {
+    j = -i;
+
+    // Make sure we can write the '-' character.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+    *start++ = '-';
+  }
+
+  // Loop until we have converted the entire number. Output at least one
+  // character (i.e. '0').
+  char* ptr = start;
+  do {
+    // Make sure there is still enough space left in our output buffer.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+
+    // Output the next digit.
+    *ptr++ = "0123456789abcdef"[j % base];
+    j /= base;
+  } while (j);
+
+  // Terminate the output with a NUL character.
+  *ptr = '\000';
+
+  // Conversion to ASCII actually resulted in the digits being in reverse
+  // order. We can't easily generate them in forward order, as we can't tell
+  // the number of characters needed until we are done converting.
+  // So, now, we reverse the string (except for the possible "-" sign).
+  while (--ptr > start) {
+    char ch = *ptr;
+    *ptr = *start;
+    *start++ = ch;
+  }
+  return buf;
+}
+
+void OutputPointer(void* pointer, BacktraceOutputHandler* handler) {
+  char buf[1024] = {'\0'};
+  handler->HandleOutput(" [0x");
+  itoa_r(reinterpret_cast<intptr_t>(pointer), buf, sizeof(buf), 16);
+  handler->HandleOutput(buf);
+  handler->HandleOutput("]");
+}
+
+void ProcessBacktrace(void* const* trace,
+                      int size,
+                      BacktraceOutputHandler* handler) {
+  for (int i = 0; i < size; ++i) {
+    handler->HandleOutput("\t");
+
+    char buf[1024] = {'\0'};
+
+    // Subtract by one as return address of function may be in the next
+    // function when a function is annotated as noreturn.
+    void* address = static_cast<char*>(trace[i]) - 1;
+    if (SbSystemSymbolize(address, buf, sizeof(buf))) {
+      handler->HandleOutput(buf);
+    } else {
+      handler->HandleOutput("<unknown>");
+    }
+
+    OutputPointer(trace[i], handler);
+    handler->HandleOutput("\n");
+  }
+}
+
+}  // namespace
+
+StackTrace::StackTrace() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+  // Though the SbSystemGetStack API documentation does not specify any possible
+  // negative return values, we take no chance.
+  count_ = std::max(SbSystemGetStack(trace_, arraysize(trace_)), 0);
+  if (count_ < 1) {
+    return;
+  }
+
+  // We can remove this call from the stack trace, since we know it is always
+  // going to be in it.
+  for (int i = 1; i < count_; ++i) {
+    trace_[i - 1] = trace_[i];
+  }
+}
+
+void StackTrace::PrintBacktrace() const {
+  PrintBacktraceOutputHandler handler;
+  ProcessBacktrace(trace_, count_, &handler);
+}
+
+void StackTrace::OutputToStream(std::ostream* out_stream) const {
+  StreamBacktraceOutputHandler handler(out_stream);
+  ProcessBacktrace(trace_, count_, &handler);
+}
+
+bool EnableInProcessStackDumping() {
+  return true;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/src/base/debug/stack_trace_unittest.cc b/src/base/debug/stack_trace_unittest.cc
new file mode 100644
index 0000000..21205ca
--- /dev/null
+++ b/src/base/debug/stack_trace_unittest.cc
@@ -0,0 +1,211 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+#include <sstream>
+#include <string>
+
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "base/process_util.h"
+#include "base/test/test_timeouts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(__LB_SHELL__)
+#include "base/test/multiprocess_test.h"
+#endif
+
+namespace base {
+namespace debug {
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(__LB_SHELL__)
+typedef MultiProcessTest StackTraceTest;
+#else
+typedef testing::Test StackTraceTest;
+#endif
+
+// Note: On Linux, this test currently only fully works on Debug builds.
+// See comments in the #ifdef soup if you intend to change this.
+#if defined(OS_WIN)
+// Always fails on Windows: crbug.com/32070
+#define MAYBE_OutputToStream DISABLED_OutputToStream
+#else
+#define MAYBE_OutputToStream OutputToStream
+#endif
+TEST_F(StackTraceTest, MAYBE_OutputToStream) {
+  StackTrace trace;
+
+  // Dump the trace into a string.
+  std::ostringstream os;
+  trace.OutputToStream(&os);
+  std::string backtrace_message = os.str();
+
+  // ToString() should produce the same output.
+  EXPECT_EQ(backtrace_message, trace.ToString());
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG
+  // Stack traces require an extra data table that bloats our binaries,
+  // so they're turned off for release builds.  We stop the test here,
+  // at least letting us verify that the calls don't crash.
+  return;
+#endif  // defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG
+
+  size_t frames_found = 0;
+  trace.Addresses(&frames_found);
+  ASSERT_GE(frames_found, 5u) <<
+      "No stack frames found.  Skipping rest of test.";
+
+  // Check if the output has symbol initialization warning.  If it does, fail.
+  ASSERT_EQ(backtrace_message.find("Dumping unresolved backtrace"),
+            std::string::npos) <<
+      "Unable to resolve symbols.  Skipping rest of test.";
+
+#if defined(OS_MACOSX)
+#if 0
+  // Disabled due to -fvisibility=hidden in build config.
+
+  // Symbol resolution via the backtrace_symbol function does not work well
+  // in OS X.
+  // See this thread:
+  //
+  //    http://lists.apple.com/archives/darwin-dev/2009/Mar/msg00111.html
+  //
+  // Just check instead that we find our way back to the "start" symbol
+  // which should be the first symbol in the trace.
+  //
+  // TODO(port): Find a more reliable way to resolve symbols.
+
+  // Expect to at least find main.
+  EXPECT_TRUE(backtrace_message.find("start") != std::string::npos)
+      << "Expected to find start in backtrace:\n"
+      << backtrace_message;
+
+#endif
+#elif defined(USE_SYMBOLIZE)
+  // This branch is for gcc-compiled code, but not Mac due to the
+  // above #if.
+  // Expect a demangled symbol.
+  EXPECT_TRUE(backtrace_message.find("testing::Test::Run()") !=
+              std::string::npos)
+      << "Expected a demangled symbol in backtrace:\n"
+      << backtrace_message;
+
+#elif 0
+  // This is the fall-through case; it used to cover Windows.
+  // But it's disabled because of varying buildbot configs;
+  // some lack symbols.
+
+  // Expect to at least find main.
+  EXPECT_TRUE(backtrace_message.find("main") != std::string::npos)
+      << "Expected to find main in backtrace:\n"
+      << backtrace_message;
+
+#if defined(OS_WIN)
+// MSVC doesn't allow the use of C99's __func__ within C++, so we fake it with
+// MSVC's __FUNCTION__ macro.
+#define __func__ __FUNCTION__
+#endif
+
+  // Expect to find this function as well.
+  // Note: This will fail if not linked with -rdynamic (aka -export_dynamic)
+  EXPECT_TRUE(backtrace_message.find(__func__) != std::string::npos)
+      << "Expected to find " << __func__ << " in backtrace:\n"
+      << backtrace_message;
+
+#endif  // define(OS_MACOSX)
+}
+
+// The test is used for manual testing, e.g., to see the raw output.
+TEST_F(StackTraceTest, DebugOutputToStream) {
+  StackTrace trace;
+  std::ostringstream os;
+  trace.OutputToStream(&os);
+  VLOG(1) << os.str();
+}
+
+// The test is used for manual testing, e.g., to see the raw output.
+TEST_F(StackTraceTest, DebugPrintBacktrace) {
+  StackTrace().PrintBacktrace();
+}
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(__LB_ANDROID__)
+#if !defined(OS_IOS) && !defined(__LB_SHELL__)
+MULTIPROCESS_TEST_MAIN(MismatchedMallocChildProcess) {
+  char* pointer = new char[10];
+  delete pointer;
+  return 2;
+}
+
+// Regression test for StackDumpingSignalHandler async-signal unsafety.
+// Combined with tcmalloc's debugallocation, that signal handler
+// and e.g. mismatched new[]/delete would cause a hang because
+// of re-entering malloc.
+TEST_F(StackTraceTest, AsyncSignalUnsafeSignalHandlerHang) {
+  ProcessHandle child = this->SpawnChild("MismatchedMallocChildProcess", false);
+  ASSERT_NE(kNullProcessHandle, child);
+  ASSERT_TRUE(WaitForSingleProcess(child, TestTimeouts::action_timeout()));
+}
+#endif  // !defined(OS_IOS) &&!defined(__LB_SHELL__)
+
+namespace {
+
+std::string itoa_r_wrapper(intptr_t i, size_t sz, int base) {
+  char buffer[1024];
+  CHECK_LE(sz, sizeof(buffer));
+
+  char* result = internal::itoa_r(i, buffer, sz, base);
+  EXPECT_TRUE(result);
+  return std::string(buffer);
+}
+
+}  // namespace
+
+TEST_F(StackTraceTest, itoa_r) {
+  EXPECT_EQ("0", itoa_r_wrapper(0, 128, 10));
+  EXPECT_EQ("-1", itoa_r_wrapper(-1, 128, 10));
+
+  // Test edge cases.
+  if (sizeof(intptr_t) == 4) {
+    EXPECT_EQ("ffffffff", itoa_r_wrapper(-1, 128, 16));
+    EXPECT_EQ("-2147483648",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10));
+    EXPECT_EQ("2147483647",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10));
+
+    EXPECT_EQ("80000000",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16));
+    EXPECT_EQ("7fffffff",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16));
+  } else if (sizeof(intptr_t) == 8) {
+    EXPECT_EQ("ffffffffffffffff", itoa_r_wrapper(-1, 128, 16));
+    EXPECT_EQ("-9223372036854775808",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10));
+    EXPECT_EQ("9223372036854775807",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10));
+
+    EXPECT_EQ("8000000000000000",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16));
+    EXPECT_EQ("7fffffffffffffff",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16));
+  } else {
+    ADD_FAILURE() << "Missing test case for your size of intptr_t ("
+                  << sizeof(intptr_t) << ")";
+  }
+
+  // Test hex output.
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16));
+  EXPECT_EQ("deadbeef", itoa_r_wrapper(0xdeadbeef, 128, 16));
+
+  // Check that itoa_r respects passed buffer size limit.
+  char buffer[1024];
+  EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 10, 16));
+  EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 9, 16));
+  EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 8, 16));
+  EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 7, 16));
+}
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+}  // namespace debug
+}  // namespace base
diff --git a/src/base/debug/stack_trace_win.cc b/src/base/debug/stack_trace_win.cc
new file mode 100644
index 0000000..d26b492
--- /dev/null
+++ b/src/base/debug/stack_trace_win.cc
@@ -0,0 +1,245 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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 {
+
+#if !defined(COBALT_WIN)
+// 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;
+}
+#endif  // !defined(COBALT_WIN)
+
+// 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
+
+#if !defined(COBALT_WIN)
+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;
+}
+#endif
+
+// 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) {
+  // StackWalk64 requires symbol information to be loaded. The following
+  // will make sure that SymbolContext singleton is initialized which will
+  // load the required symbols.
+  static volatile SymbolContext* context = SymbolContext::GetInstance();
+  (void)context;
+
+  // 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/src/base/debug/trace_event.cc b/src/base/debug/trace_event.cc
new file mode 100644
index 0000000..682e065
--- /dev/null
+++ b/src/base/debug/trace_event.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/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 (*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,
+        TRACE_EVENT_FLAG_NONE);
+  }
+}
+
+}  // namespace trace_event_internal
diff --git a/src/base/debug/trace_event.h b/src/base/debug/trace_event.h
new file mode 100644
index 0000000..67a79a6
--- /dev/null
+++ b/src/base/debug/trace_event.h
@@ -0,0 +1,960 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// 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"
+
+#if defined(TRACING_DISABLED)
+
+inline void NullAddTraceEvent(
+        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) {
+    UNREFERENCED_PARAMETER(phase);
+    UNREFERENCED_PARAMETER(category_enabled);
+    UNREFERENCED_PARAMETER(name);
+    UNREFERENCED_PARAMETER(id);
+    UNREFERENCED_PARAMETER(num_args);
+    UNREFERENCED_PARAMETER(arg_names);
+    UNREFERENCED_PARAMETER(arg_types);
+    UNREFERENCED_PARAMETER(arg_values);
+    UNREFERENCED_PARAMETER(flags);
+}
+
+#define TRACE_EVENT_API_ADD_TRACE_EVENT NullAddTraceEvent
+
+#define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \
+    (void)0
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \
+    (void)0
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category, name, id, flags, \
+                                         ...) \
+    (void)0
+
+#endif // #if defined(TRACING_DISABLED)
+
+// 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)
+
+// 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
+
+#if !defined(TRACING_DISABLED)
+// Add a trace event to the platform tracing system.
+// void 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,
+//                    unsigned char flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT \
+    base::debug::TraceLog::GetInstance()->AddTraceEvent
+#endif  // !defined(TRACING_DISABLED)
+
+////////////////////////////////////////////////////////////////////////////////
+
+// 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))); \
+    }
+
+#if !defined(TRACING_DISABLED)
+// 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_UID(catstatic)) { \
+        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_UID(catstatic)) { \
+      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
+// 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_UID(catstatic)) { \
+        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)
+#endif  // #if !defined(TRACING_DISABLED)
+
+// 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 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_(reinterpret_cast<unsigned long 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 void AddTraceEvent(char phase,
+                                const unsigned char* category_enabled,
+                                const char* name,
+                                unsigned long long id,
+                                unsigned char flags) {
+  TRACE_EVENT_API_ADD_TRACE_EVENT(
+      phase, category_enabled, name, id,
+      kZeroNumArgs, NULL, NULL, NULL,
+      flags);
+}
+
+template<class ARG1_TYPE>
+static inline void 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];
+  trace_event_internal::SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+  TRACE_EVENT_API_ADD_TRACE_EVENT(
+      phase, category_enabled, name, id,
+      num_args, &arg1_name, arg_types, arg_values,
+      flags);
+}
+
+template<class ARG1_TYPE, class ARG2_TYPE>
+static inline void 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];
+  trace_event_internal::SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+  trace_event_internal::SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
+  TRACE_EVENT_API_ADD_TRACE_EVENT(
+      phase, category_enabled, name, id,
+      num_args, arg_names, arg_types, arg_values,
+      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_;
+};
+
+
+}  // namespace trace_event_internal
+
+#endif  // BASE_DEBUG_TRACE_EVENT_H_
diff --git a/src/base/debug/trace_event_android.cc b/src/base/debug/trace_event_android.cc
new file mode 100644
index 0000000..c56c3c1
--- /dev/null
+++ b/src/base/debug/trace_event_android.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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;
+}
+
+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 (g_atrace_fd == -1)
+    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);
+}
+
+// Must be called with lock_ locked.
+void TraceLog::ApplyATraceEnabledFlag(unsigned char* category_enabled) {
+  if (g_atrace_fd != -1)
+    *category_enabled |= ATRACE_ENABLED;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/src/base/debug/trace_event_impl.cc b/src/base/debug/trace_event_impl.cc
new file mode 100644
index 0000000..5af61e5
--- /dev/null
+++ b/src/base/debug/trace_event_impl.cc
@@ -0,0 +1,830 @@
+// Copyright (c) 2012 The Chromium Authors. All 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
+
+#if defined(OS_STARBOARD)
+#include "starboard/types.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 matched_value,
+                                   unsigned char unmatched_value) {
+  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 ?
+      matched_value : unmatched_value;
+}
+
+// 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 |matched_value|. Otherwise its enabled status is set to |unmatched_value|.
+static void EnableMatchingCategories(const std::vector<std::string>& patterns,
+                                     unsigned char matched_value,
+                                     unsigned char unmatched_value) {
+  for (int i = 0; i < g_category_index; i++)
+    EnableMatchingCategory(i, patterns, matched_value, unmatched_value);
+}
+
+const unsigned char* TraceLog::GetCategoryEnabledInternal(const char* name) {
+  AutoLock lock(lock_);
+  DCHECK(!strchr(name, '"')) << "Category names may not contain double quote";
+
+  unsigned char* category_enabled = NULL;
+  // Search for pre-existing category matching this name
+  for (int i = 0; i < g_category_index; i++) {
+    if (strcmp(g_categories[i], name) == 0) {
+      category_enabled = &g_category_enabled[i];
+      break;
+    }
+  }
+
+  if (!category_enabled) {
+    // 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_,
+                                 CATEGORY_ENABLED, 0);
+        } else {
+          EnableMatchingCategory(new_index, excluded_categories_,
+                                 0, CATEGORY_ENABLED);
+        }
+      } else {
+        g_category_enabled[new_index] = 0;
+      }
+      category_enabled = &g_category_enabled[new_index];
+    } else {
+      category_enabled = &g_category_enabled[g_category_categories_exhausted];
+    }
+  }
+#if defined(OS_ANDROID)
+  ApplyATraceEnabledFlag(category_enabled);
+#endif
+  return category_enabled;
+}
+
+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) {
+#if defined(TRACING_DISABLED)
+  return;
+#else  // defined(TRACING_DISABLED)
+  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(256 * 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_, CATEGORY_ENABLED, 0);
+  else
+    EnableMatchingCategories(excluded_categories_, 0, CATEGORY_ENABLED);
+#endif  // defined(TRACING_DISABLED)
+}
+
+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);
+  }
+}
+
+void TraceLog::FlushWithRawEvents(
+    const TraceLog::RawEventOutputCallback& raw_event_callback,
+    const TraceLog::OutputCallback& json_output_callback) {
+  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) {
+    if (!raw_event_callback.is_null()) {
+      for (size_t j = i; j < i + kTraceEventBatchSize; ++j) {
+        if (j >= previous_logged_events.size()) {
+          break;
+        }
+        raw_event_callback.Run(previous_logged_events[j]);
+      }
+    }
+
+    if (!json_output_callback.is_null()) {
+      scoped_refptr<RefCountedString> json_events_str_ptr =
+          new RefCountedString();
+      TraceEvent::AppendEventsAsJSON(previous_logged_events,
+                                     i,
+                                     kTraceEventBatchSize,
+                                     &(json_events_str_ptr->data()));
+      json_output_callback.Run(json_events_str_ptr);
+    }
+  }
+}
+
+void 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,
+                            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() - time_offset_;
+  NotificationHelper notifier(this);
+  {
+    AutoLock lock(lock_);
+    if (*category_enabled != CATEGORY_ENABLED)
+      return;
+    if (logged_events_.size() >= kTraceEventBufferSize)
+      return;
+
+    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 (flags & TRACE_EVENT_FLAG_MANGLE_ID)
+      id ^= process_id_hash_;
+
+    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();
+}
+
+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;
+}
+
+void TraceLog::SetTimeOffset(TimeDelta offset) {
+  time_offset_ = offset;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/src/base/debug/trace_event_impl.h b/src/base/debug/trace_event_impl.h
new file mode 100644
index 0000000..b8b4110
--- /dev/null
+++ b/src/base/debug/trace_event_impl.h
@@ -0,0 +1,412 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_; }
+
+#if defined(COBALT)
+  unsigned long long id() const { return id_; }
+  const TraceValue* arg_values() const { return arg_values_; }
+  int thread_id() const { return thread_id_; }
+  char phase() const { return phase_; }
+#endif
+
+ 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) || defined(__LB_ANDROID__)
+  static void InitATrace();
+#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);
+
+#if defined(COBALT)
+  // Flush out events as raw TraceEvent structures.  Optinally also flush out
+  // JSON output as well.
+  typedef base::Callback<void(const TraceEvent&)> RawEventOutputCallback;
+  void FlushWithRawEvents(const RawEventOutputCallback& raw_event_callback,
+                          const OutputCallback& json_output_callback);
+#endif
+
+  // 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.
+  // 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.
+  void 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,
+                    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);
+
+  // Allow setting an offset between the current TimeTicks time and the time
+  // that should be reported.
+  void SetTimeOffset(TimeDelta offset);
+
+ private:
+  // This allows constructor and destructor to be private and usable only
+  // by the Singleton class.
+  friend struct StaticMemorySingletonTraits<TraceLog>;
+
+  // The pointer returned from GetCategoryEnabledInternal() points to a value
+  // with zero or more of the following bits. Used in this class only.
+  // The TRACE_EVENT macros should only use the value as a bool.
+  enum CategoryEnabledFlags {
+    // Normal enabled flag for categories enabled with Enable().
+    CATEGORY_ENABLED = 1 << 0,
+    // On Android if ATrace is enabled, all categories will have this bit.
+    // Not used on other platforms.
+    ATRACE_ENABLED = 1 << 1
+  };
+
+  // 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) || defined(__LB_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();
+  static void ApplyATraceEnabledFlag(unsigned char* category_enabled);
+#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_;
+
+  TimeDelta time_offset_;
+
+  // 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/src/base/debug/trace_event_unittest.cc b/src/base/debug/trace_event_unittest.cc
new file mode 100644
index 0000000..445118b
--- /dev/null
+++ b/src/base/debug/trace_event_unittest.cc
@@ -0,0 +1,1341 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_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_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"));
+}
+
+
+// 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/src/base/debug/trace_event_unittest.h b/src/base/debug/trace_event_unittest.h
new file mode 100644
index 0000000..3b570e1
--- /dev/null
+++ b/src/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/src/base/debug/trace_event_win.cc b/src/base/debug/trace_event_win.cc
new file mode 100644
index 0000000..d5a21f4
--- /dev/null
+++ b/src/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/src/base/debug/trace_event_win.h b/src/base/debug/trace_event_win.h
new file mode 100644
index 0000000..2a900bb
--- /dev/null
+++ b/src/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/src/base/debug/trace_event_win_unittest.cc b/src/base/debug/trace_event_win_unittest.cc
new file mode 100644
index 0000000..786b9d5
--- /dev/null
+++ b/src/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/src/base/debug_message.cc b/src/base/debug_message.cc
new file mode 100644
index 0000000..10f441d
--- /dev/null
+++ b/src/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/src/base/environment.cc b/src/base/environment.cc
new file mode 100644
index 0000000..8c61591
--- /dev/null
+++ b/src/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/src/base/environment.h b/src/base/environment.h
new file mode 100644
index 0000000..5160ff2
--- /dev/null
+++ b/src/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/src/base/environment_unittest.cc b/src/base/environment_unittest.cc
new file mode 100644
index 0000000..b6654c9
--- /dev/null
+++ b/src/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/src/base/event_recorder.h b/src/base/event_recorder.h
new file mode 100644
index 0000000..32e1124
--- /dev/null
+++ b/src/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/src/base/event_recorder_stubs.cc b/src/base/event_recorder_stubs.cc
new file mode 100644
index 0000000..91f2e07
--- /dev/null
+++ b/src/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/src/base/event_recorder_win.cc b/src/base/event_recorder_win.cc
new file mode 100644
index 0000000..11bf0f0
--- /dev/null
+++ b/src/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/src/base/event_types.h b/src/base/event_types.h
new file mode 100644
index 0000000..af586e4
--- /dev/null
+++ b/src/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/src/base/file_descriptor_posix.h b/src/base/file_descriptor_posix.h
new file mode 100644
index 0000000..abc0789
--- /dev/null
+++ b/src/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/src/base/file_path.cc b/src/base/file_path.cc
new file mode 100644
index 0000000..acada54
--- /dev/null
+++ b/src/base/file_path.cc
@@ -0,0 +1,1264 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 {
+
+#if defined(FILE_PATH_USES_WIN_SEPARATORS) && defined(OS_POSIX)
+inline bool StartsWith(const std::string& str,
+                       const std::string& search,
+                       bool case_sensitive) {
+  return StartsWithASCII(str, search, case_sensitive);
+}
+#endif
+
+const char* kCommonDoubleExtensionSuffixes[] = { "gz", "z", "bz2" };
+const char* kCommonDoubleExtensions[] = { "user.js" };
+
+const FilePath::CharType kStringTerminator = FILE_PATH_LITERAL('\0');
+
+// If this FilePath contains a drive letter specification, returns the
+// position of the last character of the drive letter specification,
+// otherwise returns npos.  This can only be true on Windows, when a pathname
+// begins with a letter followed by a colon.  On other platforms, this always
+// returns npos.
+StringType::size_type FindDriveLetter(const StringType& path) {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  // This is dependent on an ASCII-based character set, but that's a
+  // reasonable assumption.  iswalpha can be too inclusive here.
+  if (path.length() >= 2 && path[1] == L':' &&
+      ((path[0] >= L'A' && path[0] <= L'Z') ||
+       (path[0] >= L'a' && path[0] <= L'z'))) {
+    return 1;
+  }
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+  return StringType::npos;
+}
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+bool EqualDriveLetterCaseInsensitive(const StringType& a,
+                                     const StringType& b) {
+  size_t a_letter_pos = FindDriveLetter(a);
+  size_t b_letter_pos = FindDriveLetter(b);
+
+  if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos)
+    return a == b;
+
+  StringType a_letter(a.substr(0, a_letter_pos + 1));
+  StringType b_letter(b.substr(0, b_letter_pos + 1));
+  if (!StartsWith(a_letter, b_letter, false))
+    return false;
+
+  StringType a_rest(a.substr(a_letter_pos + 1));
+  StringType b_rest(b.substr(b_letter_pos + 1));
+  return a_rest == b_rest;
+}
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+
+bool IsPathAbsolute(const StringType& path) {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  StringType::size_type letter = FindDriveLetter(path);
+  if (letter != StringType::npos) {
+    // Look for a separator right after the drive specification.
+    return path.length() > letter + 1 &&
+        FilePath::IsSeparator(path[letter + 1]);
+  }
+  // Look for a pair of leading separators.
+  return path.length() > 1 &&
+      FilePath::IsSeparator(path[0]) && FilePath::IsSeparator(path[1]);
+#else  // FILE_PATH_USES_DRIVE_LETTERS
+  // Look for a separator in the first position.
+  return path.length() > 0 && FilePath::IsSeparator(path[0]);
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+}
+
+bool AreAllSeparators(const StringType& input) {
+  for (StringType::const_iterator it = input.begin();
+      it != input.end(); ++it) {
+    if (!FilePath::IsSeparator(*it))
+      return false;
+  }
+
+  return true;
+}
+
+// Find the position of the '.' that separates the extension from the rest
+// of the file name. The position is relative to BaseName(), not value().
+// 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) {
+  StringType::size_type nul_pos = path_.find(kStringTerminator);
+  if (nul_pos != StringType::npos)
+    path_.erase(nul_pos, StringType::npos);
+}
+
+FilePath::~FilePath() {
+}
+
+FilePath& FilePath::operator=(const FilePath& that) {
+  path_ = that.path_;
+  return *this;
+}
+
+bool FilePath::operator==(const FilePath& that) const {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return EqualDriveLetterCaseInsensitive(this->path_, that.path_);
+#else  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return path_ == that.path_;
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+}
+
+bool FilePath::operator!=(const FilePath& that) const {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return !EqualDriveLetterCaseInsensitive(this->path_, that.path_);
+#else  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return path_ != that.path_;
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+}
+
+// static
+bool FilePath::IsSeparator(CharType character) {
+  for (size_t i = 0; i < 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) || defined(OS_STARBOARD)
+  return InsertBeforeExtension(suffix.as_string());
+#endif
+}
+
+FilePath FilePath::AddExtension(const StringType& extension) const {
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  // If the new extension is "" or ".", then just return the current FilePath.
+  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+    return *this;
+
+  StringType str = path_;
+  if (extension[0] != kExtensionSeparator &&
+      *(str.end() - 1) != kExtensionSeparator) {
+    str.append(1, kExtensionSeparator);
+  }
+  str.append(extension);
+  return FilePath(str);
+}
+
+FilePath FilePath::ReplaceExtension(const StringType& extension) const {
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  FilePath no_ext = RemoveExtension();
+  // If the new extension is "" or ".", then just remove the current extension.
+  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+    return no_ext;
+
+  StringType str = no_ext.value();
+  if (extension[0] != kExtensionSeparator)
+    str.append(1, kExtensionSeparator);
+  str.append(extension);
+  return FilePath(str);
+}
+
+bool FilePath::MatchesExtension(const StringType& extension) const {
+  DCHECK(extension.empty() || extension[0] == kExtensionSeparator);
+
+  StringType current_extension = Extension();
+
+  if (current_extension.length() != extension.length())
+    return false;
+
+  return FilePath::CompareEqualIgnoreCase(extension, current_extension);
+}
+
+FilePath FilePath::Append(const StringType& component) const {
+  const StringType* appended = &component;
+  StringType without_nuls;
+
+  StringType::size_type nul_pos = component.find(kStringTerminator);
+  if (nul_pos != StringType::npos) {
+    without_nuls = component.substr(0, nul_pos);
+    appended = &without_nuls;
+  }
+
+  DCHECK(!IsPathAbsolute(*appended));
+
+  if (path_.compare(kCurrentDirectory) == 0) {
+    // Append normally doesn't do any normalization, but as a special case,
+    // when appending to kCurrentDirectory, just return a new path for the
+    // component argument.  Appending component to kCurrentDirectory would
+    // serve no purpose other than needlessly lengthening the path, and
+    // it's likely in practice to wind up with FilePath objects containing
+    // only kCurrentDirectory when calling DirName on a single relative path
+    // component.
+    return FilePath(*appended);
+  }
+
+  FilePath new_path(path_);
+  new_path.StripTrailingSeparatorsInternal();
+
+  // Don't append a separator if the path is empty (indicating the current
+  // directory) or if the path component is empty (indicating nothing to
+  // append).
+  if (appended->length() > 0 && new_path.path_.length() > 0) {
+    // Don't append a separator if the path still ends with a trailing
+    // separator after stripping (indicating the root directory).
+    if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) {
+      // Don't append a separator if the path is just a drive letter.
+      if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) {
+        new_path.path_.append(1, kSeparators[0]);
+      }
+    }
+  }
+
+  new_path.path_.append(*appended);
+  return new_path;
+}
+
+FilePath FilePath::Append(const FilePath& component) const {
+  return Append(component.value());
+}
+
+FilePath FilePath::AppendASCII(const base::StringPiece& component) const {
+  DCHECK(IsStringASCII(component));
+#if defined(OS_WIN)
+  return Append(ASCIIToUTF16(component.as_string()));
+#elif defined(OS_POSIX) || defined(OS_STARBOARD)
+  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) || defined(OS_STARBOARD)
+// 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) const {
+#if defined(OS_WIN)
+  pickle->WriteString16(path_);
+#else
+  pickle->WriteString(path_);
+#endif
+}
+
+bool FilePath::ReadFromPickle(PickleIterator* iter) {
+#if defined(OS_WIN)
+  if (!iter->ReadString16(&path_))
+    return false;
+#else
+  if (!iter->ReadString(&path_))
+    return false;
+#endif
+
+  if (path_.find(kStringTerminator) != StringType::npos)
+    return false;
+
+  return true;
+}
+
+#if defined(OS_WIN)
+// Windows specific implementation of file string comparisons
+
+int FilePath::CompareIgnoreCase(const StringType& string1,
+                                const StringType& string2) {
+  // Perform character-wise upper case comparison rather than using the
+  // fully Unicode-aware CompareString(). For details see:
+  // http://blogs.msdn.com/michkap/archive/2005/10/17/481600.aspx
+  StringType::const_iterator i1 = string1.begin();
+  StringType::const_iterator i2 = string2.begin();
+  StringType::const_iterator string1end = string1.end();
+  StringType::const_iterator string2end = string2.end();
+  for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) {
+    wchar_t c1 = (wchar_t)LOWORD(::CharUpperW((LPWSTR)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/src/base/file_path.h b/src/base/file_path.h
new file mode 100644
index 0000000..d1eb74c
--- /dev/null
+++ b/src/base/file_path.h
@@ -0,0 +1,437 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// 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.
+//
+// Paths can't contain NULs as a precaution agaist premature truncation.
+//
+// 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) || defined(__LB_XB1__) || defined(__LB_XB360__)
+#define FILE_PATH_USES_DRIVE_LETTERS
+#define FILE_PATH_USES_WIN_SEPARATORS
+#endif  // OS_WIN || __LB_XB1__ || __LB_XB360__
+
+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) || defined(OS_STARBOARD)
+  // 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) const;
+  bool ReadFromPickle(PickleIterator* iter);
+
+  // Normalize all path separators to backslash on Windows
+  // (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
+  FilePath NormalizePathSeparators() const;
+
+  // 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) || defined(OS_STARBOARD)
+#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(BASE_HASH_USE_HASH_STRUCT)
+template<>
+struct hash<FilePath> {
+  size_t operator()(const FilePath& f) const {
+    return hash<FilePath::StringType>()(f.value());
+  }
+};
+
+#else
+inline size_t hash_value(const FilePath& f) {
+  return hash_value(f.value());
+}
+
+#endif  // defined(BASE_HASH_USE_HASH_STRUCT)
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#endif  // BASE_FILE_PATH_H_
diff --git a/src/base/file_path_unittest.cc b/src/base/file_path_unittest.cc
new file mode 100644
index 0000000..b61d5d2
--- /dev/null
+++ b/src/base/file_path_unittest.cc
@@ -0,0 +1,1213 @@
+// Copyright (c) 2012 The Chromium Authors. All 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)
+
+// This macro constructs strings which can contain NULs.
+#define FPS(x) FilePath::StringType(FPL(x), arraysize(FPL(x)) - 1)
+
+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) || defined(OS_STARBOARD)
+    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},
+// TODO: Since Cobalt on Windows is compiled in POSIX emulation mode, strings
+//       are single-byte. Unicode characters cannot be represented in
+//       single-byte encoding, so tests below are doomed to fail. Re-enable
+//       tests after getting rid of POSIX emulation.
+// TODO: Starboard, the replacement for POSIX emulation, would like path
+//       encoding to be consistent across platforms in common code. Lowest
+//       common denominator suggests we should still use single-byte paths. The
+//       TODO is to discuss and act on these TODOs.
+#if !defined(COBALT_WIN) && !defined(OS_STARBOARD)
+    { { FPL("\u1E9E"),                       FPL("\u1E9E") },               0},
+#endif
+// CompareIgnoreCase is tertiary.  These glyphs don't exist.
+#if !defined(COBALT) && !defined(OS_STARBOARD)
+    { { FPL("\u00DF"),                       FPL("\u1E9E") },               1},
+    { { FPL("SS"),                           FPL("\u00DF") },              -1},
+    { { FPL("SS"),                           FPL("\u1E9E") },               1},
+#endif
+#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" },
+#if !defined(__LB_SHELL__)
+    // "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" },
+#endif
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    // Test FromUTF8Unsafe() works.
+    FilePath from_utf8 = FilePath::FromUTF8Unsafe(cases[i].utf8);
+    EXPECT_EQ(cases[i].native, from_utf8.value())
+        << "i: " << i << ", input: " << cases[i].native;
+    // Test AsUTF8Unsafe() works.
+    FilePath from_native = FilePath(cases[i].native);
+    EXPECT_EQ(cases[i].utf8, from_native.AsUTF8Unsafe())
+        << "i: " << i << ", input: " << cases[i].native;
+    // Test the two file paths are identical.
+    EXPECT_EQ(from_utf8.value(), from_native.value());
+  }
+}
+
+TEST_F(FilePathTest, ConstructWithNUL) {
+  // Assert FPS() works.
+  ASSERT_TRUE(FPS("a\0b").length() == 3);
+
+  // Test constructor strips '\0'
+  FilePath path(FPS("a\0b"));
+  EXPECT_TRUE(path.value().length() == 1);
+  EXPECT_EQ(path.value(), FPL("a"));
+}
+
+TEST_F(FilePathTest, AppendWithNUL) {
+  // Assert FPS() works.
+  ASSERT_TRUE(FPS("b\0b").length() == 3);
+
+  // Test Append() strips '\0'
+  FilePath path(FPL("a"));
+  path = path.Append(FPS("b\0b"));
+  EXPECT_TRUE(path.value().length() == 3);
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+  EXPECT_EQ(path.value(), FPL("a\\b"));
+#else
+  EXPECT_EQ(path.value(), FPL("a/b"));
+#endif
+}
+
+TEST_F(FilePathTest, ReferencesParentWithNUL) {
+  // Assert FPS() works.
+  ASSERT_TRUE(FPS("..\0").length() == 3);
+
+  // Test ReferencesParent() doesn't break with "..\0"
+  FilePath path(FPS("..\0"));
+  EXPECT_TRUE(path.ReferencesParent());
+}
+
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+TEST_F(FilePathTest, NormalizePathSeparators) {
+  const struct UnaryTestData cases[] = {
+    { FPL("foo/bar"), FPL("foo\\bar") },
+    { FPL("foo/bar\\betz"), FPL("foo\\bar\\betz") },
+    { FPL("foo\\bar"), FPL("foo\\bar") },
+    { FPL("foo\\bar/betz"), FPL("foo\\bar\\betz") },
+    { FPL("foo"), FPL("foo") },
+    // Trailing slashes don't automatically get stripped.  That's what
+    // StripTrailingSeparators() is for.
+    { FPL("foo\\"), FPL("foo\\") },
+    { FPL("foo/"), FPL("foo\\") },
+    { FPL("foo/bar\\"), FPL("foo\\bar\\") },
+    { FPL("foo\\bar/"), FPL("foo\\bar\\") },
+    { FPL("foo/bar/"), FPL("foo\\bar\\") },
+    { FPL("foo\\bar\\"), FPL("foo\\bar\\") },
+    { FPL("\\foo/bar"), FPL("\\foo\\bar") },
+    { FPL("/foo\\bar"), FPL("\\foo\\bar") },
+    { FPL("c:/foo/bar/"), FPL("c:\\foo\\bar\\") },
+    { FPL("/foo/bar/"), FPL("\\foo\\bar\\") },
+    { FPL("\\foo\\bar\\"), FPL("\\foo\\bar\\") },
+    { FPL("c:\\foo/bar"), FPL("c:\\foo\\bar") },
+    { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") },
+    { FPL("\\\\foo\\bar\\"), FPL("\\\\foo\\bar\\") },
+    { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") },
+    // This method does not normalize the number of path separators.
+    { FPL("foo\\\\bar"), FPL("foo\\\\bar") },
+    { FPL("foo//bar"), FPL("foo\\\\bar") },
+    { FPL("foo/\\bar"), FPL("foo\\\\bar") },
+    { FPL("foo\\/bar"), FPL("foo\\\\bar") },
+    { FPL("///foo\\\\bar"), FPL("\\\\\\foo\\\\bar") },
+    { FPL("foo//bar///"), FPL("foo\\\\bar\\\\\\") },
+    { FPL("foo/\\bar/\\"), FPL("foo\\\\bar\\\\") },
+    { FPL("/\\foo\\/bar"), FPL("\\\\foo\\\\bar") },
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    FilePath observed = input.NormalizePathSeparators();
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+#endif
diff --git a/src/base/file_util.cc b/src/base/file_util.cc
new file mode 100644
index 0000000..cf12128
--- /dev/null
+++ b/src/base/file_util.cc
@@ -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.
+
+#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;
+}
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
+  std::ifstream file1(filename1.value().c_str(), std::ios::in);
+  std::ifstream file2(filename2.value().c_str(), std::ios::in);
+
+  // Even if both files aren't openable (and thus, in some sense, "equal"),
+  // any unusable file yields a result of "false".
+  if (!file1.is_open() || !file2.is_open())
+    return false;
+
+  do {
+    std::string line1, line2;
+    getline(file1, line1);
+    getline(file2, line2);
+
+    // Check for mismatched EOF states, or any error state.
+    if ((file1.eof() != file2.eof()) ||
+        file1.bad() || file2.bad()) {
+      return false;
+    }
+
+    // Trim all '\r' and '\n' characters from the end of the line.
+    std::string::size_type end1 = line1.find_last_not_of("\r\n");
+    if (end1 == std::string::npos)
+      line1.clear();
+    else if (end1 + 1 < line1.length())
+      line1.erase(end1 + 1);
+
+    std::string::size_type end2 = line2.find_last_not_of("\r\n");
+    if (end2 == std::string::npos)
+      line2.clear();
+    else if (end2 + 1 < line2.length())
+      line2.erase(end2 + 1);
+
+    if (line1 != line2)
+      return false;
+  } while (!file1.eof() || !file2.eof());
+
+  return true;
+}
+#endif
+
+bool ReadFileToString(const FilePath& path, std::string* contents) {
+  if (path.ReferencesParent())
+    return false;
+
+#if defined(COBALT)
+  // Use a smaller buffer so we don't run out of stack space.
+  const size_t kReadBufferSize = 1 << 12;
+#else
+  const size_t kReadBufferSize = 1 << 16;
+#endif
+
+#if defined(OS_STARBOARD)
+  base::PlatformFile file = base::CreatePlatformFile(
+      path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL, NULL);
+  if (file == base::kInvalidPlatformFileValue) {
+    return false;
+  }
+
+  char buf[kReadBufferSize];
+  size_t len;
+  while ((len = base::ReadPlatformFileAtCurrentPos(file, buf, sizeof(buf))) >
+         0) {
+    if (contents) {
+      contents->append(buf, len);
+    }
+  }
+  base::ClosePlatformFile(file);
+
+  return true;
+#else
+  FILE* file = OpenFile(path, "rb");
+  if (!file) {
+    return false;
+  }
+
+  char buf[kReadBufferSize];
+  size_t len;
+  while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
+    if (contents)
+      contents->append(buf, len);
+  }
+  CloseFile(file);
+
+  return true;
+#endif
+}
+
+bool IsDirectoryEmpty(const FilePath& dir_path) {
+  FileEnumerator files(dir_path, false,
+      FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
+  if (files.Next().value().empty())
+    return true;
+  return false;
+}
+
+#if !defined(OS_STARBOARD)
+FILE* CreateAndOpenTemporaryFile(FilePath* path) {
+  FilePath directory;
+  if (!GetTempDir(&directory))
+    return NULL;
+
+  return CreateAndOpenTemporaryFileInDir(directory, path);
+}
+#endif  // !defined(OS_STARBOARD)
+
+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();
+}
+
+#if !defined(OS_STARBOARD)
+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(COBALT_WIN)
+  // Ensure that this makes it through to the CRT.
+  flags |= base::PLATFORM_FILE_WRITE;
+#endif // COBALT_WIN
+
+#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;
+}
+#endif  // !defined(OS_STARBOARD)
+
+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;
+#elif defined(OS_STARBOARD)
+    running_size += info.sb_info.size;
+#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;
+#elif defined(OS_STARBOARD)
+    running_size += info.sb_info.size;
+#else
+    running_size += info.stat.st_size;
+#endif
+  }
+  return running_size;
+}
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+///////////////////////////////////////////////
+// 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();
+}
+#endif
+
+///////////////////////////////////////////////
+// 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/src/base/file_util.h b/src/base/file_util.h
new file mode 100644
index 0000000..4392627
--- /dev/null
+++ b/src/base/file_util.h
@@ -0,0 +1,679 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// 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>
+#elif defined(OS_STARBOARD)
+#include "starboard/file.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/file_descriptor_posix.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.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:
+
+#if !defined(OS_STARBOARD)
+// 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);
+#endif
+
+// 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
+
+#if !defined(OS_STARBOARD)
+// NOTE: file_util::Move is used in a small number of places. We won't
+// implement it in Starboard for the time being, but we may bring it back if it
+// is is deemed necessary.
+
+// 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);
+#endif
+
+// Copies a single file. Use CopyDirectory to copy directories.
+BASE_EXPORT bool CopyFile(const FilePath& from_path, const FilePath& to_path);
+
+#if !defined(OS_STARBOARD)
+// NOTE: file_util::CopyDirectory is only referenced by disabled tests.
+
+// 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);
+#endif
+
+// 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);
+
+#if !defined(__LB_SHELL__) && !defined(COBALT)
+// 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);
+#endif
+
+// Read the file at |path| into |contents|, returning true on success.
+// This function fails if the |path| contains path traversal components ('..').
+// |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);
+
+#if !defined(OS_STARBOARD)
+// 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);
+#endif
+
+// 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);
+
+#if !defined(OS_STARBOARD)
+// 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);
+#endif
+
+#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);
+
+#if !defined(OS_STARBOARD)
+// 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) && !defined(__LB_WIIU__)
+// 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);
+#endif
+
+// 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);
+
+#if !defined(OS_STARBOARD)
+// 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);
+#endif
+
+// 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)
+
+#if !defined(OS_STARBOARD)
+// 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;
+#endif
+
+#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;
+#elif defined(OS_STARBOARD)
+  typedef struct {
+    SbFileInfo sb_info;
+    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_;
+#elif defined(OS_STARBOARD)
+  struct DirectoryEntryInfo {
+    FilePath filename;
+    SbFileInfo sb_info;
+  };
+
+  // Read the filenames in source into the vector of DirectoryEntryInfo's
+  static bool ReadDirectory(std::vector<DirectoryEntryInfo>* entries,
+                            const FilePath& source);
+
+  // 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);
+};
+
+#if !defined(__LB_SHELL__) && !defined(COBALT)
+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);
+};
+#endif
+
+// 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/src/base/file_util_android.cc b/src/base/file_util_android.cc
new file mode 100644
index 0000000..79db279
--- /dev/null
+++ b/src/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/src/base/file_util_linux.cc b/src/base/file_util_linux.cc
new file mode 100644
index 0000000..f7d4f6e
--- /dev/null
+++ b/src/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/src/base/file_util_mac.mm b/src/base/file_util_mac.mm
new file mode 100644
index 0000000..0638167
--- /dev/null
+++ b/src/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/src/base/file_util_posix.cc b/src/base/file_util_posix.cc
new file mode 100644
index 0000000..6a4a309
--- /dev/null
+++ b/src/base/file_util_posix.cc
@@ -0,0 +1,1177 @@
+// Copyright (c) 2012 The Chromium Authors. All 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) && !defined(__LB_SHELL__)
+#include <glib.h>
+#endif
+
+#include <fstream>
+
+#include "base/basictypes.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/posix/eintr_wrapper.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) || defined(__LB_ANDROID__)
+#include "base/os_compat_android.h"
+#endif
+
+#if !defined(OS_IOS) && !defined(__LB_SHELL__)
+#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) || defined(__LB_SHELL__)
+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
+
+#if !defined(__LB_PS4__) && !defined(__LB_ANDROID__)
+// 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;
+}
+#endif
+
+// 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
+}
+
+#if !defined(__LB_PS4__) && !defined(__LB_ANDROID__)
+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;
+}
+#endif
+
+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) && !defined(__LB_SHELL__)
+  #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 append
+    // the suffix after from_path to to_path to create the target_path.
+    FilePath target_path(to_path);
+    if (from_path_base != current) {
+      if (!from_path_base.AppendRelativePath(current, &target_path)) {
+        success = false;
+        break;
+      }
+    }
+
+    if (S_ISDIR(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;
+}
+
+#if !defined(__LB_XB1__) && !defined(__LB_XB360__)
+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;
+}
+#endif
+
+// 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;
+}
+
+#if !defined(__LB_SHELL__)
+FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) {
+  FilePath directory;
+  if (!GetShmemTempDir(&directory, executable))
+    return NULL;
+
+  return CreateAndOpenTemporaryFileInDir(directory, path);
+}
+#endif
+
+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);
+}
+
+#if !defined(__LB_XB1__) && !defined(__LB_XB360__)
+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;
+}
+#endif
+
+// 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;
+}
+
+#if !defined(__LB_SHELL__)
+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;
+}
+#endif
+
+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) != 0))
+      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) && !defined(__LB_SHELL__)
+  #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
+#if !defined(__LB_SHELL__)
+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;
+}
+#endif
+
+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)
+#if !defined(__LB_SHELL__)
+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");
+}
+#endif // !defined(__LB_SHELL__)
+
+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/src/base/file_util_proxy.cc b/src/base/file_util_proxy.cc
new file mode 100644
index 0000000..2b075b0
--- /dev/null
+++ b/src/base/file_util_proxy.cc
@@ -0,0 +1,449 @@
+// Copyright (c) 2012 The Chromium Authors. All 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,
+             const FileUtilProxy::CreateOrOpenTask& open_task) {
+    DCHECK(!callback.is_null());
+    if (error_ != PLATFORM_FILE_ERROR_TOO_MANY_OPENED) {
+      callback.Run(error_, PassPlatformFile(&file_handle_), created_);
+      return;
+    }
+    DLOG(WARNING) << "Too many files are opened, retrying ...";
+    CreateOrOpenHelper* helper =
+        new CreateOrOpenHelper(task_runner_, close_task_);
+    task_runner_->PostTaskAndReply(
+        FROM_HERE,
+        Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), open_task),
+        Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback, open_task));
+  }
+
+ 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));
+}
+
+#if !defined(OS_STARBOARD)
+// 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));
+}
+#endif
+
+// 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, open_task));
+}
+
+// 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/src/base/file_util_proxy.h b/src/base/file_util_proxy.h
new file mode 100644
index 0000000..f6ecbad
--- /dev/null
+++ b/src/base/file_util_proxy.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_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);
+
+#if !defined(OS_STARBOARD)
+  // 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);
+#endif
+
+  // 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/src/base/file_util_proxy_unittest.cc b/src/base/file_util_proxy_unittest.cc
new file mode 100644
index 0000000..e238b32
--- /dev/null
+++ b/src/base/file_util_proxy_unittest.cc
@@ -0,0 +1,438 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop.h"
+#include "base/platform_file.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();
+  ASSERT_EQ(PLATFORM_FILE_OK, error_);
+
+  // file_ has been closed by FileUtilProxy::Close
+  file_ = kInvalidPlatformFileValue;
+
+#if !defined(OS_STARBOARD)
+  // Now it should pass on all platforms.
+  EXPECT_TRUE(file_util::Move(test_path(), test_dir_path().AppendASCII("new")));
+#endif
+}
+
+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_);
+
+#if defined(__LB_WIIU__)
+  // Don't open a handle for reading if one is already open for writing
+  ClosePlatformFile(file);
+#endif
+
+  // 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]);
+  }
+}
+
+#if !defined(__LB_PS3__) && !defined(__LB_WIIU__) && !defined(OS_STARBOARD)
+// FileUtilProxy::Touch creates a platform file and passes its descriptor to
+// base::TouchPlatformFile().
+// This requires OS support for futimes.
+
+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()));
+}
+#endif
+
+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);
+
+#if defined(__LB_WIIU__)
+  // If the platform file is already created, GetTestPlatformFile will return
+  // the platform file, so the flags are irrelevant.
+  ClosePlatformFile(GetTestPlatformFile(0));
+#endif
+
+  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);
+
+#if defined(__LB_WIIU__)
+  // If the platform file is already created, GetTestPlatformFile will return
+  // the platform file, so the flags are irrelevant.
+  ClosePlatformFile(GetTestPlatformFile(0));
+#endif
+
+  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/src/base/file_util_starboard.cc b/src/base/file_util_starboard.cc
new file mode 100644
index 0000000..0c6511a
--- /dev/null
+++ b/src/base/file_util_starboard.cc
@@ -0,0 +1,602 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Adapted from file_util_posix.cc.
+
+#include "base/file_util.h"
+
+#include <stack>
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/platform_file.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time.h"
+#include "starboard/directory.h"
+#include "starboard/file.h"
+#include "starboard/system.h"
+
+namespace {
+
+// The list of portable filename characters as per POSIX. This should be the
+// lowest-common-denominator of acceptable filename characters.
+const char kPortableFilenameCharacters[] = {
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+  "abcdefghijklmnopqrstuvwxyz"
+  "0123456789"
+  "._-"
+};
+const int kPortableFilenameCharactersLength =
+    SB_ARRAY_SIZE_INT(kPortableFilenameCharacters) - 1;
+
+// 8 characters = 65 ^ 8 possible filenames, which gives a nice wide space for
+// avoiding collisions.
+const char kTempSubstitution[] = "XXXXXXXX";
+const int kTempSubstitutionLength = SB_ARRAY_SIZE_INT(kTempSubstitution) - 1;
+
+std::string TempFileName() {
+  return std::string(".com.youtube.Cobalt.XXXXXXXX");
+}
+
+// Takes the template defined in |in_out_template| and destructively replaces
+// any 'X' characters at the end with randomized portable filename characters.
+void GenerateTempFileName(FilePath::StringType *in_out_template) {
+  size_t template_start = in_out_template->find(kTempSubstitution);
+  if (template_start == FilePath::StringType::npos) {
+    // No pattern.
+    return;
+  }
+
+  for (int i = 0; i < kTempSubstitutionLength; ++i) {
+    uint64_t random = SbSystemGetRandomUInt64();
+    int index = random % kPortableFilenameCharactersLength;
+    (*in_out_template)[template_start + i] = kPortableFilenameCharacters[index];
+  }
+}
+
+// Creates a random filename based on the TempFileName() pattern, creates the
+// file, leaving it open, placing the path in |out_path| and returning the open
+// SbFile.
+SbFile CreateAndOpenTemporaryFile(FilePath directory, FilePath *out_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(out_path);
+  FilePath path = directory.Append(TempFileName());
+  FilePath::StringType tmpdir_string = path.value();
+  GenerateTempFileName(&tmpdir_string);
+  *out_path = FilePath(tmpdir_string);
+  return SbFileOpen(tmpdir_string.c_str(), kSbFileCreateOnly | kSbFileWrite,
+                    NULL, NULL);
+}
+
+// Retries creating a temporary file until it can win the race to create a
+// unique one.
+SbFile CreateAndOpenTemporaryFileSafely(FilePath directory,
+                                        FilePath *out_path) {
+  SbFile file = kSbFileInvalid;
+  while (!SbFileIsValid(file)) {
+    file = CreateAndOpenTemporaryFile(directory, out_path);
+  }
+  return file;
+}
+
+bool CreateTemporaryDirInDirImpl(const FilePath &base_dir,
+                                 const FilePath::StringType &name_tmpl,
+                                 FilePath *new_dir) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(name_tmpl.find(kTempSubstitution) != FilePath::StringType::npos)
+      << "Directory name template must contain \"XXXXXXXX\".";
+
+  FilePath dir_template = base_dir.Append(name_tmpl);
+  std::string dir_template_string = dir_template.value();
+  FilePath sub_dir;
+  while (true) {
+    std::string sub_dir_string = dir_template_string;
+    GenerateTempFileName(&sub_dir_string);
+    sub_dir = FilePath(sub_dir_string);
+    if (!file_util::DirectoryExists(sub_dir)) {
+      break;
+    }
+  }
+
+  // NOTE: This is not as secure as mkdtemp, because it doesn't atomically
+  // guarantee that there is no collision. But, with 8 X's it should be good
+  // enough for our purposes.
+  if (!file_util::CreateDirectory(sub_dir)) {
+    DPLOG(ERROR) << "CreateDirectory";
+    return false;
+  }
+
+  *new_dir = sub_dir;
+  return true;
+}
+
+}  // namespace
+
+namespace file_util {
+
+bool AbsolutePath(FilePath* path) {
+  // We don't have cross-platform tools for this, so we will just return true if
+  // the path is already absolute.
+  return path->IsAbsolute();
+}
+
+bool Delete(const FilePath &path, bool recursive) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  const char *path_str = path.value().c_str();
+
+  bool directory = SbDirectoryCanOpen(path_str);
+  if (!recursive || !directory) {
+    return SbFileDelete(path_str);
+  }
+
+  bool success = true;
+  std::stack<std::string> directories;
+  directories.push(path.value());
+
+  // NOTE: Right now, for Linux, SbFileGetInfo does not follow
+  // symlinks. This is good for avoiding deleting through symlinks, but makes it
+  // hard to use symlinks on platforms where they are supported. This seems
+  // safest for the lowest-common-denominator approach of pretending symlinks
+  // don't exist.
+  FileEnumerator traversal(
+      path, true, FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
+
+  // Delete all files and push all directories in depth order onto the stack.
+  for (FilePath current = traversal.Next();
+       success && !current.empty();
+       current = traversal.Next()) {
+    FileEnumerator::FindInfo info;
+    traversal.GetFindInfo(&info);
+
+    if (FileEnumerator::IsDirectory(info)) {
+      directories.push(current.value());
+    } else {
+      success = SbFileDelete(current.value().c_str());
+    }
+  }
+
+  // Delete all directories in reverse-depth order, now that they have no more
+  // regular files.
+  while (success && !directories.empty()) {
+    success = SbFileDelete(directories.top().c_str());
+    directories.pop();
+  }
+
+  return success;
+}
+
+bool CopyFile(const FilePath &from_path, const FilePath &to_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  base::PlatformFile source_file = base::CreatePlatformFile(
+      from_path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL,
+      NULL);
+  if (source_file == base::kInvalidPlatformFileValue) {
+    DPLOG(ERROR) << "CopyFile(): Unable to open source file: "
+                 << from_path.value();
+    return false;
+  }
+
+  base::PlatformFile destination_file = base::CreatePlatformFileUnsafe(
+      to_path, base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE, NULL,
+      NULL);
+  if (destination_file == base::kInvalidPlatformFileValue) {
+    DPLOG(ERROR) << "CopyFile(): Unable to open destination file: "
+                 << to_path.value();
+    ignore_result(base::ClosePlatformFile(destination_file));
+    return false;
+  }
+
+  const size_t kBufferSize = 32768;
+  std::vector<char> buffer(kBufferSize);
+  bool result = true;
+
+  while (result) {
+    int bytes_read = base::ReadPlatformFileAtCurrentPos(source_file, &buffer[0],
+                                                        buffer.size());
+    if (bytes_read < 0) {
+      result = false;
+      break;
+    }
+
+    if (bytes_read == 0) {
+      break;
+    }
+
+    int bytes_written = base::WritePlatformFileAtCurrentPos(
+        destination_file, &buffer[0], bytes_read);
+    if (bytes_written < bytes_read) {
+      DLOG(ERROR) << "CopyFile(): bytes_read (" << bytes_read
+                  << ") > bytes_written (" << bytes_written << ")";
+      // Because we use a best-effort write, if we wrote less than what was
+      // available, something went wrong.
+      result = false;
+      break;
+    }
+  }
+
+  if (!base::ClosePlatformFile(source_file)) {
+    result = false;
+  }
+
+  if (!base::ClosePlatformFile(destination_file)) {
+    result = false;
+  }
+
+  return result;
+}
+
+bool PathExists(const FilePath &path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return SbFileExists(path.value().c_str());
+}
+
+bool PathIsWritable(const FilePath &path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return SbFileCanOpen(path.value().c_str(), kSbFileOpenAlways | kSbFileWrite);
+}
+
+bool DirectoryExists(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  SbFileInfo info;
+  if (!SbFileGetPathInfo(path.value().c_str(), &info)) {
+    return false;
+  }
+
+  return info.is_directory;
+}
+
+bool GetTempDir(FilePath *path) {
+  char buffer[SB_FILE_MAX_PATH + 1] = {0};
+  bool result = SbSystemGetPath(kSbSystemPathTempDirectory, buffer,
+                                SB_ARRAY_SIZE_INT(buffer));
+  if (!result) {
+    return false;
+  }
+
+  *path = FilePath(buffer);
+  if (DirectoryExists(*path)) {
+    return true;
+  }
+
+  return CreateDirectory(*path);
+}
+
+bool GetShmemTempDir(FilePath *path, bool executable) {
+  return GetTempDir(path);
+}
+
+FilePath GetHomeDir() {
+  FilePath path;
+  bool result = PathService::Get(base::DIR_HOME, &path);
+  DCHECK(result);
+  return path;
+}
+
+bool CreateTemporaryFile(FilePath *path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(path);
+
+  FilePath directory;
+  if (!GetTempDir(&directory)) {
+    return false;
+  }
+
+  return CreateTemporaryFileInDir(directory, path);
+}
+
+bool CreateTemporaryFileInDir(const FilePath &dir, FilePath *temp_file) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(temp_file);
+  SbFile file = CreateAndOpenTemporaryFileSafely(dir, temp_file);
+  return (SbFileIsValid(file) && SbFileClose(file));
+}
+
+bool CreateTemporaryDirInDir(const FilePath &base_dir,
+                             const FilePath::StringType &prefix,
+                             FilePath *new_dir) {
+  FilePath::StringType mkdtemp_template = prefix + kTempSubstitution;
+  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();
+  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 (!SbDirectoryCreate(i->value().c_str())) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool IsLink(const FilePath &file_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  SbFileInfo info;
+
+  // If we can't SbfileGetPathInfo on the file, it's safe to assume that the
+  // file won't at least be a 'followable' link.
+  if (!SbFileGetPathInfo(file_path.value().c_str(), &info)) {
+    return false;
+  }
+
+  return info.is_symbolic_link;
+}
+
+bool GetFileInfo(const FilePath &file_path, base::PlatformFileInfo *results) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  SbFileInfo info;
+  if (!SbFileGetPathInfo(file_path.value().c_str(), &info)) {
+    return false;
+  }
+
+  results->is_directory = info.is_directory;
+  results->size = info.size;
+  results->last_modified = base::Time::FromSbTime(info.last_modified);
+  results->last_accessed = base::Time::FromSbTime(info.last_accessed);
+  results->creation_time = base::Time::FromSbTime(info.creation_time);
+  return true;
+}
+
+int ReadFile(const FilePath &filename, char *data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  base::PlatformFile file = base::CreatePlatformFile(
+      filename, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL,
+      NULL);
+  if (file == base::kInvalidPlatformFileValue) {
+    DLOG(ERROR) << "ReadFile(" << filename.value() << "): Unable to open.";
+    return -1;
+  }
+
+  // We use a best-effort read here.
+  int bytes_read = base::ReadPlatformFileAtCurrentPos(file, data, size);
+  if (!base::ClosePlatformFile(file)) {
+    DLOG(ERROR) << "ReadFile(" << filename.value() << "): Unable to close.";
+    return -1;
+  }
+
+  return bytes_read;
+}
+
+int WriteFile(const FilePath &filename, const char *data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  base::PlatformFile file = base::CreatePlatformFile(
+      filename, base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE,
+      NULL, NULL);
+  if (file == base::kInvalidPlatformFileValue) {
+    DLOG(ERROR) << "WriteFile(" << filename.value() << "): Unable to open.";
+    return -1;
+  }
+
+  // We use a best-effort write here.
+  int bytes_written = base::WritePlatformFileAtCurrentPos(file, data, size);
+  if (!base::ClosePlatformFile(file)) {
+    DLOG(ERROR) << "WriteFile(" << filename.value() << "): Unable to close.";
+    return -1;
+  }
+
+  return bytes_written;
+}
+
+int AppendToFile(const FilePath &filename, const char *data, int size) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  base::PlatformFile file = base::CreatePlatformFile(
+      filename, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, NULL,
+      NULL);
+  if (file == base::kInvalidPlatformFileValue) {
+    DLOG(ERROR) << "AppendToFile(" << filename.value() << "): Unable to open.";
+    return -1;
+  }
+
+  if (!base::SeekPlatformFile(file, base::PLATFORM_FILE_FROM_END, 0)) {
+    DLOG(ERROR) << "AppendToFile(" << filename.value()
+                << "): Unable to truncate.";
+    return -1;
+  }
+
+  int bytes_written = base::WritePlatformFileAtCurrentPos(file, data, size);
+  if (!base::ClosePlatformFile(file)) {
+    DLOG(ERROR) << "AppendToFile(" << filename.value() << "): Unable to close.";
+    return -1;
+  }
+
+  return bytes_written;
+}
+
+bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo &find_info,
+                              const base::Time &cutoff_time) {
+  return FileEnumerator::GetLastModifiedTime(find_info) >= cutoff_time;
+}
+
+
+///////////////////////////////////////////////
+// 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_)) {
+      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()) {
+        NOTREACHED() << "Patterns not supported in Starboard.";
+        continue;
+      }
+
+      if (recursive_ && i->sb_info.is_directory) {
+        pending_paths_.push(full_path);
+      }
+
+      if ((i->sb_info.is_directory && (file_type_ & DIRECTORIES)) ||
+          (!i->sb_info.is_directory && (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->sb_info), &(cur_entry->sb_info), sizeof(info->sb_info));
+  info->filename.assign(cur_entry->filename.value());
+}
+
+// static
+bool FileEnumerator::IsDirectory(const FindInfo &info) {
+  return info.sb_info.is_directory;
+}
+
+// static
+FilePath FileEnumerator::GetFilename(const FindInfo &find_info) {
+  return FilePath(find_info.filename);
+}
+
+// static
+int64 FileEnumerator::GetFilesize(const FindInfo &find_info) {
+  return find_info.sb_info.size;
+}
+
+// static
+base::Time FileEnumerator::GetLastModifiedTime(const FindInfo &find_info) {
+  return base::Time::FromSbTime(find_info.sb_info.last_modified);
+}
+
+// static
+bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo> *entries,
+                                   const FilePath &source) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  SbDirectory dir = SbDirectoryOpen(source.value().c_str(), NULL);
+  if (!SbDirectoryIsValid(dir)) {
+    return false;
+  }
+
+  SbDirectoryEntry entry;
+  while (SbDirectoryGetNext(dir, &entry)) {
+    DirectoryEntryInfo info;
+    info.filename = FilePath(entry.name);
+
+    FilePath full_name = source.Append(entry.name);
+    // TODO: Make sure this follows symlinks on relevant platforms.
+    if (!SbFileGetPathInfo(full_name.value().c_str(), &info.sb_info)) {
+      DPLOG(ERROR) << "Couldn't SbFileGetInfo on " << full_name.value();
+      memset(&info.sb_info, 0, sizeof(info.sb_info));
+    }
+
+    entries->push_back(info);
+  }
+
+  ignore_result(SbDirectoryClose(dir));
+  return true;
+}
+
+}  // namespace file_util
diff --git a/src/base/file_util_unittest.cc b/src/base/file_util_unittest.cc
new file mode 100644
index 0000000..6f4e111
--- /dev/null
+++ b/src/base/file_util_unittest.cc
@@ -0,0 +1,2493 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <tchar.h>
+#include <winioctl.h>
+#endif
+
+#if !defined(__LB_PS3__)
+// These headers are not available on the PS3
+#include <algorithm>
+#include <fstream>
+#endif
+#include <set>
+
+#include "base/base_paths.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/test/test_file_util.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)
+
+#if defined(COBALT) || defined(OS_STARBOARD)
+#define MAYBE_CopyDirectoryRecursivelyNew DISABLED_CopyDirectoryRecursivelyNew
+#define MAYBE_CopyDirectoryRecursivelyExists \
+  DISABLED_CopyDirectoryRecursivelyExists
+#define MAYBE_CopyDirectoryNew DISABLED_CopyDirectoryNew
+#define MAYBE_CopyDirectoryExists DISABLED_CopyDirectoryExists
+#define MAYBE_CopyFileWithCopyDirectoryRecursiveToNew \
+  DISABLED_CopyFileWithCopyDirectoryRecursiveToNew
+#define MAYBE_CopyFileWithCopyDirectoryRecursiveToExisting \
+  DISABLED_CopyFileWithCopyDirectoryRecursiveToExisting
+#define MAYBE_CopyFileWithCopyDirectoryRecursiveToExistingDirectory \
+  DISABLED_CopyFileWithCopyDirectoryRecursiveToExistingDirectory
+#define MAYBE_CopyDirectoryWithTrailingSeparators \
+  DISABLED_CopyDirectoryWithTrailingSeparators
+#else
+#define MAYBE_CopyDirectoryRecursivelyNew CopyDirectoryRecursivelyNew
+#define MAYBE_CopyDirectoryRecursivelyExists CopyDirectoryRecursivelyExists
+#define MAYBE_CopyDirectoryNew CopyDirectoryNew
+#define MAYBE_CopyDirectoryExists CopyDirectoryExists
+#define MAYBE_CopyFileWithCopyDirectoryRecursiveToNew \
+  CopyFileWithCopyDirectoryRecursiveToNew
+#define MAYBE_CopyFileWithCopyDirectoryRecursiveToExisting \
+  CopyFileWithCopyDirectoryRecursiveToExisting
+#define MAYBE_CopyFileWithCopyDirectoryRecursiveToExistingDirectory \
+  CopyFileWithCopyDirectoryRecursiveToExistingDirectory
+#define MAYBE_CopyDirectoryWithTrailingSeparators \
+  CopyDirectoryWithTrailingSeparators
+#endif
+
+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());
+  }
+
+  base::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) {
+#if defined(__LB_PS3__)
+  FILE *file = fopen(filename.value().c_str(), "w");
+  ASSERT_TRUE(file != NULL);
+  fputws(contents.c_str(), file);
+  fclose(file);
+#elif defined(__LB_WIIU__)
+  int fd = open(filename.value().c_str(), O_WRONLY | O_CREAT | O_TRUNC);
+  ASSERT_TRUE(fd >= 0);
+  char mb_sequence[64];
+  const wchar_t* wc_string = contents.c_str();
+  size_t nbytes = wcsrtombs(mb_sequence, &wc_string, arraysize(mb_sequence), NULL);
+  ssize_t bytes_written = write(fd, mb_sequence, nbytes);
+  ASSERT_TRUE(bytes_written == nbytes);
+  ASSERT_TRUE(wc_string == NULL);
+  close(fd);
+#else
+  std::wofstream file;
+  file.open(filename.value().c_str());
+  ASSERT_TRUE(file.is_open());
+  file << contents;
+  file.close();
+#endif
+}
+
+// Simple function to take out some text from a file.
+std::wstring ReadTextFile(const FilePath& filename) {
+  wchar_t contents[64];
+#if defined(__LB_PS3__)
+  FILE *file = fopen(filename.value().c_str(), "r");
+  EXPECT_TRUE(file != NULL);
+  fgetws(contents, arraysize(contents), file);
+  fclose(file);
+#elif defined(__LB_WIIU__)
+  char mb_sequence_buffer[64];
+  int fd = open(filename.value().c_str(), O_RDONLY);
+  EXPECT_TRUE(fd >= 0);
+  ssize_t bytes_read = read(fd, mb_sequence_buffer, arraysize(mb_sequence_buffer));
+  EXPECT_TRUE(bytes_read >= 0);
+  close(fd);
+  const char * mb_sequence = mb_sequence_buffer;
+  size_t nbytes = mbsrtowcs(contents, &mb_sequence, sizeof(contents), NULL);
+  EXPECT_TRUE(mb_sequence == NULL);
+#else
+  std::wifstream file;
+  file.open(filename.value().c_str());
+  EXPECT_TRUE(file.is_open());
+  file.getline(contents, arraysize(contents));
+  file.close();
+#endif
+  return std::wstring(contents);
+}
+
+#if defined(OS_WIN)
+uint64 FileTimeAsUint64(const FILETIME& ft) {
+  ULARGE_INTEGER u;
+  u.LowPart = ft.dwLowDateTime;
+  u.HighPart = ft.dwHighDateTime;
+  return u.QuadPart;
+}
+#endif
+
+
+TEST_F(FileUtilTest, FileAndDirectorySize) {
+  // Create three files of 20, 30 and 3 chars (utf8). ComputeDirectorySize
+  // should return 53 bytes.
+  FilePath file_01 = temp_dir_.path().Append(FPL("The file 01.txt"));
+  CreateTextFile(file_01, L"12345678901234567890");
+  int64 size_f1 = 0;
+  ASSERT_TRUE(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);
+
+#if !defined(OS_STARBOARD)
+  // No pattern support in Starboard.
+  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);
+#endif
+}
+
+#if !defined(OS_STARBOARD)
+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()));
+}
+#endif
+
+#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);
+}
+
+TEST_F(FileUtilTest, CreateTemporaryFileInDirLongPathTest) {
+  // Test that CreateTemporaryFileInDir() creates a path and returns a long path
+  // if it is available. This test requires that:
+  // - the filesystem at |temp_dir_| supports long filenames.
+  // - the account has FILE_LIST_DIRECTORY permission for all ancestor
+  //   directories of |temp_dir_|.
+  const FilePath::CharType kLongDirName[] = FPL("A long path");
+  const FilePath::CharType kTestSubDirName[] = FPL("test");
+  FilePath long_test_dir = temp_dir_.path().Append(kLongDirName);
+  ASSERT_TRUE(file_util::CreateDirectory(long_test_dir));
+
+  // kLongDirName is not a 8.3 component. So GetShortName() should give us a
+  // different short name.
+  WCHAR path_buffer[MAX_PATH];
+  DWORD path_buffer_length = GetShortPathName(long_test_dir.value().c_str(),
+                                              path_buffer, MAX_PATH);
+  ASSERT_LT(path_buffer_length, DWORD(MAX_PATH));
+  ASSERT_NE(DWORD(0), path_buffer_length);
+  FilePath short_test_dir(path_buffer);
+  ASSERT_STRNE(kLongDirName, short_test_dir.BaseName().value().c_str());
+
+  FilePath temp_file;
+  ASSERT_TRUE(file_util::CreateTemporaryFileInDir(short_test_dir, &temp_file));
+  EXPECT_STREQ(kLongDirName, temp_file.DirName().BaseName().value().c_str());
+  EXPECT_TRUE(file_util::PathExists(temp_file));
+
+  // Create a subdirectory of |long_test_dir| and make |long_test_dir|
+  // unreadable. We should still be able to create a temp file in the
+  // subdirectory, but we won't be able to determine the long path for it. This
+  // mimics the environment that some users run where their user profiles reside
+  // in a location where the don't have full access to the higher level
+  // directories. (Note that this assumption is true for NTFS, but not for some
+  // network file systems. E.g. AFS).
+  FilePath access_test_dir = long_test_dir.Append(kTestSubDirName);
+  ASSERT_TRUE(file_util::CreateDirectory(access_test_dir));
+  file_util::PermissionRestorer long_test_dir_restorer(long_test_dir);
+  ASSERT_TRUE(file_util::MakeFileUnreadable(long_test_dir));
+
+  // Use the short form of the directory to create a temporary filename.
+  ASSERT_TRUE(file_util::CreateTemporaryFileInDir(
+      short_test_dir.Append(kTestSubDirName), &temp_file));
+  EXPECT_TRUE(file_util::PathExists(temp_file));
+  EXPECT_TRUE(short_test_dir.IsParent(temp_file.DirName()));
+
+  // Check that the long path can't be determined for |temp_file|.
+  path_buffer_length = GetLongPathName(temp_file.value().c_str(),
+                                       path_buffer, MAX_PATH);
+  EXPECT_EQ(DWORD(0), path_buffer_length);
+}
+
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX) && !defined(__LB_SHELL__)
+// Symbolic links not supported in lbshell
+
+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) && !defined(__LB_SHELL__)
+// Symbolic links not supported in lbshell
+
+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));
+}
+
+#if !defined(OS_STARBOARD)
+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));
+}
+#endif
+
+#if !defined(OS_STARBOARD)
+TEST_F(FileUtilTest, MAYBE_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, MAYBE_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, MAYBE_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, MAYBE_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, MAYBE_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, MAYBE_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,
+       MAYBE_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, MAYBE_CopyDirectoryWithTrailingSeparators) {
+  // 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));
+
+  // Copy the directory recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  // Create from path with trailing separators.
+#if defined(OS_WIN)
+  FilePath from_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir\\\\\\"));
+#elif defined (OS_POSIX)
+  FilePath from_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir///"));
+#endif
+
+  EXPECT_TRUE(file_util::CopyDirectory(from_path, 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(dir_name_to));
+  EXPECT_TRUE(file_util::PathExists(file_name_to));
+}
+#endif  // defined(OS_STARBOARD)
+
+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));
+
+#if defined(OS_STARBOARD)
+  // Why should we ensure CopyFile is unsafe? On Starboard, it won't open files
+  // with a ".." in the path.
+  // Copy the file to another location using '..' in the path.
+  FilePath dest_file2(temp_dir_.path());
+  dest_file2 = dest_file2.AppendASCII("DestFile.txt");
+  ASSERT_TRUE(file_util::CopyFile(file_name_from, dest_file2));
+#else
+  // 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));
+#endif
+
+  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;
+
+#if !defined(__LB_WIIU__) && !defined(OS_STARBOARD)
+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));
+}
+#endif
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+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));
+}
+#endif // __LB_SHELL__
+
+// 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));
+}
+
+#if !defined(OS_STARBOARD)
+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));
+  }
+}
+#endif
+
+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));
+}
+
+#if !defined(__LB_SHELL__)
+TEST_F(FileUtilTest, GetShmemTempDirTest) {
+  FilePath dir;
+  EXPECT_TRUE(file_util::GetShmemTempDir(&dir, false));
+  EXPECT_TRUE(file_util::DirectoryExists(dir));
+}
+#endif
+
+TEST_F(FileUtilTest, CreateDirectoryTest) {
+  FilePath test_root =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("create_directory_test"));
+#if defined(OS_WIN)
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("dir\\tree\\likely\\doesnt\\exist\\"));
+#elif defined(OS_POSIX)
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("dir/tree/likely/doesnt/exist/"));
+#elif defined(OS_STARBOARD)
+  // Directory depth is limited on certain platforms.
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("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));
+
+#if !defined(__LB_PS3__) && !defined(OS_STARBOARD)
+  // Starboard doesn't support relative paths.
+
+  // 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)));
+#endif
+
+  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.
+#if !defined(OS_STARBOARD)
+  EXPECT_TRUE(file_util::CreateDirectory(
+      FilePath(FilePath::kCurrentDirectory)));
+#endif
+
+  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 "..".
+#if !defined(OS_STARBOARD)
+  // Starboard doesn't support relative paths.
+  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());
+#endif
+
+  // 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);
+
+#if !defined(__LB_XB1__) && !defined(OS_STARBOARD)
+// As all file access is absolute, this is not an issue
+  // 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);
+#endif
+
+  // 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);
+
+#if !defined(OS_STARBOARD)
+  // 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);
+#endif
+
+  // 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
+}
+
+#if !defined(OS_STARBOARD)
+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));
+
+#if !defined(__LB_PS3__)
+  // file_util::TouchFile creates a platform file and passes its descriptor to
+  // base::TouchPlatformFile().
+  // Unfortunately, PS3 only implements utime, not futime, which means it
+  // can only touch a file path, not a file descriptor.
+
+  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());
+#endif
+}
+#endif
+
+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) && !defined(__LB_SHELL__)
+// We don't support uids or symlinks in lbshell
+
+// 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_));
+}
+
+#if !defined(__LB_SHELL__)
+// We don't support uids or symlinks in lbshell
+
+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
+
+#endif  // defined(OS_POSIX)
+
+}  // namespace
diff --git a/src/base/file_util_win.cc b/src/base/file_util_win.cc
new file mode 100644
index 0000000..ef51594
--- /dev/null
+++ b/src/base/file_util_win.cc
@@ -0,0 +1,977 @@
+// Copyright (c) 2012 The Chromium Authors. All 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) {
+  // WinXP SHFileOperation doesn't like trailing separators.
+  FilePath stripped_from = from_path.StripTrailingSeparators();
+  FilePath stripped_to = to_path.StripTrailingSeparators();
+
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // NOTE: I suspect we could support longer paths, but that would involve
+  // analyzing all our usage of files.
+  if (stripped_from.value().length() >= MAX_PATH ||
+      stripped_to.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, stripped_from.value().c_str());
+#pragma warning(suppress:4996)  // don't complain about wcscpy deprecation
+  wcscpy(double_terminated_path_to, stripped_to.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;
+  }
+
+  wchar_t long_temp_name[MAX_PATH + 1];
+  DWORD long_name_len = GetLongPathName(temp_name, long_temp_name, MAX_PATH);
+  if (long_name_len > MAX_PATH || long_name_len == 0) {
+    // GetLongPathName() failed, but we still have a temporary file.
+    *temp_file = FilePath(temp_name);
+    return true;
+  }
+
+  FilePath::StringType long_temp_name_str;
+  long_temp_name_str.assign(long_temp_name, long_name_len);
+  *temp_file = FilePath(long_temp_name_str);
+  return true;
+}
+
+bool CreateTemporaryDirInDir(const FilePath& base_dir,
+                             const FilePath::StringType& prefix,
+                             FilePath* new_dir) {
+  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/src/base/file_version_info.h b/src/base/file_version_info.h
new file mode 100644
index 0000000..84eec41
--- /dev/null
+++ b/src/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/src/base/file_version_info_mac.h b/src/base/file_version_info_mac.h
new file mode 100644
index 0000000..0ab3296
--- /dev/null
+++ b/src/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/src/base/file_version_info_mac.mm b/src/base/file_version_info_mac.mm
new file mode 100644
index 0000000..3a6df81
--- /dev/null
+++ b/src/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/src/base/file_version_info_unittest.cc b/src/base/file_version_info_unittest.cc
new file mode 100644
index 0000000..916e7bc
--- /dev/null
+++ b/src/base/file_version_info_unittest.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/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 {
+
+#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/src/base/file_version_info_win.cc b/src/base/file_version_info_win.cc
new file mode 100644
index 0000000..6528ca3
--- /dev/null
+++ b/src/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/src/base/file_version_info_win.h b/src/base/file_version_info_win.h
new file mode 100644
index 0000000..a378577
--- /dev/null
+++ b/src/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/src/base/files/dir_reader_dirent.h b/src/base/files/dir_reader_dirent.h
new file mode 100644
index 0000000..c2d88d5
--- /dev/null
+++ b/src/base/files/dir_reader_dirent.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Follows the interface defined in dir_reader_posix.h/dir_reader_fallback.h
+// but isn't directly included as the memory usage of this object may be higher
+// than that offered by the dir_reader_linux implementation. Therefore the
+// programmer must ask for this DirReaderDirent implementation by name. Also
+// we add a few methods to this object to make file enumeration more convenient.
+
+#ifndef BASE_DIR_READER_DIRENT_H_
+#define BASE_DIR_READER_DIRENT_H_
+#pragma once
+
+#include <dirent.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+class DirReaderDirent {
+ public:
+  explicit DirReaderDirent(const char* directory_path)
+      : current_(NULL) {
+    dir_ = opendir(directory_path);
+  }
+
+  ~DirReaderDirent() {
+    if (dir_) {
+      closedir(dir_);
+    }
+  }
+
+  bool IsValid() const {
+    return dir_ != NULL;
+  }
+
+  bool Next() {
+    if (!IsValid()) return false;
+    current_ = readdir(dir_);
+    return current_ != NULL;
+  }
+
+  const char* name() const {
+    if (!IsValid()) return NULL;
+    if (!current_) return NULL;
+    return current_->d_name;
+  }
+
+#if !defined(__LB_SHELL__)
+  // reading the linux implementation this is clear it is a call for the
+  // opened directory fd
+  int fd() const {
+    if (!IsValid()) return -1;
+    return dir_->fd;
+  }
+#endif
+
+  static bool IsFallback() {
+    return false;
+  }
+
+  //**************** extra convenience methods
+
+  // returns true if the current enumerated object is a file
+  bool IsFile() const {
+    if (!IsValid()) return false;
+    if (!current_) return false;
+    return (current_->d_type == DT_REG);
+  }
+
+ private:
+  DIR* dir_;
+  dirent* current_;
+};
+
+}
+#endif  // BASE_DIR_READER_DIRENT_H_
diff --git a/src/base/files/dir_reader_fallback.h b/src/base/files/dir_reader_fallback.h
new file mode 100644
index 0000000..a435f25
--- /dev/null
+++ b/src/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/src/base/files/dir_reader_linux.h b/src/base/files/dir_reader_linux.h
new file mode 100644
index 0000000..fda955f
--- /dev/null
+++ b/src/base/files/dir_reader_linux.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_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 <dirent.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+// See the comments in dir_reader_posix.h about this.
+
+namespace base {
+
+struct linux_dirent {
+  uint64_t        d_ino;
+  int64_t         d_off;
+  unsigned short  d_reclen;
+  unsigned char   d_type;
+  char            d_name[0];
+};
+
+class DirReaderLinux {
+ public:
+  explicit DirReaderLinux(const char* directory_path)
+      : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)),
+        offset_(0),
+        size_(0) {
+    memset(buf_, 0, sizeof(buf_));
+  }
+
+  ~DirReaderLinux() {
+    if (fd_ >= 0) {
+      if (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;
+  }
+
+  //**************** extra convenience methods
+
+  // returns true if the current enumerated object is a file
+  bool IsFile() const {
+    if (!IsValid()) return false;
+    const linux_dirent* dirent =
+        reinterpret_cast<const linux_dirent*>(&buf_[offset_]);
+    return (dirent->d_type == DT_REG);
+  }
+
+ 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/src/base/files/dir_reader_posix.h b/src/base/files/dir_reader_posix.h
new file mode 100644
index 0000000..6a20ced
--- /dev/null
+++ b/src/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/src/base/files/dir_reader_posix_unittest.cc b/src/base/files/dir_reader_posix_unittest.cc
new file mode 100644
index 0000000..0685031
--- /dev/null
+++ b/src/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/src/base/files/file_path_watcher.cc b/src/base/files/file_path_watcher.cc
new file mode 100644
index 0000000..bc8db37
--- /dev/null
+++ b/src/base/files/file_path_watcher.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.
+
+// 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, false, delegate);
+}
+
+FilePathWatcher::PlatformDelegate::PlatformDelegate(): cancelled_(false) {
+}
+
+FilePathWatcher::PlatformDelegate::~PlatformDelegate() {
+  DCHECK(is_cancelled());
+}
+
+bool FilePathWatcher::Watch(const FilePath& path,
+                            bool recursive,
+                            const Callback& callback) {
+  DCHECK(path.IsAbsolute());
+  return impl_->Watch(path, recursive, new FilePathWatcherDelegate(callback));
+}
+
+}  // namespace files
+}  // namespace base
diff --git a/src/base/files/file_path_watcher.h b/src/base/files/file_path_watcher.h
new file mode 100644
index 0000000..94a3f9a
--- /dev/null
+++ b/src/base/files/file_path_watcher.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// 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,
+                       bool recursive,
+                       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. Set |recursive| to
+  // true, to watch |path| and its children. The callback will be invoked on
+  // the same loop. Returns true on success.
+  //
+  // NOTE: Recursive watch is not supported on all platforms and file systems.
+  // Watch() will return false in the case of failure.
+  bool Watch(const FilePath& path, bool recursive, const Callback& callback);
+
+ private:
+  scoped_refptr<PlatformDelegate> impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcher);
+};
+
+}  // namespace files
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PATH_WATCHER_H_
diff --git a/src/base/files/file_path_watcher_browsertest.cc b/src/base/files/file_path_watcher_browsertest.cc
new file mode 100644
index 0000000..9a7c6c4
--- /dev/null
+++ b/src/base/files/file_path_watcher_browsertest.cc
@@ -0,0 +1,916 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path_watcher.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <aclapi.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#endif
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.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,
+                               base::Unretained(delegate)));
+  }
+
+  void Register(TestDelegate* delegate) {
+    delegates_.insert(delegate);
+  }
+
+  void Reset() {
+    signaled_.clear();
+  }
+
+  bool Success() {
+    return signaled_ == delegates_;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<NotificationCollector>;
+  ~NotificationCollector() {}
+
+  void RecordChange(TestDelegate* delegate) {
+    // Warning: |delegate| is Unretained. Do not dereference.
+    ASSERT_TRUE(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_;
+};
+
+class TestDelegateBase : public SupportsWeakPtr<TestDelegateBase> {
+ public:
+  TestDelegateBase() {}
+  virtual ~TestDelegateBase() {}
+
+  virtual void OnFileChanged(const FilePath& path, bool error) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
+};
+
+// A mock class for testing. Gmock is not appropriate because it is not
+// thread-safe for setting expectations. Thus the test code cannot safely
+// reset expectations while the file watcher is running.
+// Instead, TestDelegate gets the notifications from FilePathWatcher and uses
+// NotificationCollector to aggregate the results.
+class TestDelegate : public TestDelegateBase {
+ public:
+  explicit TestDelegate(NotificationCollector* collector)
+      : collector_(collector) {
+    collector_->Register(this);
+  }
+  ~TestDelegate() {}
+
+  virtual void OnFileChanged(const FilePath& path, bool error) OVERRIDE {
+    if (error)
+      ADD_FAILURE() << "Error " << path.value();
+    else
+      collector_->OnChange(this);
+  }
+
+ private:
+  scoped_refptr<NotificationCollector> collector_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+void SetupWatchCallback(const FilePath& target,
+                        FilePathWatcher* watcher,
+                        TestDelegateBase* delegate,
+                        bool recursive_watch,
+                        bool* result,
+                        base::WaitableEvent* completion) {
+  *result = watcher->Watch(target, recursive_watch,
+                           base::Bind(&TestDelegateBase::OnFileChanged,
+                                      delegate->AsWeakPtr()));
+  completion->Signal();
+}
+
+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();
+  }
+
+  void DeleteDelegateOnFileThread(TestDelegate* delegate) {
+    file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, delegate);
+  }
+
+  FilePath test_file() {
+    return temp_dir_.path().AppendASCII("FilePathWatcherTest");
+  }
+
+  FilePath test_link() {
+    return temp_dir_.path().AppendASCII("FilePathWatcherTest.lnk");
+  }
+
+  // Write |content| to |file|. Returns true on success.
+  bool WriteFile(const FilePath& file, const std::string& content) {
+    int write_size = file_util::WriteFile(file, content.c_str(),
+                                          content.length());
+    return write_size == static_cast<int>(content.length());
+  }
+
+  bool SetupWatch(const FilePath& target,
+                  FilePathWatcher* watcher,
+                  TestDelegateBase* delegate,
+                  bool recursive_watch) WARN_UNUSED_RESULT;
+
+  bool WaitForEvents() WARN_UNUSED_RESULT {
+    collector_->Reset();
+    loop_.Run();
+    return collector_->Success();
+  }
+
+  NotificationCollector* collector() { return collector_.get(); }
+
+  MessageLoop loop_;
+  base::Thread file_thread_;
+  ScopedTempDir temp_dir_;
+  scoped_refptr<NotificationCollector> collector_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherTest);
+};
+
+bool FilePathWatcherTest::SetupWatch(const FilePath& target,
+                                     FilePathWatcher* watcher,
+                                     TestDelegateBase* delegate,
+                                     bool recursive_watch) {
+  base::WaitableEvent completion(false, false);
+  bool result;
+  file_thread_.message_loop_proxy()->PostTask(
+      FROM_HERE,
+      base::Bind(SetupWatchCallback,
+                 target, watcher, delegate, recursive_watch, &result,
+                 &completion));
+  completion.Wait();
+  return result;
+}
+
+// Basic test: Create the file and verify that we notice.
+TEST_F(FilePathWatcherTest, NewFile) {
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that modifying the file is caught.
+TEST_F(FilePathWatcherTest, ModifiedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(WriteFile(test_file(), "new content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that moving the file into place is caught.
+TEST_F(FilePathWatcherTest, MovedFile) {
+  FilePath source_file(temp_dir_.path().AppendASCII("source"));
+  ASSERT_TRUE(WriteFile(source_file, "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(file_util::Move(source_file, test_file()));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, DeletedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is deleted.
+  file_util::Delete(test_file(), false);
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Used by the DeleteDuringNotify test below.
+// Deletes the FilePathWatcher when it's notified.
+class Deleter : public TestDelegateBase {
+ public:
+  Deleter(FilePathWatcher* watcher, MessageLoop* loop)
+      : watcher_(watcher),
+        loop_(loop) {
+  }
+  ~Deleter() {}
+
+  virtual void OnFileChanged(const FilePath&, bool) OVERRIDE {
+    watcher_.reset();
+    loop_->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+  }
+
+  FilePathWatcher* watcher() const { return watcher_.get(); }
+
+ private:
+  scoped_ptr<FilePathWatcher> watcher_;
+  MessageLoop* loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(Deleter);
+};
+
+// Verify that deleting a watcher during the callback doesn't crash.
+TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
+  FilePathWatcher* watcher = new FilePathWatcher;
+  // Takes ownership of watcher.
+  scoped_ptr<Deleter> deleter(new Deleter(watcher, &loop_));
+  ASSERT_TRUE(SetupWatch(test_file(), watcher, deleter.get(), false));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // We win if we haven't crashed yet.
+  // Might as well double-check it got deleted, too.
+  ASSERT_TRUE(deleter->watcher() == NULL);
+}
+
+// Verify that deleting the watcher works even if there is a pending
+// notification.
+// Flaky on MacOS. 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_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  FilePathWatcher* watcher = new FilePathWatcher;
+  ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get(), false));
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher);
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, MultipleWatchersSingleFile) {
+  FilePathWatcher watcher1, watcher2;
+  scoped_ptr<TestDelegate> delegate1(new TestDelegate(collector()));
+  scoped_ptr<TestDelegate> delegate2(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get(), false));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get(), false));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate1.release());
+  DeleteDelegateOnFileThread(delegate2.release());
+}
+
+// Verify that watching a file whose parent directory doesn't exist yet works if
+// the directory and file are created eventually.
+TEST_F(FilePathWatcherTest, NonExistentDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file(dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(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());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Exercises watch reconfiguration for the case that directories on the path
+// are rapidly created.
+TEST_F(FilePathWatcherTest, DirectoryChain) {
+  FilePath path(temp_dir_.path());
+  std::vector<std::string> dir_names;
+  for (int i = 0; i < 20; i++) {
+    std::string dir(base::StringPrintf("d%d", i));
+    dir_names.push_back(dir);
+    path = path.AppendASCII(dir);
+  }
+
+  FilePathWatcher watcher;
+  FilePath file(path.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
+
+  FilePath sub_path(temp_dir_.path());
+  for (std::vector<std::string>::const_iterator d(dir_names.begin());
+       d != dir_names.end(); ++d) {
+    sub_path = sub_path.AppendASCII(*d);
+    ASSERT_TRUE(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());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#if defined(OS_MACOSX)
+// http://crbug.com/85930
+#define DisappearingDirectory DISABLED_DisappearingDirectory
+#endif
+TEST_F(FilePathWatcherTest, DisappearingDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file(dir.AppendASCII("file"));
+  ASSERT_TRUE(file_util::CreateDirectory(dir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(file_util::Delete(dir, true));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Tests that a file that is deleted and reappears is tracked correctly.
+TEST_F(FilePathWatcherTest, DeleteAndRecreate) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(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());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, WatchDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file1(dir.AppendASCII("file1"));
+  FilePath file2(dir.AppendASCII("file2"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(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());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, MoveParent) {
+  FilePathWatcher file_watcher;
+  FilePathWatcher subdir_watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath dest(temp_dir_.path().AppendASCII("dest"));
+  FilePath subdir(dir.AppendASCII("subdir"));
+  FilePath file(subdir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &file_watcher, file_delegate.get(), false));
+  scoped_ptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(subdir, &subdir_watcher, subdir_delegate.get(),
+                         false));
+
+  // Setup a directory hierarchy.
+  ASSERT_TRUE(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());
+  DeleteDelegateOnFileThread(file_delegate.release());
+  DeleteDelegateOnFileThread(subdir_delegate.release());
+}
+
+#if defined(OS_WIN)
+TEST_F(FilePathWatcherTest, RecursiveWatch) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get(), true));
+
+  // Main directory("dir") creation.
+  ASSERT_TRUE(file_util::CreateDirectory(dir));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/file1".
+  FilePath file1(dir.AppendASCII("file1"));
+  ASSERT_TRUE(WriteFile(file1, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir".
+  FilePath subdir(dir.AppendASCII("subdir"));
+  ASSERT_TRUE(file_util::CreateDirectory(subdir));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir/subdir_file1".
+  FilePath subdir_file1(subdir.AppendASCII("subdir_file1"));
+  ASSERT_TRUE(WriteFile(subdir_file1, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir/subdir_child_dir".
+  FilePath subdir_child_dir(subdir.AppendASCII("subdir_child_dir"));
+  ASSERT_TRUE(file_util::CreateDirectory(subdir_child_dir));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir/subdir_child_dir/child_dir_file1".
+  FilePath child_dir_file1(subdir_child_dir.AppendASCII("child_dir_file1"));
+  ASSERT_TRUE(WriteFile(child_dir_file1, "content v2"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Write into "$dir/subdir/subdir_child_dir/child_dir_file1".
+  ASSERT_TRUE(WriteFile(child_dir_file1, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Modify "$dir/subdir/subdir_child_dir/child_dir_file1" attributes.
+  ASSERT_TRUE(file_util::MakeFileUnreadable(child_dir_file1));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Delete "$dir/subdir/subdir_file1".
+  ASSERT_TRUE(file_util::Delete(subdir_file1, false));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Delete "$dir/subdir/subdir_child_dir/child_dir_file1".
+  ASSERT_TRUE(file_util::Delete(child_dir_file1, false));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+#else
+TEST_F(FilePathWatcherTest, RecursiveWatch) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Non-Windows implementaion does not support recursive watching.
+  ASSERT_FALSE(SetupWatch(dir, &watcher, delegate.get(), true));
+  DeleteDelegateOnFileThread(delegate.release());
+}
+#endif
+
+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_ptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get(), false));
+  scoped_ptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get(),
+                         false));
+
+  // Move the directory into place, s.t. the watched file appears.
+  ASSERT_TRUE(file_util::Move(source_dir, dest_dir));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(file_delegate.release());
+  DeleteDelegateOnFileThread(subdir_delegate.release());
+}
+
+#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_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(file_util::MakeFileUnreadable(test_file()));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#endif  // !OS_LINUX
+
+#if defined(OS_LINUX)
+
+// Verify that creating a symlink is caught.
+TEST_F(FilePathWatcherTest, CreateLink) {
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the link is created.
+  // Note that test_file() doesn't have to exist.
+  ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that deleting a symlink is caught.
+TEST_F(FilePathWatcherTest, DeleteLink) {
+  // Unfortunately this test case only works if the link target exists.
+  // TODO(craig) fix this as part of crbug.com/91561.
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the link is deleted.
+  ASSERT_TRUE(file_util::Delete(test_link(), false));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that modifying a target file that a link is pointing to
+// when we are watching the link is caught.
+TEST_F(FilePathWatcherTest, ModifiedLinkedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(WriteFile(test_file(), "new content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that creating a target file that a link is pointing to
+// when we are watching the link is caught.
+TEST_F(FilePathWatcherTest, CreateTargetLinkedFile) {
+  ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the target file is created.
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that deleting a target file that a link is pointing to
+// when we are watching the link is caught.
+TEST_F(FilePathWatcherTest, DeleteTargetLinkedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the target file is deleted.
+  ASSERT_TRUE(file_util::Delete(test_file(), false));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that watching a file whose parent directory is a link that
+// doesn't exist yet works if the symlink is created eventually.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart1) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // dir/file should exist.
+  ASSERT_TRUE(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(), false));
+
+  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());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that watching a file whose parent directory is a
+// dangling symlink works if the directory is created eventually.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart2) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Now create the link from dir.lnk pointing to dir but
+  // neither dir nor dir/file exist yet.
+  ASSERT_TRUE(file_util::CreateSymbolicLink(dir, link_dir));
+  // Note that we are watching dir.lnk/file.
+  ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false));
+
+  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());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that watching a file with a symlink on the path
+// to the file works.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart3) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(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(), false));
+
+  ASSERT_TRUE(WriteFile(file, "content"));
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file change";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(file_util::Delete(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#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_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file, &watcher, delegate.get(), false));
+
+  // We should not get notified in this case as it hasn't affected our ability
+  // to access the file.
+  ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, false));
+  loop_.PostDelayedTask(FROM_HERE,
+                        MessageLoop::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));
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#endif  // OS_MACOSX
+}  // namespace
+
+}  // namespace files
+}  // namespace base
diff --git a/src/base/files/file_path_watcher_kqueue.cc b/src/base/files/file_path_watcher_kqueue.cc
new file mode 100644
index 0000000..aebe15a
--- /dev/null
+++ b/src/base/files/file_path_watcher_kqueue.cc
@@ -0,0 +1,513 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/logging.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,
+                     bool recursive,
+                     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,
+                                bool recursive,
+                                FilePathWatcher::Delegate* delegate) {
+  DCHECK(MessageLoopForIO::current());
+  DCHECK(target_.value().empty());  // Can only watch one path.
+  DCHECK(delegate);
+  DCHECK_EQ(kqueue_, -1);
+
+  if (recursive) {
+    // Recursive watch is not supported on this platform.
+    NOTIMPLEMENTED();
+    return false;
+  }
+
+  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/src/base/files/file_path_watcher_linux.cc b/src/base/files/file_path_watcher_linux.cc
new file mode 100644
index 0000000..9e55022
--- /dev/null
+++ b/src/base/files/file_path_watcher_linux.cc
@@ -0,0 +1,490 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/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/posix/eintr_wrapper.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,
+                     bool recursive,
+                     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,
+                                bool recursive,
+                                FilePathWatcher::Delegate* delegate) {
+  DCHECK(target_.empty());
+  DCHECK(MessageLoopForIO::current());
+  if (recursive) {
+    // Recursive watch is not supported on this platform.
+    NOTIMPLEMENTED();
+    return false;
+  }
+
+  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/src/base/files/file_path_watcher_stub.cc b/src/base/files/file_path_watcher_stub.cc
new file mode 100644
index 0000000..0c25d7f
--- /dev/null
+++ b/src/base/files/file_path_watcher_stub.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.
+
+// 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,
+                     bool recursive,
+                     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/src/base/files/file_path_watcher_win.cc b/src/base/files/file_path_watcher_win.cc
new file mode 100644
index 0000000..c25260c
--- /dev/null
+++ b/src/base/files/file_path_watcher_win.cc
@@ -0,0 +1,295 @@
+// Copyright (c) 2011 The Chromium Authors. All 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),
+        recursive_watch_(false) {}
+
+  // FilePathWatcher::PlatformDelegate overrides.
+  virtual bool Watch(const FilePath& path,
+                     bool recursive,
+                     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|. Set |recursive| to true to watch
+  // the directory sub trees. Returns true if no fatal error occurs. |handle|
+  // will receive the handle value if |dir| is watchable, otherwise
+  // INVALID_HANDLE_VALUE.
+  static bool SetupWatchHandle(const FilePath& dir,
+                               bool recursive,
+                               HANDLE* handle) WARN_UNUSED_RESULT;
+
+  // (Re-)Initialize the watch handle.
+  bool UpdateWatch() WARN_UNUSED_RESULT;
+
+  // Destroy the watch handle.
+  void DestroyWatch();
+
+  // Cleans up and stops observing the |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_;
+
+  // Set to true to watch the sub trees of the specified directory file path.
+  bool recursive_watch_;
+
+  // Keep track of the last modified time of the file.  We use nulltime
+  // to represent the file not existing.
+  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,
+                                bool recursive,
+                                FilePathWatcher::Delegate* delegate) {
+  DCHECK(target_.value().empty());  // Can only watch one path.
+
+  set_message_loop(base::MessageLoopProxy::current());
+  delegate_ = delegate;
+  target_ = path;
+  recursive_watch_ = recursive;
+  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,
+                                           bool recursive,
+                                           HANDLE* handle) {
+  *handle = FindFirstChangeNotification(
+      dir.value().c_str(),
+      recursive,
+      FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
+      FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
+      FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
+  if (*handle != INVALID_HANDLE_VALUE) {
+    // Make sure the handle we got points to an existing directory. It seems
+    // that windows sometimes hands out watches to directories that are
+    // about to go away, but doesn't sent notifications if that happens.
+    if (!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, recursive_watch_, &handle_))
+      return false;
+
+    // Break if a valid handle is returned. Try the parent directory otherwise.
+    if (handle_ != INVALID_HANDLE_VALUE)
+      break;
+
+    // Abort if we hit the root directory.
+    child_dirs.push_back(watched_path.BaseName());
+    FilePath parent(watched_path.DirName());
+    if (parent == watched_path) {
+      DLOG(ERROR) << "Reached the root directory";
+      return false;
+    }
+    watched_path = parent;
+  }
+
+  // At this point, handle_ is valid. However, the bottom-up search that the
+  // above code performs races against directory creation. So try to walk back
+  // down and see whether any children appeared in the mean time.
+  while (!child_dirs.empty()) {
+    watched_path = watched_path.Append(child_dirs.back());
+    child_dirs.pop_back();
+    HANDLE temp_handle = INVALID_HANDLE_VALUE;
+    if (!SetupWatchHandle(watched_path, recursive_watch_, &temp_handle))
+      return false;
+    if (temp_handle == INVALID_HANDLE_VALUE)
+      break;
+    FindCloseChangeNotification(handle_);
+    handle_ = temp_handle;
+  }
+
+  return true;
+}
+
+void FilePathWatcherImpl::DestroyWatch() {
+  watcher_.StopWatching();
+  FindCloseChangeNotification(handle_);
+  handle_ = INVALID_HANDLE_VALUE;
+}
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace files
+}  // namespace base
diff --git a/src/base/files/important_file_writer.cc b/src/base/files/important_file_writer.cc
new file mode 100644
index 0000000..351adc2
--- /dev/null
+++ b/src/base/files/important_file_writer.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/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;
+}
+
+}  // namespace
+
+// static
+bool ImportantFileWriter::WriteFileAtomically(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 false;
+  }
+
+  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 false;
+  }
+
+  // If this happens in the wild something really bad is going on.
+  CHECK_LE(data.length(), static_cast<size_t>(kint32max));
+  int bytes_written = 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 false;
+  }
+
+  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 false;
+  }
+
+  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 false;
+  }
+
+  return true;
+}
+
+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(IgnoreResult(&ImportantFileWriter::WriteFileAtomically),
+                   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();
+
+    WriteFileAtomically(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/src/base/files/important_file_writer.h b/src/base/files/important_file_writer.h
new file mode 100644
index 0000000..9bc8f07
--- /dev/null
+++ b/src/base/files/important_file_writer.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_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() {}
+  };
+
+  // Save |data| to |path| in an atomic manner (see the class comment above).
+  // Blocks and writes data on the current thread.
+  static bool WriteFileAtomically(const FilePath& path,
+                                  const std::string& data);
+
+  // Initialize the writer.
+  // |path| is the name of file to write.
+  // |task_runner| is the SequencedTaskRunner instance where on which we will
+  // execute file I/O operations.
+  // All non-const methods, ctor and dtor must be called on the same thread.
+  ImportantFileWriter(const FilePath& path,
+                      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/src/base/files/important_file_writer_unittest.cc b/src/base/files/important_file_writer_unittest.cc
new file mode 100644
index 0000000..3bd3016
--- /dev/null
+++ b/src/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/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/message_loop.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/src/base/files/scoped_temp_dir.cc b/src/base/files/scoped_temp_dir.cc
new file mode 100644
index 0000000..509f808
--- /dev/null
+++ b/src/base/files/scoped_temp_dir.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/scoped_temp_dir.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+
+namespace base {
+
+ScopedTempDir::ScopedTempDir() {
+}
+
+ScopedTempDir::~ScopedTempDir() {
+  if (!path_.empty() && !Delete())
+    DLOG(WARNING) << "Could not delete temp dir in dtor.";
+}
+
+bool ScopedTempDir::CreateUniqueTempDir() {
+  if (!path_.empty())
+    return false;
+
+  // This "scoped_dir" prefix is only used on Windows and serves as a template
+  // for the unique name.
+  if (!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_);
+}
+
+}  // namespace base
diff --git a/src/base/files/scoped_temp_dir.h b/src/base/files/scoped_temp_dir.h
new file mode 100644
index 0000000..641e7ef
--- /dev/null
+++ b/src/base/files/scoped_temp_dir.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_SCOPED_TEMP_DIR_H_
+#define BASE_FILES_SCOPED_TEMP_DIR_H_
+
+// An object representing a temporary / scratch directory that should be cleaned
+// up (recursively) when this object goes out of scope.  Note that since
+// deletion occurs during the destructor, no further error handling is possible
+// if the directory fails to be deleted.  As a result, deletion is not
+// guaranteed by this class.
+//
+// Multiple calls to the methods which establish a temporary directory
+// (CreateUniqueTempDir, CreateUniqueTempDirUnderPath, and Set) must have
+// intervening calls to Delete or Take, or the calls will fail.
+
+#include "base/base_export.h"
+#include "base/file_path.h"
+
+namespace base {
+
+class BASE_EXPORT ScopedTempDir {
+ public:
+  // No directory is owned/created initially.
+  ScopedTempDir();
+
+  // Recursively delete path.
+  ~ScopedTempDir();
+
+  // Creates a unique directory in TempPath, and takes ownership of it.
+  // See file_util::CreateNewTemporaryDirectory.
+  bool CreateUniqueTempDir() WARN_UNUSED_RESULT;
+
+  // Creates a unique directory under a given path, and takes ownership of it.
+  bool CreateUniqueTempDirUnderPath(const FilePath& path) WARN_UNUSED_RESULT;
+
+  // Takes ownership of directory at |path|, creating it if necessary.
+  // Don't call multiple times unless Take() has been called first.
+  bool Set(const FilePath& path) WARN_UNUSED_RESULT;
+
+  // Deletes the temporary directory wrapped by this object.
+  bool Delete() WARN_UNUSED_RESULT;
+
+  // Caller takes ownership of the temporary directory so it won't be destroyed
+  // when this object goes out of scope.
+  FilePath Take();
+
+  const FilePath& path() const { return path_; }
+
+  // Returns true if path_ is non-empty and exists.
+  bool IsValid() const;
+
+ private:
+  FilePath path_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTempDir);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_SCOPED_TEMP_DIR_H_
diff --git a/src/base/files/scoped_temp_dir_unittest.cc b/src/base/files/scoped_temp_dir_unittest.cc
new file mode 100644
index 0000000..8497ac6
--- /dev/null
+++ b/src/base/files/scoped_temp_dir_unittest.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2011 The Chromium Authors. 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/files/scoped_temp_dir.h"
+#include "base/platform_file.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+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)
+
+}  // namespace base
diff --git a/src/base/float_util.h b/src/base/float_util.h
new file mode 100644
index 0000000..e2fa484
--- /dev/null
+++ b/src/base/float_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_FLOAT_UTIL_H_
+#define BASE_FLOAT_UTIL_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_STARBOARD)
+#include "starboard/double.h"
+#else
+#include <float.h>
+#include <math.h>
+#include <cmath>
+#endif
+
+namespace base {
+
+inline bool IsFinite(const double& number) {
+#if defined(OS_STARBOARD)
+  return SbDoubleIsFinite(number);
+#elif defined(__LB_SHELL__) && defined(__LB_LINUX__)
+  // On Linux, math.h defines fpclassify() as a macro which is undefined in
+  // cmath.  However, as math.h has guard to avoid being included again, the
+  // fpclassify() macro is no longer available if cmath is included after
+  // math.h, even if math.h is included again.  So we have to use
+  // std::fpclassify() on Linux.
+  return std::fpclassify(number) != FP_INFINITE;
+#elif defined(__LB_SHELL__)
+  return fpclassify(number) != FP_INFINITE;
+#elif 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/src/base/format_macros.h b/src/base/format_macros.h
new file mode 100644
index 0000000..a073b83
--- /dev/null
+++ b/src/base/format_macros.h
@@ -0,0 +1,77 @@
+// 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_STARBOARD)
+#include "starboard/types.h"
+#endif
+
+#if (defined(OS_POSIX) || defined(OS_STARBOARD)) && !defined(COMPILER_MSVC)
+
+#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 || __LB_XB1__ || __LB_XB360__
+
+#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/src/base/gmock_unittest.cc b/src/base/gmock_unittest.cc
new file mode 100644
index 0000000..855380a
--- /dev/null
+++ b/src/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/src/base/gtest_prod_util.h b/src/base/gtest_prod_util.h
new file mode 100644
index 0000000..3289e63
--- /dev/null
+++ b/src/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/src/base/guid.cc b/src/base/guid.cc
new file mode 100644
index 0000000..920dae5
--- /dev/null
+++ b/src/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/src/base/guid.h b/src/base/guid.h
new file mode 100644
index 0000000..e730f4c
--- /dev/null
+++ b/src/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) || defined(OS_STARBOARD)
+// 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/src/base/guid_posix.cc b/src/base/guid_posix.cc
new file mode 100644
index 0000000..89811d0
--- /dev/null
+++ b/src/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/src/base/guid_shell.cc b/src/base/guid_shell.cc
new file mode 100644
index 0000000..8336580
--- /dev/null
+++ b/src/base/guid_shell.cc
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "guid_posix.cc"
diff --git a/src/base/guid_starboard.cc b/src/base/guid_starboard.cc
new file mode 100644
index 0000000..f050ba0
--- /dev/null
+++ b/src/base/guid_starboard.cc
@@ -0,0 +1,15 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "guid_posix.cc"
diff --git a/src/base/guid_unittest.cc b/src/base/guid_unittest.cc
new file mode 100644
index 0000000..18c04a9
--- /dev/null
+++ b/src/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/src/base/guid_win.cc b/src/base/guid_win.cc
new file mode 100644
index 0000000..1cddff8
--- /dev/null
+++ b/src/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/src/base/hash.cc b/src/base/hash.cc
new file mode 100644
index 0000000..411e186
--- /dev/null
+++ b/src/base/hash.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2010, Paul Hsieh
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither my name, Paul Hsieh, nor the names of any other contributors to the
+//   code use may not be used to endorse or promote products derived from this
+//   software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+// 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/src/base/hash.h b/src/base/hash.h
new file mode 100644
index 0000000..cf8ea3a
--- /dev/null
+++ b/src/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/src/base/hash_tables.h b/src/base/hash_tables.h
new file mode 100644
index 0000000..b6f40be
--- /dev/null
+++ b/src/base/hash_tables.h
@@ -0,0 +1,162 @@
+// Copyright (c) 2011 The Chromium 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 <string>
+
+#include "build/build_config.h"
+
+#include "base/string16.h"
+
+#if defined(OS_STARBOARD)
+#include "starboard/configuration.h"
+#define BASE_HASH_DEFINE_LONG_LONG_HASHES !SB_HAS(LONG_LONG_HASH)
+#define BASE_HASH_DEFINE_STRING_HASHES !SB_HAS(STRING_HASH)
+#define BASE_HASH_USE_HASH !SB_HAS(HASH_USING)
+#define BASE_HASH_MAP_INCLUDE SB_HASH_MAP_INCLUDE
+#define BASE_HASH_NAMESPACE SB_HASH_NAMESPACE
+#define BASE_HASH_SET_INCLUDE SB_HASH_SET_INCLUDE
+#if !SB_HAS(HASH_VALUE)
+#define BASE_HASH_USE_HASH_STRUCT
+#endif
+#elif defined(COMPILER_MSVC)
+#define BASE_HASH_DEFINE_LONG_LONG_HASHES 0
+#define BASE_HASH_DEFINE_STRING_HASHES 0
+#define BASE_HASH_USE_HASH 0
+#define BASE_HASH_MAP_INCLUDE <hash_map>
+#define BASE_HASH_NAMESPACE stdext
+#define BASE_HASH_SET_INCLUDE <hash_set>
+#elif defined(COMPILER_GCC)
+#if defined(OS_ANDROID) || (defined(__LB_SHELL__) && !defined(__LB_LINUX__))
+#define BASE_HASH_DEFINE_LONG_LONG_HASHES 0
+#define BASE_HASH_DEFINE_STRING_HASHES !defined(__LB_SHELL__)
+#define BASE_HASH_MAP_INCLUDE <hash_map>
+#define BASE_HASH_NAMESPACE std
+#define BASE_HASH_SET_INCLUDE <hash_set>
+#else
+#define BASE_HASH_DEFINE_LONG_LONG_HASHES 1
+#define BASE_HASH_DEFINE_STRING_HASHES 1
+#define BASE_HASH_MAP_INCLUDE <ext/hash_map>
+#define BASE_HASH_NAMESPACE __gnu_cxx
+#define BASE_HASH_SET_INCLUDE <ext/hash_set>
+#define BASE_HASH_USE_HASH_STRUCT
+#endif
+#if defined(__LB_LINUX__)
+#define BASE_HASH_USE_HASH 1
+#else
+#define BASE_HASH_USE_HASH 0
+#endif
+#else  // COMPILER
+#error define BASE_HASH_NAMESPACE for your compiler
+#endif  // COMPILER
+
+// This is a hack to disable the gcc 4.4 warning about hash_map and hash_set
+// being deprecated.  We can get rid of this when we upgrade to VS2008 and we
+// can use <tr1/unordered_map> and <tr1/unordered_set>.
+#ifdef __DEPRECATED
+#define CHROME_OLD__DEPRECATED __DEPRECATED
+#undef __DEPRECATED
+#endif
+
+#include BASE_HASH_MAP_INCLUDE
+#include BASE_HASH_SET_INCLUDE
+
+#ifdef CHROME_OLD__DEPRECATED
+#define __DEPRECATED CHROME_OLD__DEPRECATED
+#undef CHROME_OLD__DEPRECATED
+#endif
+
+#if BASE_HASH_DEFINE_LONG_LONG_HASHES
+// 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); \
+      } \
+    }
+
+namespace BASE_HASH_NAMESPACE {
+DEFINE_TRIVIAL_HASH(long long);
+DEFINE_TRIVIAL_HASH(unsigned long long);
+
+template <typename T>
+struct hash<T*> {
+  std::size_t operator()(T* value) const {
+    return BASE_HASH_NAMESPACE::hash<uintptr_t>()(
+        reinterpret_cast<uintptr_t>(value));
+  }
+};
+}  // namespace BASE_HASH_NAMESPACE
+
+#undef DEFINE_TRIVIAL_HASH
+#endif  // BASE_HASH_DEFINE_LONG_LONG_HASHES
+
+
+#if BASE_HASH_DEFINE_STRING_HASHES
+// 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; \
+      } \
+    }
+
+namespace BASE_HASH_NAMESPACE {
+DEFINE_STRING_HASH(std::string);
+DEFINE_STRING_HASH(string16);
+}  // namespace BASE_HASH_NAMESPACE
+
+#undef DEFINE_STRING_HASH
+#endif  // BASE_HASH_DEFINE_STRING_HASHES
+
+
+namespace base {
+#if BASE_HASH_USE_HASH
+using BASE_HASH_NAMESPACE::hash;
+#endif
+using BASE_HASH_NAMESPACE::hash_map;
+using BASE_HASH_NAMESPACE::hash_multimap;
+using BASE_HASH_NAMESPACE::hash_multiset;
+using BASE_HASH_NAMESPACE::hash_set;
+}
+
+#undef BASE_HASH_DEFINE_LONG_LONG_HASHES
+#undef BASE_HASH_DEFINE_STRING_HASHES
+#undef BASE_HASH_MAP_INCLUDE
+#undef BASE_HASH_SET_INCLUDE
+#undef BASE_HASH_USE_HASH
+
+#endif  // BASE_HASH_TABLES_H_
diff --git a/src/base/hi_res_timer_manager.h b/src/base/hi_res_timer_manager.h
new file mode 100644
index 0000000..1bd5538
--- /dev/null
+++ b/src/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/src/base/hi_res_timer_manager_posix.cc b/src/base/hi_res_timer_manager_posix.cc
new file mode 100644
index 0000000..7c16eb7
--- /dev/null
+++ b/src/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/src/base/hi_res_timer_manager_unittest.cc b/src/base/hi_res_timer_manager_unittest.cc
new file mode 100644
index 0000000..07651ce
--- /dev/null
+++ b/src/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/src/base/hi_res_timer_manager_win.cc b/src/base/hi_res_timer_manager_win.cc
new file mode 100644
index 0000000..1a92394
--- /dev/null
+++ b/src/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/src/base/i18n/base_i18n_export.h b/src/base/i18n/base_i18n_export.h
new file mode 100644
index 0000000..7ef4ee8
--- /dev/null
+++ b/src/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(_MSC_VER)
+
+#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/src/base/i18n/bidi_line_iterator.cc b/src/base/i18n/bidi_line_iterator.cc
new file mode 100644
index 0000000..6251185
--- /dev/null
+++ b/src/base/i18n/bidi_line_iterator.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/bidi_line_iterator.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace i18n {
+
+namespace {
+  UBiDiLevel GetParagraphLevelForDirection(TextDirection direction) {
+    switch (direction) {
+    case UNKNOWN_DIRECTION:
+      return UBIDI_DEFAULT_LTR;
+      break;
+    case RIGHT_TO_LEFT:
+      return 1;  // Highest RTL level.
+      break;
+    case LEFT_TO_RIGHT:
+      return 0;  // Highest LTR level.
+      break;
+    default:
+      NOTREACHED();
+      return 0;
+    }
+  }
+}  // namespace
+
+BiDiLineIterator::BiDiLineIterator() : bidi_(NULL) {
+}
+
+BiDiLineIterator::~BiDiLineIterator() {
+  if (bidi_) {
+    ubidi_close(bidi_);
+    bidi_ = NULL;
+  }
+}
+
+bool BiDiLineIterator::Open(const string16& text, TextDirection direction) {
+  DCHECK(!bidi_);
+  UErrorCode error = U_ZERO_ERROR;
+  bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
+  if (U_FAILURE(error))
+    return false;
+  ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()),
+    GetParagraphLevelForDirection(direction), NULL, &error);
+  return (U_SUCCESS(error) == TRUE);
+}
+
+int BiDiLineIterator::CountRuns() {
+  DCHECK(bidi_ != NULL);
+  UErrorCode error = U_ZERO_ERROR;
+  const int runs = ubidi_countRuns(bidi_, &error);
+  return U_SUCCESS(error) ? runs : 0;
+}
+
+UBiDiDirection BiDiLineIterator::GetVisualRun(int index,
+                                              int* start,
+                                              int* length) {
+  DCHECK(bidi_ != NULL);
+  return ubidi_getVisualRun(bidi_, index, start, length);
+}
+
+void BiDiLineIterator::GetLogicalRun(int start,
+                                     int* end,
+                                     UBiDiLevel* level) {
+  DCHECK(bidi_ != NULL);
+  ubidi_getLogicalRun(bidi_, start, end, level);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/src/base/i18n/bidi_line_iterator.h b/src/base/i18n/bidi_line_iterator.h
new file mode 100644
index 0000000..8e1217b
--- /dev/null
+++ b/src/base/i18n/bidi_line_iterator.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_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/i18n/rtl.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, TextDirection direction);
+
+  // Returns the number of visual runs in the text, or zero on error.
+  int CountRuns();
+
+  // Gets the logical offset, length, and direction of the specified visual run.
+  UBiDiDirection GetVisualRun(int index, int* start, int* length);
+
+  // Given a start position, figure out where the run ends (and the BiDiLevel).
+  void GetLogicalRun(int start, int* end, UBiDiLevel* level);
+
+ private:
+  UBiDi* bidi_;
+
+  DISALLOW_COPY_AND_ASSIGN(BiDiLineIterator);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_BIDI_LINE_ITERATOR_H_
diff --git a/src/base/i18n/break_iterator.cc b/src/base/i18n/break_iterator.cc
new file mode 100644
index 0000000..339de3d
--- /dev/null
+++ b/src/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: " << u_errorName(status);
+    return false;
+  }
+  // Move the iterator to the beginning of the string.
+  ubrk_first(static_cast<UBreakIterator*>(iter_));
+  return true;
+}
+
+bool BreakIterator::Advance() {
+  int32_t pos;
+  int32_t status;
+  prev_ = pos_;
+  switch (break_type_) {
+    case BREAK_CHARACTER:
+    case BREAK_WORD:
+    case BREAK_LINE:
+      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/src/base/i18n/break_iterator.h b/src/base/i18n/break_iterator.h
new file mode 100644
index 0000000..d558e23
--- /dev/null
+++ b/src/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/src/base/i18n/break_iterator_unittest.cc b/src/base/i18n/break_iterator_unittest.cc
new file mode 100644
index 0000000..afb780c
--- /dev/null
+++ b/src/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/src/base/i18n/case_conversion.cc b/src/base/i18n/case_conversion.cc
new file mode 100644
index 0000000..d3b06c9
--- /dev/null
+++ b/src/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/src/base/i18n/case_conversion.h b/src/base/i18n/case_conversion.h
new file mode 100644
index 0000000..14fef00
--- /dev/null
+++ b/src/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/src/base/i18n/case_conversion_unittest.cc b/src/base/i18n/case_conversion_unittest.cc
new file mode 100644
index 0000000..63900ec
--- /dev/null
+++ b/src/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/src/base/i18n/char_iterator.cc b/src/base/i18n/char_iterator.cc
new file mode 100644
index 0000000..ce4d513
--- /dev/null
+++ b/src/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/src/base/i18n/char_iterator.h b/src/base/i18n/char_iterator.h
new file mode 100644
index 0000000..431e350
--- /dev/null
+++ b/src/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/src/base/i18n/char_iterator_unittest.cc b/src/base/i18n/char_iterator_unittest.cc
new file mode 100644
index 0000000..6d1294e
--- /dev/null
+++ b/src/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/src/base/i18n/file_util_icu.cc b/src/base/i18n/file_util_icu.cc
new file mode 100644
index 0000000..fc07d13
--- /dev/null
+++ b/src/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) || defined(OS_STARBAORD)
+    // 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) || defined(OS_STARBOARD)
+  // 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/src/base/i18n/file_util_icu.h b/src/base/i18n/file_util_icu.h
new file mode 100644
index 0000000..4672135
--- /dev/null
+++ b/src/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/src/base/i18n/file_util_icu_unittest.cc b/src/base/i18n/file_util_icu_unittest.cc
new file mode 100644
index 0000000..dfc4943
--- /dev/null
+++ b/src/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/src/base/i18n/icu_encoding_detection.cc b/src/base/i18n/icu_encoding_detection.cc
new file mode 100644
index 0000000..2081c7a
--- /dev/null
+++ b/src/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/src/base/i18n/icu_encoding_detection.h b/src/base/i18n/icu_encoding_detection.h
new file mode 100644
index 0000000..6d1e71c
--- /dev/null
+++ b/src/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/src/base/i18n/icu_string_conversions.cc b/src/base/i18n/icu_string_conversions.cc
new file mode 100644
index 0000000..5ebadf3
--- /dev/null
+++ b/src/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/src/base/i18n/icu_string_conversions.h b/src/base/i18n/icu_string_conversions.h
new file mode 100644
index 0000000..31a57df
--- /dev/null
+++ b/src/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/src/base/i18n/icu_string_conversions_unittest.cc b/src/base/i18n/icu_string_conversions_unittest.cc
new file mode 100644
index 0000000..5401759
--- /dev/null
+++ b/src/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\x8E\xA6",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00\xFF66",
+   NULL},
+  // Japanese (ISO-2022)
+  {"iso-2022-jp",
+   "\x1B$B" "\x24\x33\x24\x73\x24\x4B\x24\x41\x24\x4F\x30\x6C" "\x1B(B"
+   "ab" "\x1B(J" "\x5C\x7E#$" "\x1B(B",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00" L"ab\x00A5\x203E#$",
+   NULL},
+  // Japanese (Shift-JIS)
+  {"sjis",
+   "\x82\xB1\x82\xF1\x82\xC9\x82\xBF\x82\xCD\x88\xEA\xA6",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00\xFF66",
+   NULL},
+  // Russian (KOI8)
+  {"koi8-r",
+   "\xDA\xC4\xD2\xC1\xD7\xD3\xD4\xD7\xD5\xCA\xD4\xC5",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0437\x0434\x0440\x0430\x0432\x0441\x0442\x0432"
+   L"\x0443\x0439\x0442\x0435",
+   NULL},
+  // Thai (windows-874)
+  {"windows-874",
+   "\xCA\xC7\xD1\xCA\xB4\xD5" "\xA4\xC3\xD1\xBA",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0E2A\x0E27\x0E31\x0E2A\x0E14\x0E35"
+   L"\x0E04\x0E23\x0e31\x0E1A",
+   NULL},
+  // 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/src/base/i18n/icu_util.cc b/src/base/i18n/icu_util.cc
new file mode 100644
index 0000000..8c48b36
--- /dev/null
+++ b/src/base/i18n/icu_util.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 "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
+
+#if defined(OS_STARBOARD)
+#include "starboard/client_porting/icu_init/icu_init.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) || defined(__LB_SHELL__) || defined(OS_STARBOARD)
+#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(__LB_SHELL__)
+  // Locate the data directory.
+  FilePath data_path;
+  bool path_ok = PathService::Get(base::DIR_EXE, &data_path);
+  DCHECK(path_ok);
+  data_path = data_path.Append("icu");
+#if U_IS_BIG_ENDIAN
+  data_path = data_path.Append("icudt46b");
+#else
+  data_path = data_path.Append("icudt46l");
+#endif
+  // set this as the data directory.
+  u_setDataDirectory(data_path.value().c_str());
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setFileAccess(UDATA_FILES_FIRST, &err);
+  return err == U_ZERO_ERROR;
+#elif defined(OS_STARBOARD)
+  SbIcuInit();
+  return true;
+#elif !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/src/base/i18n/icu_util.h b/src/base/i18n/icu_util.h
new file mode 100644
index 0000000..f6356f1
--- /dev/null
+++ b/src/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/src/base/i18n/icu_util_nacl_win64.cc b/src/base/i18n/icu_util_nacl_win64.cc
new file mode 100644
index 0000000..6e0bb6b
--- /dev/null
+++ b/src/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/src/base/i18n/number_formatting.cc b/src/base/i18n/number_formatting.cc
new file mode 100644
index 0000000..35ff08d
--- /dev/null
+++ b/src/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/src/base/i18n/number_formatting.h b/src/base/i18n/number_formatting.h
new file mode 100644
index 0000000..cfc4e12
--- /dev/null
+++ b/src/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/src/base/i18n/number_formatting_unittest.cc b/src/base/i18n/number_formatting_unittest.cc
new file mode 100644
index 0000000..e35eea0
--- /dev/null
+++ b/src/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) && !defined(__LB_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/src/base/i18n/rtl.cc b/src/base/i18n/rtl.cc
new file mode 100644
index 0000000..65f6a53
--- /dev/null
+++ b/src/base/i18n/rtl.cc
@@ -0,0 +1,362 @@
+// Copyright (c) 2011 The Chromium Authors. All 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) {
+#if defined(__LB_SHELL__) || defined(OS_STARBOARD)
+  // lbshell does not have the icu tables needed to determine RTL-ness.
+  // Rather than beef up our icu tables, hard-code the list of RTL languages
+  // that Chrome supports.  RTL layout is implemented by other components,
+  // so this does not affect our ability to do RTL layout nor RTL text.
+  return (!strncmp(locale_name, "he", 2) ||
+          !strncmp(locale_name, "ar", 2) ||
+          !strncmp(locale_name, "iw", 2) ||
+          !strncmp(locale_name, "fa", 2) ||
+          !strncmp(locale_name, "ur", 2))
+         ? RIGHT_TO_LEFT : LEFT_TO_RIGHT;
+#else
+  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;
+#endif
+}
+
+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/src/base/i18n/rtl.h b/src/base/i18n/rtl.h
new file mode 100644
index 0000000..202a126
--- /dev/null
+++ b/src/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/src/base/i18n/rtl_unittest.cc b/src/base/i18n/rtl_unittest.cc
new file mode 100644
index 0000000..176715a
--- /dev/null
+++ b/src/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/src/base/i18n/string_search.cc b/src/base/i18n/string_search.cc
new file mode 100644
index 0000000..9dc84ca
--- /dev/null
+++ b/src/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/src/base/i18n/string_search.h b/src/base/i18n/string_search.h
new file mode 100644
index 0000000..2069b0f
--- /dev/null
+++ b/src/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/src/base/i18n/string_search_unittest.cc b/src/base/i18n/string_search_unittest.cc
new file mode 100644
index 0000000..e6ca1c5
--- /dev/null
+++ b/src/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/src/base/i18n/time_formatting.cc b/src/base/i18n/time_formatting.cc
new file mode 100644
index 0000000..9906dba
--- /dev/null
+++ b/src/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/src/base/i18n/time_formatting.h b/src/base/i18n/time_formatting.h
new file mode 100644
index 0000000..91b79c6
--- /dev/null
+++ b/src/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/src/base/i18n/time_formatting_unittest.cc b/src/base/i18n/time_formatting_unittest.cc
new file mode 100644
index 0000000..89b5c55
--- /dev/null
+++ b/src/base/i18n/time_formatting_unittest.cc
@@ -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.
+
+#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 {
+
+#if defined(__LB_SHELL__)
+
+// Some legacy platforms' local time calculations always use the current
+// Daylight Savings Time status when exploding/unexploding time ticks, no matter
+// what the time to explode is. On Starboard platforms, we use ICU instead as it
+// is platform-independent and considerably more correct.
+#define MAYBE_TimeFormatTimeOfDayDefault12h \
+    DISABLED_TimeFormatTimeOfDayDefault12h
+#define MAYBE_TimeFormatTimeOfDayDefault24h \
+    DISABLED_TimeFormatTimeOfDayDefault24h
+#define MAYBE_TimeFormatTimeOfDayJP \
+    DISABLED_TimeFormatTimeOfDayJP
+#define MAYBE_TimeFormatDateUS \
+    DISABLED_TimeFormatDateUS
+#define MAYBE_TimeFormatDateGB \
+    DISABLED_TimeFormatDateGB
+
+#else
+
+#define MAYBE_TimeFormatTimeOfDayDefault12h TimeFormatTimeOfDayDefault12h
+#define MAYBE_TimeFormatTimeOfDayDefault24h TimeFormatTimeOfDayDefault24h
+#define MAYBE_TimeFormatTimeOfDayJP TimeFormatTimeOfDayJP
+#define MAYBE_TimeFormatDateUS TimeFormatDateUS
+#define MAYBE_TimeFormatDateGB TimeFormatDateGB
+
+#endif
+
+const Time::Exploded kTestDateTimeExploded = {
+  2011, 4, 6, 30, // Sat, Apr 30, 2011
+  15, 42, 7, 0    // 15:42:07.000
+};
+
+TEST(TimeFormattingTest, MAYBE_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, MAYBE_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, MAYBE_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, MAYBE_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, MAYBE_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/src/base/id_map.h b/src/base/id_map.h
new file mode 100644
index 0000000..d3fc7b8
--- /dev/null
+++ b/src/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/src/base/id_map_unittest.cc b/src/base/id_map_unittest.cc
new file mode 100644
index 0000000..53ca656
--- /dev/null
+++ b/src/base/id_map_unittest.cc
@@ -0,0 +1,341 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/id_map.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class TestObject {
+};
+
+class DestructorCounter {
+ public:
+  explicit DestructorCounter(int* counter) : counter_(counter) {}
+  ~DestructorCounter() { ++(*counter_); }
+
+ private:
+  int* counter_;
+};
+
+TEST(IDMapTest, Basic) {
+  IDMap<TestObject> map;
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  TestObject obj1;
+  TestObject obj2;
+
+  int32 id1 = map.Add(&obj1);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(1U, map.size());
+  EXPECT_EQ(&obj1, map.Lookup(id1));
+
+  int32 id2 = map.Add(&obj2);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(2U, map.size());
+
+  EXPECT_EQ(&obj1, map.Lookup(id1));
+  EXPECT_EQ(&obj2, map.Lookup(id2));
+
+  map.Remove(id1);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(1U, map.size());
+
+  map.Remove(id2);
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  map.AddWithID(&obj1, 1);
+  map.AddWithID(&obj2, 2);
+  EXPECT_EQ(&obj1, map.Lookup(1));
+  EXPECT_EQ(&obj2, map.Lookup(2));
+
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, IteratorRemainsValidWhenRemovingCurrentElement) {
+  IDMap<TestObject> map;
+
+  TestObject obj1;
+  TestObject obj2;
+  TestObject obj3;
+
+  map.Add(&obj1);
+  map.Add(&obj2);
+  map.Add(&obj3);
+
+  {
+    IDMap<TestObject>::const_iterator iter(&map);
+
+    EXPECT_EQ(1, map.iteration_depth());
+
+    while (!iter.IsAtEnd()) {
+      map.Remove(iter.GetCurrentKey());
+      iter.Advance();
+    }
+
+    // Test that while an iterator is still in scope, we get the map emptiness
+    // right (http://crbug.com/35571).
+    EXPECT_TRUE(map.IsEmpty());
+    EXPECT_EQ(0U, map.size());
+  }
+
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) {
+  IDMap<TestObject> map;
+
+  const int kCount = 5;
+  TestObject obj[kCount];
+  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(IDMapTest, CopyIterator) {
+  IDMap<TestObject> map;
+
+  TestObject obj1;
+  TestObject obj2;
+  TestObject obj3;
+
+  map.Add(&obj1);
+  map.Add(&obj2);
+  map.Add(&obj3);
+
+  EXPECT_EQ(0, map.iteration_depth());
+
+  {
+    IDMap<TestObject>::const_iterator iter1(&map);
+    EXPECT_EQ(1, map.iteration_depth());
+
+    // Make sure that copying the iterator correctly increments
+    // map's iteration depth.
+    IDMap<TestObject>::const_iterator iter2(iter1);
+    EXPECT_EQ(2, map.iteration_depth());
+  }
+
+  // Make sure after destroying all iterators the map's iteration depth
+  // returns to initial state.
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, AssignIterator) {
+  IDMap<TestObject> map;
+
+  TestObject obj1;
+  TestObject obj2;
+  TestObject obj3;
+
+  map.Add(&obj1);
+  map.Add(&obj2);
+  map.Add(&obj3);
+
+  EXPECT_EQ(0, map.iteration_depth());
+
+  {
+    IDMap<TestObject>::const_iterator iter1(&map);
+    EXPECT_EQ(1, map.iteration_depth());
+
+    IDMap<TestObject>::const_iterator iter2(&map);
+    EXPECT_EQ(2, map.iteration_depth());
+
+    // Make sure that assigning the iterator correctly updates
+    // map's iteration depth (-1 for destruction, +1 for assignment).
+    EXPECT_EQ(2, map.iteration_depth());
+  }
+
+  // Make sure after destroying all iterators the map's iteration depth
+  // returns to initial state.
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+// This test relies on specific ordering of items in a hash map to expect a
+// given ID at a given iteration point.  This is a bad expectation for a
+// hash_map, and one that does not hold on lbshell platforms.  This test
+// should be rewritten.
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+TEST(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());
+}
+#endif
+
+TEST(IDMapTest, OwningPointersDeletesThemOnRemove) {
+  const int kCount = 3;
+
+  int external_del_count = 0;
+  DestructorCounter* external_obj[kCount];
+  int map_external_ids[kCount];
+
+  int owned_del_count = 0;
+  DestructorCounter* owned_obj[kCount];
+  int map_owned_ids[kCount];
+
+  IDMap<DestructorCounter> map_external;
+  IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+  for (int i = 0; i < kCount; ++i) {
+    external_obj[i] = new DestructorCounter(&external_del_count);
+    map_external_ids[i] = map_external.Add(external_obj[i]);
+
+    owned_obj[i] = new DestructorCounter(&owned_del_count);
+    map_owned_ids[i] = map_owned.Add(owned_obj[i]);
+  }
+
+  for (int i = 0; i < kCount; ++i) {
+    EXPECT_EQ(external_del_count, 0);
+    EXPECT_EQ(owned_del_count, i);
+
+    map_external.Remove(map_external_ids[i]);
+    map_owned.Remove(map_owned_ids[i]);
+  }
+
+  for (int i = 0; i < kCount; ++i) {
+    delete external_obj[i];
+  }
+
+  EXPECT_EQ(external_del_count, kCount);
+  EXPECT_EQ(owned_del_count, kCount);
+}
+
+TEST(IDMapTest, OwningPointersDeletesThemOnClear) {
+  const int kCount = 3;
+
+  int external_del_count = 0;
+  DestructorCounter* external_obj[kCount];
+
+  int owned_del_count = 0;
+  DestructorCounter* owned_obj[kCount];
+
+  IDMap<DestructorCounter> map_external;
+  IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+  for (int i = 0; i < kCount; ++i) {
+    external_obj[i] = new DestructorCounter(&external_del_count);
+    map_external.Add(external_obj[i]);
+
+    owned_obj[i] = new DestructorCounter(&owned_del_count);
+    map_owned.Add(owned_obj[i]);
+  }
+
+  EXPECT_EQ(external_del_count, 0);
+  EXPECT_EQ(owned_del_count, 0);
+
+  map_external.Clear();
+  map_owned.Clear();
+
+  EXPECT_EQ(external_del_count, 0);
+  EXPECT_EQ(owned_del_count, kCount);
+
+  for (int i = 0; i < kCount; ++i) {
+    delete external_obj[i];
+  }
+
+  EXPECT_EQ(external_del_count, kCount);
+  EXPECT_EQ(owned_del_count, kCount);
+}
+
+TEST(IDMapTest, OwningPointersDeletesThemOnDestruct) {
+  const int kCount = 3;
+
+  int external_del_count = 0;
+  DestructorCounter* external_obj[kCount];
+
+  int owned_del_count = 0;
+  DestructorCounter* owned_obj[kCount];
+
+  {
+    IDMap<DestructorCounter> map_external;
+    IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+    for (int i = 0; i < kCount; ++i) {
+      external_obj[i] = new DestructorCounter(&external_del_count);
+      map_external.Add(external_obj[i]);
+
+      owned_obj[i] = new DestructorCounter(&owned_del_count);
+      map_owned.Add(owned_obj[i]);
+    }
+  }
+
+  EXPECT_EQ(external_del_count, 0);
+
+  for (int i = 0; i < kCount; ++i) {
+    delete external_obj[i];
+  }
+
+  EXPECT_EQ(external_del_count, kCount);
+  EXPECT_EQ(owned_del_count, kCount);
+}
+
+}  // namespace
diff --git a/src/base/ios/device_util.h b/src/base/ios/device_util.h
new file mode 100644
index 0000000..fe4833d
--- /dev/null
+++ b/src/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/src/base/ios/device_util.mm b/src/base/ios/device_util.mm
new file mode 100644
index 0000000..b538ea8
--- /dev/null
+++ b/src/base/ios/device_util.mm
@@ -0,0 +1,151 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/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 kLegacyClientIdPreferenceKey = @"ChromiumClientID";
+NSString* const kClientIdPreferenceKey = @"ChromeClientID";
+// Default salt for device ids.
+const char kDefaultSalt[] = "Salt";
+// Zero UUID returned on buggy iOS devices.
+NSString* const kZeroUUID = @"00000000-0000-0000-0000-000000000000";
+
+NSString* GenerateClientId() {
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+
+  // Try to migrate from legacy client id.
+  NSString* client_id = [defaults stringForKey:kLegacyClientIdPreferenceKey];
+
+  // Some iOS6 devices return a buggy identifierForVendor:
+  // http://openradar.appspot.com/12377282. If this is the case, revert to
+  // generating a new one.
+  if (!client_id || [client_id isEqualToString:kZeroUUID]) {
+    if (base::ios::IsRunningOnIOS6OrLater()) {
+      client_id = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
+      if ([client_id isEqualToString:kZeroUUID])
+        client_id = base::SysUTF8ToNSString(ios::device_util::GetRandomId());
+    } else {
+      client_id = base::SysUTF8ToNSString(ios::device_util::GetRandomId());
+    }
+  }
+  return client_id;
+}
+
+}  // namespace
+
+namespace ios {
+namespace device_util {
+
+std::string GetPlatform() {
+  std::string platform;
+  size_t size = 0;
+  sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+  sysctlbyname("hw.machine", WriteInto(&platform, size), &size, NULL, 0);
+  return platform;
+}
+
+bool 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) {
+    client_id = GenerateClientId();
+    [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/src/base/ios/device_util_unittest.mm b/src/base/ios/device_util_unittest.mm
new file mode 100644
index 0000000..12bfe09
--- /dev/null
+++ b/src/base/ios/device_util_unittest.mm
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.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;
+
+void CleanNSUserDefaultsForDeviceId() {
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults removeObjectForKey:@"ChromeClientID"];
+  [defaults removeObjectForKey:@"ChromiumClientID"];
+  [defaults synchronize];
+}
+
+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) {
+  CleanNSUserDefaultsForDeviceId();
+
+  std::string default_id = ios::device_util::GetDeviceIdentifier(NULL);
+  std::string other_id = ios::device_util::GetDeviceIdentifier("ForTest");
+  EXPECT_NE(default_id, other_id);
+
+  CleanNSUserDefaultsForDeviceId();
+
+  std::string new_default_id = ios::device_util::GetDeviceIdentifier(NULL);
+  if (base::ios::IsRunningOnIOS6OrLater() &&
+      ![[[[UIDevice currentDevice] identifierForVendor] UUIDString]
+          isEqualToString:@"00000000-0000-0000-0000-000000000000"]) {
+    EXPECT_EQ(default_id, new_default_id);
+  } else {
+    EXPECT_NE(default_id, new_default_id);
+  }
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+TEST_F(DeviceUtilTest, CheckMigration) {
+  CleanNSUserDefaultsForDeviceId();
+
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:@"10000000-0000-0000-0000-000000000000"
+               forKey:@"ChromeClientID"];
+  [defaults synchronize];
+  std::string expected_id = ios::device_util::GetDeviceIdentifier(NULL);
+  [defaults removeObjectForKey:@"ChromeClientID"];
+  [defaults setObject:@"10000000-0000-0000-0000-000000000000"
+               forKey:@"ChromiumClientID"];
+  [defaults synchronize];
+  std::string new_id = ios::device_util::GetDeviceIdentifier(NULL);
+  EXPECT_EQ(expected_id, new_id);
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+TEST_F(DeviceUtilTest, CheckMigrationFromZero) {
+  CleanNSUserDefaultsForDeviceId();
+
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:@"00000000-0000-0000-0000-000000000000"
+               forKey:@"ChromeClientID"];
+  [defaults synchronize];
+  std::string zero_id = ios::device_util::GetDeviceIdentifier(NULL);
+  [defaults removeObjectForKey:@"ChromeClientID"];
+  [defaults setObject:@"00000000-0000-0000-0000-000000000000"
+               forKey:@"ChromiumClientID"];
+  [defaults synchronize];
+  std::string new_id = ios::device_util::GetDeviceIdentifier(NULL);
+  EXPECT_NE(zero_id, new_id);
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+}  // namespace
diff --git a/src/base/ios/ios_util.h b/src/base/ios/ios_util.h
new file mode 100644
index 0000000..e8f9806
--- /dev/null
+++ b/src/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/src/base/ios/ios_util.mm b/src/base/ios/ios_util.mm
new file mode 100644
index 0000000..37f386d
--- /dev/null
+++ b/src/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/src/base/ios/scoped_critical_action.h b/src/base/ios/scoped_critical_action.h
new file mode 100644
index 0000000..660a83a
--- /dev/null
+++ b/src/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/src/base/ios/scoped_critical_action.mm b/src/base/ios/scoped_critical_action.mm
new file mode 100644
index 0000000..734c0a2
--- /dev/null
+++ b/src/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/src/base/json/json_file_value_serializer.cc b/src/base/json/json_file_value_serializer.cc
new file mode 100644
index 0000000..2fac451
--- /dev/null
+++ b/src/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/src/base/json/json_file_value_serializer.h b/src/base/json/json_file_value_serializer.h
new file mode 100644
index 0000000..633db5d
--- /dev/null
+++ b/src/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/src/base/json/json_parser.cc b/src/base/json/json_parser.cc
new file mode 100644
index 0000000..4c03a98
--- /dev/null
+++ b/src/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 new StringValue(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 new FundamentalValue(num_int);
+
+  double num_double;
+  if (base::StringToDouble(num_string.as_string(), &num_double) &&
+      IsFinite(num_double)) {
+    return new FundamentalValue(num_double);
+  }
+
+  return NULL;
+}
+
+bool JSONParser::ReadInt(bool allow_leading_zeros) {
+  char first = *pos_;
+  int len = 0;
+
+  char c = first;
+  while (CanConsume(1) && IsAsciiDigit(c)) {
+    c = *NextChar();
+    ++len;
+  }
+
+  if (len == 0)
+    return false;
+
+  if (!allow_leading_zeros && len > 1 && first == '0')
+    return false;
+
+  return true;
+}
+
+Value* JSONParser::ConsumeLiteral() {
+  switch (*pos_) {
+    case 't': {
+      const char* kTrueLiteral = "true";
+      const int kTrueLen = static_cast<int>(strlen(kTrueLiteral));
+      if (!CanConsume(kTrueLen - 1) ||
+          !StringsAreEqual(pos_, kTrueLiteral, kTrueLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kTrueLen - 1);
+      return new FundamentalValue(true);
+    }
+    case 'f': {
+      const char* kFalseLiteral = "false";
+      const int kFalseLen = static_cast<int>(strlen(kFalseLiteral));
+      if (!CanConsume(kFalseLen - 1) ||
+          !StringsAreEqual(pos_, kFalseLiteral, kFalseLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kFalseLen - 1);
+      return new FundamentalValue(false);
+    }
+    case 'n': {
+      const char* kNullLiteral = "null";
+      const int kNullLen = static_cast<int>(strlen(kNullLiteral));
+      if (!CanConsume(kNullLen - 1) ||
+          !StringsAreEqual(pos_, kNullLiteral, kNullLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kNullLen - 1);
+      return Value::CreateNullValue();
+    }
+    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/src/base/json/json_parser.h b/src/base/json/json_parser.h
new file mode 100644
index 0000000..020ac25
--- /dev/null
+++ b/src/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/src/base/json/json_parser_unittest.cc b/src/base/json/json_parser_unittest.cc
new file mode 100644
index 0000000..8ee886b
--- /dev/null
+++ b/src/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/src/base/json/json_reader.cc b/src/base/json/json_reader.cc
new file mode 100644
index 0000000..593273e
--- /dev/null
+++ b/src/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/src/base/json/json_reader.h b/src/base/json/json_reader.h
new file mode 100644
index 0000000..86b2612
--- /dev/null
+++ b/src/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/src/base/json/json_reader_unittest.cc b/src/base/json/json_reader_unittest.cc
new file mode 100644
index 0000000..38bf590
--- /dev/null
+++ b/src/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/src/base/json/json_string_value_serializer.cc b/src/base/json/json_string_value_serializer.cc
new file mode 100644
index 0000000..59c0765
--- /dev/null
+++ b/src/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/src/base/json/json_string_value_serializer.h b/src/base/json/json_string_value_serializer.h
new file mode 100644
index 0000000..e333dc6
--- /dev/null
+++ b/src/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/src/base/json/json_value_converter.h b/src/base/json/json_value_converter.h
new file mode 100644
index 0000000..69da0d8
--- /dev/null
+++ b/src/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/src/base/json/json_value_converter_unittest.cc b/src/base/json/json_value_converter_unittest.cc
new file mode 100644
index 0000000..e5ad289
--- /dev/null
+++ b/src/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/src/base/json/json_value_serializer_unittest.cc b/src/base/json/json_value_serializer_unittest.cc
new file mode 100644
index 0000000..dc103dd
--- /dev/null
+++ b/src/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/files/scoped_temp_dir.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/memory/scoped_ptr.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/src/base/json/json_writer.cc b/src/base/json/json_writer.cc
new file mode 100644
index 0000000..e8cf9ac
--- /dev/null
+++ b/src/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/src/base/json/json_writer.h b/src/base/json/json_writer.h
new file mode 100644
index 0000000..94052c8
--- /dev/null
+++ b/src/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/src/base/json/json_writer_unittest.cc b/src/base/json/json_writer_unittest.cc
new file mode 100644
index 0000000..7ddd7b4
--- /dev/null
+++ b/src/base/json/json_writer_unittest.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/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 = new FundamentalValue(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 = new FundamentalValue(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 = new FundamentalValue(-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(new FundamentalValue(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", new FundamentalValue(3));
+  period_dict.SetWithoutPathExpansion("c", new FundamentalValue(2));
+  DictionaryValue* period_dict2 = new DictionaryValue;
+  period_dict2->SetWithoutPathExpansion("g.h.i.j", new FundamentalValue(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", new FundamentalValue(2));
+  period_dict3.SetWithoutPathExpansion("a.b", new FundamentalValue(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(new FundamentalValue(5));
+  binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_list.Append(new FundamentalValue(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", new FundamentalValue(5));
+  binary_dict.Set("b", BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_dict.Set("c", new FundamentalValue(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/src/base/json/string_escape.cc b/src/base/json/string_escape.cc
new file mode 100644
index 0000000..b4415b8
--- /dev/null
+++ b/src/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/src/base/json/string_escape.h b/src/base/json/string_escape.h
new file mode 100644
index 0000000..088db62
--- /dev/null
+++ b/src/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/src/base/json/string_escape_unittest.cc b/src/base/json/string_escape_unittest.cc
new file mode 100644
index 0000000..c550ca3
--- /dev/null
+++ b/src/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/src/base/lazy_instance.cc b/src/base/lazy_instance.cc
new file mode 100644
index 0000000..a81cb8c
--- /dev/null
+++ b/src/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/src/base/lazy_instance.h b/src/base/lazy_instance.h
new file mode 100644
index 0000000..6e833bf
--- /dev/null
+++ b/src/base/lazy_instance.h
@@ -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.
+
+// 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/src/base/lazy_instance_unittest.cc b/src/base/lazy_instance_unittest.cc
new file mode 100644
index 0000000..e25366e
--- /dev/null
+++ b/src/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/src/base/linux_util.cc b/src/base/linux_util.cc
new file mode 100644
index 0000000..49df773
--- /dev/null
+++ b/src/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/src/base/linux_util.h b/src/base/linux_util.h
new file mode 100644
index 0000000..b9ba56d
--- /dev/null
+++ b/src/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/src/base/location.cc b/src/base/location.cc
new file mode 100644
index 0000000..b6ded2c
--- /dev/null
+++ b/src/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) && !defined(__LB_PS3__) && !defined(__LB_WIIU__)
+  return __builtin_extract_return_addr(__builtin_return_address(0));
+#endif  // COMPILER_GCC
+
+  return NULL;
+}
+
+}  // namespace tracked_objects
diff --git a/src/base/location.h b/src/base/location.h
new file mode 100644
index 0000000..05a4f66
--- /dev/null
+++ b/src/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/src/base/logging.cc b/src/base/logging.cc
new file mode 100644
index 0000000..6a135ea
--- /dev/null
+++ b/src/base/logging.cc
@@ -0,0 +1,995 @@
+// Copyright (c) 2012 The Chromium Authors. All 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>
+#elif defined(OS_STARBOARD)
+#include "starboard/client_porting/eztime/eztime.h"
+#include "starboard/file.h"
+#include "starboard/log.h"
+#include "starboard/mutex.h"
+#include "starboard/system.h"
+#include "starboard/time.h"
+typedef SbFile FileHandle;
+typedef SbMutex MutexHandle;
+#endif
+
+#if defined(__LB_SHELL__)
+// To implement TickCount.
+#include "lb_platform.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/posix/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) || defined(__LB_ANDROID__)
+#include <android/log.h>
+#endif
+
+#if defined(__LB_XB1__) || defined(__LB_XB360__)
+#undef MAX_PATH
+#include <Windows.h>
+#undef MAX_PATH
+#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;
+#elif defined(OS_STARBOARD)
+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(__LB_SHELL__) || defined(OS_STARBOARD)
+  // This should never be reached, because logging PIDs should never
+  // be enabled for LB shell.
+  return 0;
+#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_STARBOARD)
+  return static_cast<uint64>(SbTimeGetMonotonicNow());
+#elif defined(__LB_SHELL__)
+  return LB::Platform::TickCount();
+#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);
+#elif defined(OS_STARBOARD)
+  SbFileClose(log);
+#else
+  fclose(log);
+#endif
+}
+
+void DeleteFilePath(const PathString& log_name) {
+#if defined(OS_WIN)
+  DeleteFile(log_name.c_str());
+#elif defined(OS_STARBOARD)
+  SbFileDelete(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_STARBOARD)
+  // On Starboard, we politely ask for the log directory, like a civilized
+  // platform.
+  char path[SB_FILE_MAX_PATH + 1];
+  SbSystemGetPath(kSbSystemPathDebugOutputDirectory, path,
+                  SB_ARRAY_SIZE_INT(path));
+  PathString log_file = path;
+  log_file += SB_FILE_SEP_STRING "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);
+#elif defined(OS_STARBOARD)
+      SbMutexAcquire(&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);
+#elif defined(OS_STARBOARD)
+      SbMutexRelease(&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;
+#elif defined(OS_STARBOARD)
+  static SbMutex 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;
+#elif defined(OS_STARBOARD)
+SbMutex LoggingLock::log_mutex = SB_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 defined(COBALT)
+  // This seems to get called a lot with an empty filename, at least in
+  // base_unittests.
+  if (log_file_name->empty()) {
+    return false;
+  }
+#endif
+
+  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;
+#elif defined(OS_STARBOARD)
+    log_file = SbFileOpen(log_file_name->c_str(),
+                          kSbFileOpenAlways | kSbFileWrite, NULL, NULL);
+    if (!SbFileIsValid(log_file))
+      return false;
+
+    SbFileSeek(log_file, kSbFileFromEnd, 0);
+#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() {
+#if LOGGING_IS_OFFICIAL_BUILD
+  return LOG_FATAL;
+#else
+  return min_log_level;
+#endif
+}
+
+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(__LB_SHELL__FORCE_LOGGING__)) && \
+    !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_STARBOARD)
+    SbLogPriority priority = kSbLogPriorityUnknown;
+    switch (severity_) {
+      case LOG_INFO:
+        priority = kSbLogPriorityInfo;
+        break;
+      case LOG_WARNING:
+        priority = kSbLogPriorityWarning;
+        break;
+      case LOG_ERROR:
+      case LOG_ERROR_REPORT:
+        priority = kSbLogPriorityError;
+        break;
+      case LOG_FATAL:
+        priority = kSbLogPriorityFatal;
+        break;
+    }
+    SbLog(priority, str_newline.c_str());
+#elif defined(OS_WIN) || defined(COBALT_WIN)
+    OutputDebugStringA(str_newline.c_str());
+#elif defined(OS_ANDROID) || defined(__LB_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
+#if !defined(OS_STARBOARD)
+    fprintf(stderr, "%s", str_newline.c_str());
+    fflush(stderr);
+#endif
+  } 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);
+#elif defined(OS_STARBOARD)
+      SbFileSeek(log_file, kSbFileFromEnd, 0);
+      int written = 0;
+      while (written < str_newline.length()) {
+        int result = SbFileWrite(log_file, &(str_newline.c_str()[written]),
+                                 str_newline.length() - written);
+        if (result < 0) {
+          break;
+        }
+        written += result;
+      }
+#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) {
+#if defined(OS_STARBOARD)
+    EzTimeT t = EzTimeTGetNow(NULL);
+    struct EzTimeExploded local_time = {0};
+    EzTimeTExplodeLocal(&t, &local_time);
+    struct EzTimeExploded* tm_time = &local_time;
+#else
+    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;
+#endif
+    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;
+#elif defined(OS_STARBOARD)
+  // Not implemented yet
+  return SbSystemGetLastError();
+#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_);
+}
+#elif defined(OS_STARBOARD)
+StarboardLogMessage::StarboardLogMessage(const char* file,
+                                         int line,
+                                         LogSeverity severity,
+                                         SystemErrorCode err)
+    : err_(err),
+      log_message_(file, line, severity) {
+}
+
+StarboardLogMessage::~StarboardLogMessage() {
+  char message[512];
+  SbSystemGetErrorString(err_, message, SB_ARRAY_SIZE_INT(message));
+  stream() << ": " << message;
+}
+#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) {
+#if defined(OS_STARBOARD)
+    SbLogRaw(message);
+    const size_t message_len = strlen(message);
+    if (message_len > 0 && message[message_len - 1] != '\n') {
+      SbLogRaw("\n");
+    }
+#else
+    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);
+    }
+#endif
+  }
+
+  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/src/base/logging.h b/src/base/logging.h
new file mode 100644
index 0000000..2fb626e
--- /dev/null
+++ b/src/base/logging.h
@@ -0,0 +1,1092 @@
+// Copyright (c) 2012 The Chromium Authors. All 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"
+
+#if defined(OS_STARBOARD)
+#include "starboard/system.h"
+#endif
+
+//
+// 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 defined(NDEBUG) && !defined(__LB_SHELL__FORCE_LOGGING__)
+#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
+#if defined(NDEBUG) && !defined(__LB_SHELL__FORCE_LOGGING__)
+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()
+#elif defined(OS_STARBOARD)
+#define VPLOG_STREAM(verbose_level) \
+  logging::StarboardLogMessage(__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)
+#elif defined(OS_STARBOARD)
+#define LOG_SB_ERROR_STREAM(severity) \
+  COMPACT_GOOGLE_LOG_EX_ ## severity(StarboardLogMessage, \
+      ::logging::GetLastSystemErrorCode()).stream()
+#define LOG_SB_ERROR(severity) \
+  LAZY_STREAM(LOG_SB_ERROR_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_SB_ERROR_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)) || \
+    defined(__LB_SHELL__FOR_RELEASE__)
+#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
+
+// Help Microsoft code analysis tool to understand that if CHECK()/PCHECK()
+// did not terminate the execution, the condition they checked must be true.
+// Note that the code under _PREFAST_ macro is not actually executed, only
+// analyzed.
+#if defined(COBALT) && defined(_PREFAST_)
+#define CHECK(condition)                                        \
+  __analysis_assume(condition), EAT_STREAM_PARAMETERS
+
+#define PCHECK(condition)                                       \
+  __analysis_assume(condition), EAT_STREAM_PARAMETERS
+#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 ". "
+#endif
+
+// 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) && !defined(COMPILER_GHS)
+// 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); \
+  }
+
+// Turn off sign-conversion warnings for DCHECK_EQ. This is for
+// consistency with EXPECT_EQ and ASSERT_EQ in gtest.
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4389)
+#elif defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wsign-compare"
+#endif
+
+DEFINE_CHECK_OP_IMPL(EQ, ==)
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#elif defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+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 || \
+    (defined(__LB_SHELL__FOR_QA__) && !defined(__LB_SHELL__FORCE_LOGGING__))
+// In order to have optimized code for official builds, remove DLOGs and
+// DCHECKs.
+#define ENABLE_DLOG 0
+#define ENABLE_DCHECK 0
+
+#elif defined(NDEBUG) && !defined(__LB_SHELL__FORCE_LOGGING__)
+// 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) && !defined(__LB_SHELL__FORCE_LOGGING__)
+
+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) && !defined(__LB_SHELL__FORCE_LOGGING__)
+
+#if defined(NDEBUG) && defined(__LB_SHELL__FORCE_LOGGING__)
+BASE_EXPORT extern DcheckState g_dcheck_state;
+#endif
+
+// 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) && !defined(__LB_SHELL__FORCE_LOGGING__)
+
+#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.
+
+// Help Microsoft code analysis tool to understand that if DCHECK()/DPCHECK()
+// did not terminate the execution, the condition they checked must be true.
+// Note that the code under _PREFAST_ macro is not actually executed, only
+// analyzed.
+// Use !!(condition) to work around error C2088:
+// '__assume': illegal for class
+#if defined(COBALT) && defined(_PREFAST_)
+#define DCHECK(condition)                                           \
+  __analysis_assume(!!(condition)), EAT_STREAM_PARAMETERS
+
+#define DPCHECK(condition)                                          \
+  __analysis_assume(!!(condition)), EAT_STREAM_PARAMETERS
+#else
+#define DCHECK(condition)                                                  \
+  LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false)   \
+  << "Check failed: " #condition ". "
+
+#define DPCHECK(condition)                                                 \
+  LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false)  \
+  << "Check failed: " #condition ". "
+#endif
+
+// 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;
+#elif defined(OS_STARBOARD)
+typedef SbSystemError 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);
+};
+#elif defined(OS_STARBOARD)
+// Appends a formatted system message of the errno type
+class BASE_EXPORT StarboardLogMessage {
+ public:
+  StarboardLogMessage(const char* file,
+                      int line,
+                      LogSeverity severity,
+                      SystemErrorCode err);
+
+  // Appends the error message before destructing the encapsulated class.
+  ~StarboardLogMessage();
+
+  std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+  SystemErrorCode err_;
+  LogMessage log_message_;
+
+  DISALLOW_COPY_AND_ASSIGN(StarboardLogMessage);
+};
+#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();
+}
+
+#if defined(__LB_SHELL__) || defined(COBALT)
+#if defined(__cplusplus_winrt)
+// Support for logging C++/CX strings. This function must be inlined because
+// the Chromium library is not compiled with C++/CX extensions enabled.
+inline std::ostream& operator<<(std::ostream& out, ::Platform::String^ str) {
+  return out << std::wstring(str->Begin(), str->End());
+}
+#endif
+#endif
+
+// 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)) || \
+  defined(__LB_SHELL__FOR_RELEASE__)
+#define NOTIMPLEMENTED_POLICY 0
+#elif defined (__LB_SHELL__) || defined(COBALT)
+  // Only print each message once.
+#define NOTIMPLEMENTED_POLICY 5
+#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__
+#elif defined(__LB_SHELL__) || defined(COBALT)
+#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __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);\
+EAT_STREAM_PARAMETERS
+#endif
+
+#endif  // BASE_LOGGING_H_
diff --git a/src/base/logging_unittest.cc b/src/base/logging_unittest.cc
new file mode 100644
index 0000000..f0e9f56
--- /dev/null
+++ b/src/base/logging_unittest.cc
@@ -0,0 +1,279 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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) && !defined(__LB_SHELL__FORCE_LOGGING__)
+  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) || defined(__LB_SHELL__FORCE_LOGGING__)
+  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) && !defined(__LB_SHELL__FORCE_LOGGING__)
+  // 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));
+#elif defined(NDEBUG) && defined(__LB_SHELL__FORCE_LOGGING__)
+  // Unofficial release build with real DCHECKS.
+  g_dcheck_state = ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
+  SetLogAssertHandler(&LogSink);
+  EXPECT_TRUE(DCHECK_IS_ON());
+  // FORCE_LOGGING implies DLOG is on.
+  EXPECT_TRUE(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)
+
+#if !defined(OS_STARBOARD)
+#if defined(__LB_SHELL__)
+  // These only break when the Logging class thinks a debugger is attached.
+  // Unfortunately, LB_SHELL assumes a debugger is attached as long as
+  // NDEBUG is not defined for some platforms (see debugger_posix.cc:BeingDebugged()).
+  if (!base::debug::BeingDebugged()) {
+#endif
+    EXPECT_EQ(0, log_sink_call_count);
+    DCHECK(false);
+    EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count);
+    DPCHECK(false);
+    EXPECT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count);
+    DCHECK_EQ(0, 1);
+    EXPECT_EQ(DCHECK_IS_ON() ? 3 : 0, log_sink_call_count);
+#if defined(__LB_SHELL__)
+  }
+#endif
+#endif
+}
+
+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/src/base/logging_win.cc b/src/base/logging_win.cc
new file mode 100644
index 0000000..a714665
--- /dev/null
+++ b/src/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/src/base/logging_win.h b/src/base/logging_win.h
new file mode 100644
index 0000000..0720231
--- /dev/null
+++ b/src/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/src/base/mac/authorization_util.h b/src/base/mac/authorization_util.h
new file mode 100644
index 0000000..b34348d
--- /dev/null
+++ b/src/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/src/base/mac/authorization_util.mm b/src/base/mac/authorization_util.mm
new file mode 100644
index 0000000..62a2074
--- /dev/null
+++ b/src/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/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/posix/eintr_wrapper.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/src/base/mac/bind_objc_block.h b/src/base/mac/bind_objc_block.h
new file mode 100644
index 0000000..2d48c7d
--- /dev/null
+++ b/src/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/src/base/mac/bind_objc_block.mm b/src/base/mac/bind_objc_block.mm
new file mode 100644
index 0000000..81472d0
--- /dev/null
+++ b/src/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/src/base/mac/bind_objc_block_unittest.mm b/src/base/mac/bind_objc_block_unittest.mm
new file mode 100644
index 0000000..17fbe6e
--- /dev/null
+++ b/src/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/src/base/mac/bundle_locations.h b/src/base/mac/bundle_locations.h
new file mode 100644
index 0000000..dd84b59
--- /dev/null
+++ b/src/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/src/base/mac/bundle_locations.mm b/src/base/mac/bundle_locations.mm
new file mode 100644
index 0000000..363b7ea
--- /dev/null
+++ b/src/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/src/base/mac/cocoa_protocols.h b/src/base/mac/cocoa_protocols.h
new file mode 100644
index 0000000..314e7fa
--- /dev/null
+++ b/src/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/src/base/mac/crash_logging.h b/src/base/mac/crash_logging.h
new file mode 100644
index 0000000..7e83eae
--- /dev/null
+++ b/src/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/src/base/mac/crash_logging.mm b/src/base/mac/crash_logging.mm
new file mode 100644
index 0000000..e18a3fb
--- /dev/null
+++ b/src/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/src/base/mac/foundation_util.h b/src/base/mac/foundation_util.h
new file mode 100644
index 0000000..e6ad784
--- /dev/null
+++ b/src/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/src/base/mac/foundation_util.mm b/src/base/mac/foundation_util.mm
new file mode 100644
index 0000000..3fd9a57
--- /dev/null
+++ b/src/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/src/base/mac/foundation_util_unittest.mm b/src/base/mac/foundation_util_unittest.mm
new file mode 100644
index 0000000..4653006
--- /dev/null
+++ b/src/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/src/base/mac/launchd.cc b/src/base/mac/launchd.cc
new file mode 100644
index 0000000..1d384c9
--- /dev/null
+++ b/src/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/src/base/mac/launchd.h b/src/base/mac/launchd.h
new file mode 100644
index 0000000..9e4514e
--- /dev/null
+++ b/src/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/src/base/mac/libdispatch_task_runner.cc b/src/base/mac/libdispatch_task_runner.cc
new file mode 100644
index 0000000..4b5abaf
--- /dev/null
+++ b/src/base/mac/libdispatch_task_runner.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/libdispatch_task_runner.h"
+
+#include "base/callback.h"
+
+namespace base {
+namespace mac {
+
+LibDispatchTaskRunner::LibDispatchTaskRunner(const char* name)
+    : queue_(dispatch_queue_create(name, NULL)),
+      queue_finalized_(false, false) {
+  dispatch_set_context(queue_, this);
+  dispatch_set_finalizer_f(queue_, &LibDispatchTaskRunner::Finalizer);
+}
+
+bool LibDispatchTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    base::TimeDelta delay) {
+  if (!queue_)
+    return false;
+
+  // The block runtime would implicitly copy the reference, not the object
+  // it's referencing. Copy the closure into block storage so it's available
+  // to run.
+  __block const Closure task_copy = task;
+  void(^run_task)(void) = ^{
+      task_copy.Run();
+  };
+
+  int64 delay_nano =
+      delay.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond;
+  if (delay_nano > 0) {
+    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay_nano);
+    dispatch_after(time, queue_, run_task);
+  } else {
+    dispatch_async(queue_, run_task);
+  }
+  return true;
+}
+
+bool LibDispatchTaskRunner::RunsTasksOnCurrentThread() const {
+  return queue_ == dispatch_get_current_queue();
+}
+
+bool LibDispatchTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    base::TimeDelta delay) {
+  return PostDelayedTask(from_here, task, delay);
+}
+
+void LibDispatchTaskRunner::Shutdown() {
+  dispatch_release(queue_);
+  queue_ = NULL;
+  queue_finalized_.Wait();
+}
+
+dispatch_queue_t LibDispatchTaskRunner::GetDispatchQueue() const {
+  return queue_;
+}
+
+LibDispatchTaskRunner::~LibDispatchTaskRunner() {
+  if (queue_) {
+    dispatch_set_context(queue_, NULL);
+    dispatch_set_finalizer_f(queue_, NULL);
+    dispatch_release(queue_);
+  }
+}
+
+void LibDispatchTaskRunner::Finalizer(void* context) {
+  LibDispatchTaskRunner* self = static_cast<LibDispatchTaskRunner*>(context);
+  self->queue_finalized_.Signal();
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/src/base/mac/libdispatch_task_runner.h b/src/base/mac/libdispatch_task_runner.h
new file mode 100644
index 0000000..b1d90e2
--- /dev/null
+++ b/src/base/mac/libdispatch_task_runner.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_MAC_LIBDISPATCH_SEQUENCED_TASK_RUNNER_H_
+#define BASE_MAC_LIBDISPATCH_SEQUENCED_TASK_RUNNER_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+namespace mac {
+
+// This is an implementation of the TaskRunner interface that runs closures on
+// a thread managed by Apple's libdispatch. This has the benefit of being able
+// to PostTask() and friends to a dispatch queue, while being reusable as a
+// dispatch_queue_t.
+//
+// One would use this class if an object lives exclusively on one thread but
+// needs a dispatch_queue_t for use in a system API. This ensures all dispatch
+// callbacks happen on the same thread as Closure tasks.
+//
+// A LibDispatchTaskRunner will continue to run until all references to the
+// underlying dispatch queue are released.
+//
+// Important Notes:
+//   - There is no MessageLoop running on this thread, and ::current() returns
+//     NULL.
+//   - No nested loops can be run, and all tasks are run non-nested.
+//   - Work scheduled via libdispatch runs at the same priority as and is
+//     interleaved with posted tasks, though FIFO order is guaranteed.
+//
+class BASE_EXPORT LibDispatchTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+  // Starts a new serial dispatch queue with a given name.
+  explicit LibDispatchTaskRunner(const char* name);
+
+  // base::TaskRunner:
+  virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               base::TimeDelta delay) OVERRIDE;
+  virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
+
+  // base::SequencedTaskRunner:
+  virtual bool PostNonNestableDelayedTask(
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      base::TimeDelta delay) OVERRIDE;
+
+  // This blocks the calling thread until all work on the dispatch queue has
+  // been run and the queue has been destroyed. Destroying a queue requires
+  // ALL retained references to it to be released. Any new tasks posted to
+  // this thread after shutdown are dropped.
+  void Shutdown();
+
+  // Returns the dispatch queue associated with this task runner, for use with
+  // system APIs that take dispatch queues. The caller is responsible for
+  // retaining the result.
+  //
+  // All properties (context, finalizer, etc.) are managed by this class, and
+  // clients should only use the result of this for dispatch_async().
+  dispatch_queue_t GetDispatchQueue() const;
+
+ protected:
+  virtual ~LibDispatchTaskRunner();
+
+ private:
+  static void Finalizer(void* context);
+
+  dispatch_queue_t queue_;
+
+  // The event on which Shutdown waits until Finalizer runs.
+  base::WaitableEvent queue_finalized_;
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_LIBDISPATCH_SEQUENCED_TASK_RUNNER_H_
diff --git a/src/base/mac/libdispatch_task_runner_unittest.cc b/src/base/mac/libdispatch_task_runner_unittest.cc
new file mode 100644
index 0000000..c3488d2
--- /dev/null
+++ b/src/base/mac/libdispatch_task_runner_unittest.cc
@@ -0,0 +1,221 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/libdispatch_task_runner.h"
+
+#include "base/bind.h"
+#include "base/mac/bind_objc_block.h"
+#include "base/message_loop.h"
+#include "base/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class LibDispatchTaskRunnerTest : public testing::Test {
+ public:
+  virtual void SetUp() OVERRIDE {
+    task_runner_ = new base::mac::LibDispatchTaskRunner(
+        "org.chromium.LibDispatchTaskRunnerTest");
+  }
+
+  // DispatchLastTask is used to run the main test thread's MessageLoop until
+  // all non-delayed tasks are run on the LibDispatchTaskRunner.
+  void DispatchLastTask() {
+    dispatch_async(task_runner_->GetDispatchQueue(), ^{
+        (&message_loop_)->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+    });
+    message_loop_.Run();
+    task_runner_->Shutdown();
+  }
+
+  // VerifyTaskOrder takes the expectations from TaskOrderMarkers and compares
+  // them against the recorded values.
+  void VerifyTaskOrder(const char* const expectations[],
+                       size_t num_expectations) {
+    size_t actual_size = task_order_.size();
+
+    for (size_t i = 0; i < num_expectations; ++i) {
+      if (i >= actual_size) {
+        EXPECT_LE(i, actual_size) << "Expected " << expectations[i];
+        continue;
+      }
+
+      EXPECT_EQ(expectations[i], task_order_[i]);
+    }
+
+    if (actual_size > num_expectations) {
+      EXPECT_LE(actual_size, num_expectations) << "Extra tasks were run:";
+      for (size_t i = num_expectations; i < actual_size; ++i) {
+        EXPECT_EQ("<none>", task_order_[i]) << " (i=" << i << ")";
+      }
+    }
+  }
+
+  // The message loop for the test main thread.
+  MessageLoop message_loop_;
+
+  // The task runner under test.
+  scoped_refptr<base::mac::LibDispatchTaskRunner> task_runner_;
+
+  // Vector that records data from TaskOrderMarker.
+  std::vector<std::string> task_order_;
+};
+
+// Scoper that records the beginning and end of a running task.
+class TaskOrderMarker {
+ public:
+  TaskOrderMarker(LibDispatchTaskRunnerTest* test, const std::string& name)
+      : test_(test),
+        name_(name) {
+    test->task_order_.push_back(std::string("BEGIN ") + name);
+  }
+  ~TaskOrderMarker() {
+    test_->task_order_.push_back(std::string("END ") + name_);
+  }
+
+ private:
+  LibDispatchTaskRunnerTest* test_;
+  std::string name_;
+};
+
+void RecordTaskOrder(LibDispatchTaskRunnerTest* test, const std::string& name) {
+  TaskOrderMarker marker(test, name);
+}
+
+// Returns a closure that records the task order.
+base::Closure BoundRecordTaskOrder(LibDispatchTaskRunnerTest* test,
+                                   const std::string& name) {
+  return base::Bind(&RecordTaskOrder, base::Unretained(test), name);
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostTask) {
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Basic Task"));
+  DispatchLastTask();
+  const char* const expectations[] = {
+    "BEGIN Basic Task",
+    "END Basic Task"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostTaskWithinTask) {
+  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "Outer");
+      task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Inner"));
+  }));
+  DispatchLastTask();
+
+  const char* const expectations[] = {
+    "BEGIN Outer",
+    "END Outer",
+    "BEGIN Inner",
+    "END Inner"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, NoMessageLoop) {
+  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this,
+          base::StringPrintf("MessageLoop = %p", MessageLoop::current()));
+  }));
+  DispatchLastTask();
+
+  const char* const expectations[] = {
+    "BEGIN MessageLoop = 0x0",
+    "END MessageLoop = 0x0"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, DispatchAndPostTasks) {
+  dispatch_async(task_runner_->GetDispatchQueue(), ^{
+      TaskOrderMarker marker(this, "First Block");
+  });
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First Task"));
+  dispatch_async(task_runner_->GetDispatchQueue(), ^{
+      TaskOrderMarker marker(this, "Second Block");
+  });
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second Task"));
+  DispatchLastTask();
+
+  const char* const expectations[] = {
+    "BEGIN First Block",
+    "END First Block",
+    "BEGIN First Task",
+    "END First Task",
+    "BEGIN Second Block",
+    "END Second Block",
+    "BEGIN Second Task",
+    "END Second Task",
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, NonNestable) {
+  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "First");
+      task_runner_->PostNonNestableTask(FROM_HERE, base::BindBlock(^{
+          TaskOrderMarker marker(this, "Second NonNestable");
+          (&message_loop_)->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+      }));
+  }));
+  message_loop_.Run();
+  task_runner_->Shutdown();
+
+  const char* const expectations[] = {
+    "BEGIN First",
+    "END First",
+    "BEGIN Second NonNestable",
+    "END Second NonNestable"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostDelayed) {
+  base::TimeTicks post_time;
+  __block base::TimeTicks run_time;
+  const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(50);
+
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First"));
+  post_time = base::TimeTicks::Now();
+  task_runner_->PostDelayedTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "Timed");
+      run_time = base::TimeTicks::Now();
+      (&message_loop_)->PostTask(FROM_HERE, MessageLoop::QuitClosure());
+  }), delta);
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second"));
+  message_loop_.Run();
+  task_runner_->Shutdown();
+
+  const char* const expectations[] = {
+    "BEGIN First",
+    "END First",
+    "BEGIN Second",
+    "END Second",
+    "BEGIN Timed",
+    "END Timed",
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+
+  EXPECT_GE(run_time, post_time + delta);
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostAfterShutdown) {
+  EXPECT_TRUE(task_runner_->PostTask(FROM_HERE,
+      BoundRecordTaskOrder(this, "First")));
+  EXPECT_TRUE(task_runner_->PostTask(FROM_HERE,
+      BoundRecordTaskOrder(this, "Second")));
+  task_runner_->Shutdown();
+  EXPECT_FALSE(task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "Not Run");
+      ADD_FAILURE() << "Should not run a task after Shutdown";
+  })));
+
+  const char* const expectations[] = {
+    "BEGIN First",
+    "END First",
+    "BEGIN Second",
+    "END Second"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
diff --git a/src/base/mac/mac_logging.cc b/src/base/mac/mac_logging.cc
new file mode 100644
index 0000000..d58220f
--- /dev/null
+++ b/src/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/src/base/mac/mac_logging.h b/src/base/mac/mac_logging.h
new file mode 100644
index 0000000..9a0003e
--- /dev/null
+++ b/src/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/src/base/mac/mac_util.h b/src/base/mac/mac_util.h
new file mode 100644
index 0000000..ff8b2b2
--- /dev/null
+++ b/src/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/src/base/mac/mac_util.mm b/src/base/mac/mac_util.mm
new file mode 100644
index 0000000..4fb1a42
--- /dev/null
+++ b/src/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/src/base/mac/mac_util_unittest.mm b/src/base/mac/mac_util_unittest.mm
new file mode 100644
index 0000000..d69e077
--- /dev/null
+++ b/src/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/files/scoped_temp_dir.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_nsobject.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/src/base/mac/objc_property_releaser.h b/src/base/mac/objc_property_releaser.h
new file mode 100644
index 0000000..973d793
--- /dev/null
+++ b/src/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/src/base/mac/objc_property_releaser.mm b/src/base/mac/objc_property_releaser.mm
new file mode 100644
index 0000000..f7ee88f
--- /dev/null
+++ b/src/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/src/base/mac/objc_property_releaser_unittest.mm b/src/base/mac/objc_property_releaser_unittest.mm
new file mode 100644
index 0000000..50f81a8
--- /dev/null
+++ b/src/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/src/base/mac/os_crash_dumps.cc b/src/base/mac/os_crash_dumps.cc
new file mode 100644
index 0000000..e6b0996
--- /dev/null
+++ b/src/base/mac/os_crash_dumps.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/os_crash_dumps.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+void ExitSignalHandler(int sig) {
+  // A call to exit() can call atexit() handlers.  If we SIGSEGV due
+  // to a corrupt heap, and if we have an atexit handler that
+  // allocates or frees memory, we are in trouble if we do not _exit.
+  _exit(128 + sig);
+}
+
+}  // namespace
+
+void DisableOSCrashDumps() {
+  // These are the POSIX signals corresponding to the Mach exceptions that
+  // Apple Crash Reporter handles.  See ux_exception() in xnu's
+  // bsd/uxkern/ux_exception.c and machine_exception() in xnu's
+  // bsd/dev/*/unix_signal.c.
+  const int signals_to_intercept[] = {
+    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) {
+    struct sigaction act = {};
+    act.sa_handler = ExitSignalHandler;
+
+    // It is better to allow the signal handler to run on the stack
+    // registered with sigaltstack(), if one is present.
+    act.sa_flags = SA_ONSTACK;
+
+    if (sigemptyset(&act.sa_mask) != 0)
+      DLOG_ERRNO(FATAL) << "sigemptyset() failed";
+    if (sigaction(signals_to_intercept[i], &act, NULL) != 0)
+      DLOG_ERRNO(FATAL) << "sigaction() failed";
+  }
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/src/base/mac/os_crash_dumps.h b/src/base/mac/os_crash_dumps.h
new file mode 100644
index 0000000..31d90fb
--- /dev/null
+++ b/src/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/src/base/mac/scoped_aedesc.h b/src/base/mac/scoped_aedesc.h
new file mode 100644
index 0000000..a1323c0
--- /dev/null
+++ b/src/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/src/base/mac/scoped_authorizationref.h b/src/base/mac/scoped_authorizationref.h
new file mode 100644
index 0000000..6413f2e
--- /dev/null
+++ b/src/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/src/base/mac/scoped_cffiledescriptorref.h b/src/base/mac/scoped_cffiledescriptorref.h
new file mode 100644
index 0000000..07196aa
--- /dev/null
+++ b/src/base/mac/scoped_cffiledescriptorref.h
@@ -0,0 +1,75 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_
+#define BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// ScopedCFFileDescriptorRef is designed after ScopedCFTypeRef<>. On
+// destruction, it will invalidate the file descriptor.
+// ScopedCFFileDescriptorRef (unlike ScopedCFTypeRef<>) does not support RETAIN
+// semantics, copying, or assignment, as doing so would increase the chances
+// that a file descriptor is invalidated while still in use.
+class ScopedCFFileDescriptorRef {
+ public:
+  explicit ScopedCFFileDescriptorRef(CFFileDescriptorRef fdref = NULL)
+      : fdref_(fdref) {
+  }
+
+  ~ScopedCFFileDescriptorRef() {
+    if (fdref_) {
+      CFFileDescriptorInvalidate(fdref_);
+      CFRelease(fdref_);
+    }
+  }
+
+  void reset(CFFileDescriptorRef fdref = NULL) {
+    if (fdref_ == fdref)
+      return;
+    if (fdref_) {
+      CFFileDescriptorInvalidate(fdref_);
+      CFRelease(fdref_);
+    }
+    fdref_ = fdref;
+  }
+
+  bool operator==(CFFileDescriptorRef that) const {
+    return fdref_ == that;
+  }
+
+  bool operator!=(CFFileDescriptorRef that) const {
+    return fdref_ != that;
+  }
+
+  operator CFFileDescriptorRef() const {
+    return fdref_;
+  }
+
+  CFFileDescriptorRef get() const {
+    return fdref_;
+  }
+
+  CFFileDescriptorRef release() WARN_UNUSED_RESULT {
+    CFFileDescriptorRef temp = fdref_;
+    fdref_ = NULL;
+    return temp;
+  }
+
+ private:
+  CFFileDescriptorRef fdref_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCFFileDescriptorRef);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_
diff --git a/src/base/mac/scoped_cftyperef.h b/src/base/mac/scoped_cftyperef.h
new file mode 100644
index 0000000..c6ca46a
--- /dev/null
+++ b/src/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/src/base/mac/scoped_ioobject.h b/src/base/mac/scoped_ioobject.h
new file mode 100644
index 0000000..854039b
--- /dev/null
+++ b/src/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/src/base/mac/scoped_launch_data.h b/src/base/mac/scoped_launch_data.h
new file mode 100644
index 0000000..e4343b8
--- /dev/null
+++ b/src/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/src/base/mac/scoped_mach_port.cc b/src/base/mac/scoped_mach_port.cc
new file mode 100644
index 0000000..652e3f4
--- /dev/null
+++ b/src/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/src/base/mac/scoped_mach_port.h b/src/base/mac/scoped_mach_port.h
new file mode 100644
index 0000000..d2aa2f7
--- /dev/null
+++ b/src/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/src/base/mac/scoped_nsautorelease_pool.h b/src/base/mac/scoped_nsautorelease_pool.h
new file mode 100644
index 0000000..60af71a
--- /dev/null
+++ b/src/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/src/base/mac/scoped_nsautorelease_pool.mm b/src/base/mac/scoped_nsautorelease_pool.mm
new file mode 100644
index 0000000..e542ca8
--- /dev/null
+++ b/src/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/src/base/mac/scoped_nsexception_enabler.h b/src/base/mac/scoped_nsexception_enabler.h
new file mode 100644
index 0000000..e1d0b3c
--- /dev/null
+++ b/src/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/src/base/mac/scoped_nsexception_enabler.mm b/src/base/mac/scoped_nsexception_enabler.mm
new file mode 100644
index 0000000..9898789
--- /dev/null
+++ b/src/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/src/base/mac/scoped_sending_event.h b/src/base/mac/scoped_sending_event.h
new file mode 100644
index 0000000..f7637bb
--- /dev/null
+++ b/src/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/src/base/mac/scoped_sending_event.mm b/src/base/mac/scoped_sending_event.mm
new file mode 100644
index 0000000..c3813d8
--- /dev/null
+++ b/src/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/src/base/mac/scoped_sending_event_unittest.mm b/src/base/mac/scoped_sending_event_unittest.mm
new file mode 100644
index 0000000..9ae9985
--- /dev/null
+++ b/src/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/src/base/mach_ipc_mac.h b/src/base/mach_ipc_mac.h
new file mode 100644
index 0000000..1730d37
--- /dev/null
+++ b/src/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/src/base/mach_ipc_mac.mm b/src/base/mach_ipc_mac.mm
new file mode 100644
index 0000000..3d45dd7
--- /dev/null
+++ b/src/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/src/base/md5.cc b/src/base/md5.cc
new file mode 100644
index 0000000..754994c
--- /dev/null
+++ b/src/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(F